summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2011-06-09 11:47:42 +0100
committerKristian Monsen <kristianm@google.com>2011-06-29 14:33:03 +0100
commitdc0f95d653279beabeb9817299e2902918ba123e (patch)
tree32eb121cd532053a5b9cb0c390331349af8d6baa /base
parentba160cd4054d13d0cb0b1b46e61c3bed67095811 (diff)
downloadexternal_chromium-dc0f95d653279beabeb9817299e2902918ba123e.zip
external_chromium-dc0f95d653279beabeb9817299e2902918ba123e.tar.gz
external_chromium-dc0f95d653279beabeb9817299e2902918ba123e.tar.bz2
Merge Chromium at r11.0.696.0: Initial merge by git
Change-Id: I273dde2843af0839dfc08b419bb443fbd449532d
Diffstat (limited to 'base')
-rw-r--r--base/PRESUBMIT.py13
-rw-r--r--base/allocator/allocator.gyp2
-rw-r--r--base/allocator/allocator_shim.cc75
-rw-r--r--base/allocator/allocator_shim.h20
-rw-r--r--base/base.gyp5
-rw-r--r--base/base.gypi11
-rw-r--r--base/bind.h2
-rw-r--r--base/bind.h.pump2
-rw-r--r--base/bind_internal.h886
-rw-r--r--base/bind_internal.h.pump155
-rw-r--r--base/bind_internal_win.h128
-rw-r--r--base/bind_internal_win.h.pump52
-rw-r--r--base/bind_unittest.cc33
-rw-r--r--base/callback.h160
-rw-r--r--base/callback.h.pump28
-rw-r--r--base/callback_internal.cc36
-rw-r--r--base/callback_internal.h (renamed from base/callback_helpers.h)37
-rw-r--r--base/callback_unittest.cc96
-rw-r--r--base/command_line.cc528
-rw-r--r--base/command_line.h185
-rw-r--r--base/command_line_unittest.cc4
-rw-r--r--base/cpu.cc77
-rw-r--r--base/cpu.h18
-rw-r--r--base/cpu_unittest.cc91
-rw-r--r--base/crypto/encryptor_mac.cc6
-rw-r--r--base/crypto/encryptor_nss.cc8
-rw-r--r--base/crypto/encryptor_openssl.cc5
-rw-r--r--base/crypto/encryptor_win.cc7
-rw-r--r--base/debug/debug_on_start_win.cc2
-rw-r--r--base/event_recorder.cc4
-rw-r--r--base/file_path.cc17
-rw-r--r--base/file_path.h5
-rw-r--r--base/file_util.cc2
-rw-r--r--base/file_util.h14
-rw-r--r--base/file_util_posix.cc2
-rw-r--r--base/file_util_win.cc30
-rw-r--r--base/file_version_info_mac.h3
-rw-r--r--base/file_version_info_mac.mm2
-rw-r--r--base/i18n/bidi_line_iterator.cc2
-rw-r--r--base/i18n/icu_string_conversions.cc5
-rw-r--r--base/id_map.h24
-rw-r--r--base/lazy_instance.h17
-rw-r--r--base/logging.cc11
-rw-r--r--base/logging.h21
-rw-r--r--base/mac/mac_util.h99
-rw-r--r--base/mac/mac_util.mm72
-rw-r--r--base/message_loop.cc15
-rw-r--r--base/message_loop.h19
-rw-r--r--base/message_loop_unittest.cc54
-rw-r--r--base/message_pump.h12
-rw-r--r--base/message_pump_glib_x.cc28
-rw-r--r--base/message_pump_libevent.cc2
-rw-r--r--base/message_pump_mac.h19
-rw-r--r--base/message_pump_mac.mm118
-rw-r--r--base/message_pump_win.cc2
-rw-r--r--base/metrics/field_trial.cc3
-rw-r--r--base/metrics/field_trial.h3
-rw-r--r--base/metrics/histogram.cc187
-rw-r--r--base/metrics/histogram.h45
-rw-r--r--base/metrics/histogram_unittest.cc25
-rw-r--r--base/mime_util_xdg.cc2
-rw-r--r--base/pickle.cc14
-rw-r--r--base/pickle.h8
-rw-r--r--base/pickle_unittest.cc6
-rw-r--r--base/platform_file_posix.cc2
-rw-r--r--base/process_util.h14
-rw-r--r--base/process_util_mac.mm17
-rw-r--r--base/process_util_posix.cc86
-rw-r--r--base/process_util_unittest.cc4
-rw-r--r--base/ref_counted.cc20
-rw-r--r--base/ref_counted.h17
-rw-r--r--base/shared_memory_posix.cc14
-rw-r--r--base/shared_memory_win.cc4
-rw-r--r--base/singleton.h2
-rw-r--r--base/string_util.cc3
-rw-r--r--base/sync_socket_posix.cc16
-rw-r--r--base/synchronization/condition_variable_posix.cc12
-rw-r--r--base/synchronization/waitable_event_win.cc2
-rw-r--r--base/task.h15
-rw-r--r--base/template_util.h23
-rw-r--r--base/template_util_unittest.cc10
-rw-r--r--base/test/test_file_util.h10
-rw-r--r--base/test/test_file_util_posix.cc5
-rw-r--r--base/test/test_file_util_win.cc58
-rw-r--r--base/test/test_suite.cc3
-rw-r--r--base/threading/non_thread_safe.cc28
-rw-r--r--base/threading/non_thread_safe.h51
-rw-r--r--base/threading/non_thread_safe_impl.cc23
-rw-r--r--base/threading/non_thread_safe_impl.h39
-rw-r--r--base/threading/non_thread_safe_unittest.cc69
-rw-r--r--base/threading/platform_thread_posix.cc2
-rw-r--r--base/threading/thread.cc1
-rw-r--r--base/threading/thread.h1
-rw-r--r--base/threading/thread_checker.h60
-rw-r--r--base/threading/thread_checker_impl.cc (renamed from base/threading/thread_checker.cc)20
-rw-r--r--base/threading/thread_checker_impl.h43
-rw-r--r--base/threading/thread_checker_unittest.cc77
-rw-r--r--base/threading/thread_local_storage_win.cc2
-rw-r--r--base/threading/thread_unittest.cc14
-rw-r--r--base/tools_sanity_unittest.cc8
-rw-r--r--base/tracked_objects.cc2
-rw-r--r--base/tracked_objects.h11
-rw-r--r--base/tuple.h7
-rw-r--r--base/values.cc33
-rw-r--r--base/values.h10
-rw-r--r--base/win/scoped_bstr.cc2
-rw-r--r--base/win/scoped_comptr.h6
-rw-r--r--base/win/scoped_variant.cc2
-rw-r--r--base/win/win_util.cc7
-rw-r--r--base/win/win_util.h9
-rw-r--r--base/win/windows_version.cc31
-rw-r--r--base/win/windows_version.h41
112 files changed, 2772 insertions, 1728 deletions
diff --git a/base/PRESUBMIT.py b/base/PRESUBMIT.py
new file mode 100644
index 0000000..1284659
--- /dev/null
+++ b/base/PRESUBMIT.py
@@ -0,0 +1,13 @@
+#!/usr/bin/python
+# 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.
+
+"""Chromium presubmit script for src/base.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details on the presubmit API built into gcl.
+"""
+
+def GetPreferredTrySlaves():
+ return ['win', 'linux', 'mac', 'win_sync', 'linux_sync', 'mac_sync']
diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp
index 87b4127..065cbf4 100644
--- a/base/allocator/allocator.gyp
+++ b/base/allocator/allocator.gyp
@@ -133,7 +133,6 @@
'<(tcmalloc_dir)/src/stack_trace_table.cc',
'<(tcmalloc_dir)/src/stack_trace_table.h',
'<(tcmalloc_dir)/src/stacktrace.cc',
- '<(tcmalloc_dir)/src/stacktrace.h',
'<(tcmalloc_dir)/src/stacktrace_config.h',
'<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
'<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
@@ -177,6 +176,7 @@
'<(jemalloc_dir)/rb.h',
'allocator_shim.cc',
+ 'allocator_shim.h',
'generic_allocators.cc',
'win_allocator.cc',
],
diff --git a/base/allocator/allocator_shim.cc b/base/allocator/allocator_shim.cc
index 3935737..f11164c 100644
--- a/base/allocator/allocator_shim.cc
+++ b/base/allocator/allocator_shim.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/allocator/allocator_shim.h"
+
#include <config.h>
// When defined, different heap allocators can be used via an environment
@@ -29,13 +31,24 @@ static int new_mode = 0;
typedef enum {
TCMALLOC, // TCMalloc is the default allocator.
- JEMALLOC, // JEMalloc
- WINDEFAULT, // Windows Heap
- WINLFH, // Windows LFH Heap
+ JEMALLOC, // JEMalloc.
+ WINHEAP, // Windows Heap (standard Windows allocator).
+ WINLFH, // Windows LFH Heap.
} Allocator;
-// This is the default allocator.
-static Allocator allocator = TCMALLOC;
+// This is the default allocator. This value can be changed at startup by
+// specifying environment variables shown below it.
+// See SetupSubprocessAllocator() to specify a default secondary (subprocess)
+// allocator.
+// TODO(jar): Switch to using TCMALLOC for the renderer as well.
+static Allocator allocator = WINHEAP;
+
+// The names of the environment variables that can optionally control the
+// selection of the allocator. The primary may be used to control overall
+// allocator selection, and the secondary can be used to specify an allocator
+// to use in sub-processes.
+static const char* primary_name = "CHROME_ALLOCATOR";
+static const char* secondary_name = "CHROME_ALLOCATOR_2";
// We include tcmalloc and the win_allocator to get as much inlining as
// possible.
@@ -101,7 +114,7 @@ void* malloc(size_t size) __THROW {
case JEMALLOC:
ptr = je_malloc(size);
break;
- case WINDEFAULT:
+ case WINHEAP:
case WINLFH:
ptr = win_heap_malloc(size);
break;
@@ -129,7 +142,7 @@ void free(void* p) __THROW {
case JEMALLOC:
je_free(p);
return;
- case WINDEFAULT:
+ case WINHEAP:
case WINLFH:
win_heap_free(p);
return;
@@ -153,7 +166,7 @@ void* realloc(void* ptr, size_t size) __THROW {
case JEMALLOC:
new_ptr = je_realloc(ptr, size);
break;
- case WINDEFAULT:
+ case WINHEAP:
case WINLFH:
new_ptr = win_heap_realloc(ptr, size);
break;
@@ -185,7 +198,7 @@ void malloc_stats(void) __THROW {
case JEMALLOC:
// No stats.
return;
- case WINDEFAULT:
+ case WINHEAP:
case WINLFH:
// No stats.
return;
@@ -201,7 +214,7 @@ extern "C" size_t _msize(void* p) {
switch (allocator) {
case JEMALLOC:
return je_msize(p);
- case WINDEFAULT:
+ case WINHEAP:
case WINLFH:
return win_heap_msize(p);
}
@@ -217,22 +230,22 @@ extern "C" intptr_t _get_heap_handle() {
// The CRT heap initialization stub.
extern "C" int _heap_init() {
#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
- const char* override = GetenvBeforeMain("CHROME_ALLOCATOR");
- if (override) {
- if (!stricmp(override, "jemalloc"))
+ const char* environment_value = GetenvBeforeMain(primary_name);
+ if (environment_value) {
+ if (!stricmp(environment_value, "jemalloc"))
allocator = JEMALLOC;
- else if (!stricmp(override, "winheap"))
- allocator = WINDEFAULT;
- else if (!stricmp(override, "winlfh"))
+ else if (!stricmp(environment_value, "winheap"))
+ allocator = WINHEAP;
+ else if (!stricmp(environment_value, "winlfh"))
allocator = WINLFH;
- else if (!stricmp(override, "tcmalloc"))
+ else if (!stricmp(environment_value, "tcmalloc"))
allocator = TCMALLOC;
}
switch (allocator) {
case JEMALLOC:
return je_malloc_init_hard() ? 0 : 1;
- case WINDEFAULT:
+ case WINHEAP:
return win_heap_init(false) ? 1 : 0;
case WINLFH:
return win_heap_init(true) ? 1 : 0;
@@ -264,3 +277,29 @@ extern "C" void* _crtheap = reinterpret_cast<void*>(1);
#include "generic_allocators.cc"
} // extern C
+
+namespace base {
+namespace allocator {
+
+void SetupSubprocessAllocator() {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ size_t primary_length = 0;
+ getenv_s(&primary_length, NULL, 0, primary_name);
+
+ size_t secondary_length = 0;
+ char buffer[20];
+ getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name);
+ DCHECK_GT(sizeof(buffer), secondary_length);
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ if (secondary_length || !primary_length) {
+ char* secondary_value = secondary_length ? buffer : "TCMALLOC";
+ // Force renderer (or other subprocesses) to use secondary_value.
+ int ret_val = _putenv_s(primary_name, secondary_value);
+ CHECK_EQ(0, ret_val);
+ }
+#endif // ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+}
+
+} // namespace base.
+} // namespace allocator.
diff --git a/base/allocator/allocator_shim.h b/base/allocator/allocator_shim.h
new file mode 100644
index 0000000..342710f
--- /dev/null
+++ b/base/allocator/allocator_shim.h
@@ -0,0 +1,20 @@
+// 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_ALLOCATOR_ALLOCATOR_SHIM_H_
+#define BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
+
+namespace base {
+namespace allocator {
+
+// Resets the environment variable CHROME_ALLOCATOR to specify the choice to
+// be used by subprocesses. Priority is given to the current value of
+// CHROME_ALLOCATOR_2 (if specified), then CHROME_ALLOCATOR (if specified), and
+// then a default value (typically set to TCMALLOC).
+void SetupSubprocessAllocator();
+
+} // namespace base.
+} // namespace allocator.
+
+#endif // BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
diff --git a/base/base.gyp b/base/base.gyp
index 868569e..525d316 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -31,8 +31,8 @@
'base',
],
'sources': [
- 'i18n/bidi_line_iterator.cc',
- 'i18n/bidi_line_iterator.h',
+ 'i18n/bidi_line_iterator.cc',
+ 'i18n/bidi_line_iterator.h',
'i18n/break_iterator.cc',
'i18n/break_iterator.h',
'i18n/char_iterator.cc',
@@ -69,6 +69,7 @@
'bits_unittest.cc',
'callback_unittest.cc',
'command_line_unittest.cc',
+ 'cpu_unittest.cc',
'crypto/encryptor_unittest.cc',
'crypto/rsa_private_key_unittest.cc',
'crypto/rsa_private_key_nss_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index 7a5da2e..ef1d8d8 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -39,10 +39,12 @@
'bind.h',
'bind_helpers.h',
'bind_internal.h',
+ 'bind_internal_win.h',
'bits.h',
'bzip2_error_handler.cc',
'callback.h',
- 'callback_helpers.h',
+ 'callback_internal.cc',
+ 'callback_internal.h',
'callback_old.h',
'command_line.cc',
'command_line.h',
@@ -249,8 +251,9 @@
'task_queue.cc',
'task_queue.h',
'template_util.h',
- 'threading/non_thread_safe.cc',
'threading/non_thread_safe.h',
+ 'threading/non_thread_safe_impl.cc',
+ 'threading/non_thread_safe_impl.h',
'threading/platform_thread.h',
'threading/platform_thread_mac.mm',
'threading/platform_thread_posix.cc',
@@ -259,8 +262,9 @@
'threading/simple_thread.h',
'threading/thread.cc',
'threading/thread.h',
- 'threading/thread_checker.cc',
'threading/thread_checker.h',
+ 'threading/thread_checker_impl.cc',
+ 'threading/thread_checker_impl.h',
'threading/thread_collision_warner.cc',
'threading/thread_collision_warner.h',
'threading/thread_local.h',
@@ -515,7 +519,6 @@
'third_party/purify/pure_api.c',
'base_drag_source.cc',
'base_drop_target.cc',
- 'cpu.cc',
'crypto/capi_util.h',
'crypto/capi_util.cc',
'event_recorder.cc',
diff --git a/base/bind.h b/base/bind.h
index c23af2e..cd9eb19 100644
--- a/base/bind.h
+++ b/base/bind.h
@@ -12,7 +12,7 @@
#pragma once
#include "base/bind_internal.h"
-#include "base/callback_helpers.h"
+#include "base/callback_internal.h"
// See base/callback.h for how to use these functions.
//
diff --git a/base/bind.h.pump b/base/bind.h.pump
index fc7f246..62b313f 100644
--- a/base/bind.h.pump
+++ b/base/bind.h.pump
@@ -16,7 +16,7 @@ $var MAX_ARITY = 6
#pragma once
#include "base/bind_internal.h"
-#include "base/callback_helpers.h"
+#include "base/callback_internal.h"
// See base/callback.h for how to use these functions.
//
diff --git a/base/bind_internal.h b/base/bind_internal.h
index 62f2050..bb5f46f 100644
--- a/base/bind_internal.h
+++ b/base/bind_internal.h
@@ -12,8 +12,13 @@
#pragma once
#include "base/bind_helpers.h"
-#include "base/callback_helpers.h"
+#include "base/callback_internal.h"
#include "base/template_util.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/bind_internal_win.h"
+#endif
namespace base {
namespace internal {
@@ -21,35 +26,229 @@ namespace internal {
// The method by which a function is invoked is determined by 3 different
// dimensions:
//
-// 1) The type of function (normal, method, const-method)
-// 2) The arity of the function
+// 1) The type of function (normal or method).
+// 2) The arity of the function.
// 3) The number of bound parameters.
//
-// The FunctionTraitsN classes unwrap the function signature type to
-// specialize based on the first two dimensions. The N in FunctionTraitsN
-// specifies the 3rd dimension. We could have specified the unbound parameters
-// via template parameters, but this method looked cleaner.
+// The templates below handle the determination of each of these dimensions.
+// In brief:
+//
+// FunctionTraits<> -- Provides a normalied signature, and other traits.
+// InvokerN<> -- Provides a DoInvoke() function that actually executes
+// a calback.
+// InvokerStorageN<> -- Provides storage for the bound parameters, and
+// typedefs to the above.
+//
+// More details about the design of each class is included in a comment closer
+// to their defition.
+
+// FunctionTraits<>
+//
+// The FunctionTraits<> template determines the type of function, and also
+// creates a NormalizedType used to select the InvokerN classes. It turns out
+// that syntactically, you only really have 2 variations when invoking a
+// funciton pointer: normal, and method. One is invoked func_ptr(arg1). The
+// other is invoked (*obj_->method_ptr(arg1)).
+//
+// However, in the type system, there are many more distinctions. In standard
+// C++, there's all variations of const, and volatile on the function pointer.
+// In Windows, there are additional calling conventions (eg., __stdcall,
+// __fastcall, etc.). FunctionTraits<> handles categorizing each of these into
+// a normalized signature.
+//
+// Having a NormalizedSignature signature, reduces the combinatoric
+// complexity of defintions for the InvokerN<> later. Even though there are
+// only 2 syntactic variations on invoking a function, without normalizing the
+// signature, there would need to be one specialization of InvokerN for each
+// unique (function_type, bound_arg, unbound_args) tuple in order to match all
+// function signatures.
+//
+// By normalizing the function signature, we reduce function_type to exactly 2.
+
+template <typename Sig>
+struct FunctionTraits;
+
+// Function: Arity 0.
+template <typename R>
+struct FunctionTraits<R(*)()> {
+ typedef R (*NormalizedSig)();
+ typedef false_type IsMethod;
+};
+
+// Method: Arity 0.
+template <typename R, typename T>
+struct FunctionTraits<R(T::*)()> {
+ typedef R (T::*NormalizedSig)();
+ typedef true_type IsMethod;
+};
+
+// Const Method: Arity 0.
+template <typename R, typename T>
+struct FunctionTraits<R(T::*)() const> {
+ typedef R (T::*NormalizedSig)();
+ typedef true_type IsMethod;
+};
+
+// Function: Arity 1.
+template <typename R, typename X1>
+struct FunctionTraits<R(*)(X1)> {
+ typedef R (*NormalizedSig)(X1);
+ typedef false_type IsMethod;
+};
+
+// Method: Arity 1.
+template <typename R, typename T, typename X1>
+struct FunctionTraits<R(T::*)(X1)> {
+ typedef R (T::*NormalizedSig)(X1);
+ typedef true_type IsMethod;
+};
+
+// Const Method: Arity 1.
+template <typename R, typename T, typename X1>
+struct FunctionTraits<R(T::*)(X1) const> {
+ typedef R (T::*NormalizedSig)(X1);
+ typedef true_type IsMethod;
+};
+
+// Function: Arity 2.
+template <typename R, typename X1, typename X2>
+struct FunctionTraits<R(*)(X1, X2)> {
+ typedef R (*NormalizedSig)(X1, X2);
+ typedef false_type IsMethod;
+};
+
+// Method: Arity 2.
+template <typename R, typename T, typename X1, typename X2>
+struct FunctionTraits<R(T::*)(X1, X2)> {
+ typedef R (T::*NormalizedSig)(X1, X2);
+ typedef true_type IsMethod;
+};
+
+// Const Method: Arity 2.
+template <typename R, typename T, typename X1, typename X2>
+struct FunctionTraits<R(T::*)(X1, X2) const> {
+ typedef R (T::*NormalizedSig)(X1, X2);
+ typedef true_type IsMethod;
+};
+
+// Function: Arity 3.
+template <typename R, typename X1, typename X2, typename X3>
+struct FunctionTraits<R(*)(X1, X2, X3)> {
+ typedef R (*NormalizedSig)(X1, X2, X3);
+ typedef false_type IsMethod;
+};
+
+// Method: Arity 3.
+template <typename R, typename T, typename X1, typename X2, typename X3>
+struct FunctionTraits<R(T::*)(X1, X2, X3)> {
+ typedef R (T::*NormalizedSig)(X1, X2, X3);
+ typedef true_type IsMethod;
+};
+
+// Const Method: Arity 3.
+template <typename R, typename T, typename X1, typename X2, typename X3>
+struct FunctionTraits<R(T::*)(X1, X2, X3) const> {
+ typedef R (T::*NormalizedSig)(X1, X2, X3);
+ typedef true_type IsMethod;
+};
+
+// Function: Arity 4.
+template <typename R, typename X1, typename X2, typename X3, typename X4>
+struct FunctionTraits<R(*)(X1, X2, X3, X4)> {
+ typedef R (*NormalizedSig)(X1, X2, X3, X4);
+ typedef false_type IsMethod;
+};
+
+// Method: Arity 4.
+template <typename R, typename T, typename X1, typename X2, typename X3,
+ typename X4>
+struct FunctionTraits<R(T::*)(X1, X2, X3, X4)> {
+ typedef R (T::*NormalizedSig)(X1, X2, X3, X4);
+ typedef true_type IsMethod;
+};
+
+// Const Method: Arity 4.
+template <typename R, typename T, typename X1, typename X2, typename X3,
+ typename X4>
+struct FunctionTraits<R(T::*)(X1, X2, X3, X4) const> {
+ typedef R (T::*NormalizedSig)(X1, X2, X3, X4);
+ typedef true_type IsMethod;
+};
+
+// Function: Arity 5.
+template <typename R, typename X1, typename X2, typename X3, typename X4,
+ typename X5>
+struct FunctionTraits<R(*)(X1, X2, X3, X4, X5)> {
+ typedef R (*NormalizedSig)(X1, X2, X3, X4, X5);
+ typedef false_type IsMethod;
+};
+
+// Method: Arity 5.
+template <typename R, typename T, typename X1, typename X2, typename X3,
+ typename X4, typename X5>
+struct FunctionTraits<R(T::*)(X1, X2, X3, X4, X5)> {
+ typedef R (T::*NormalizedSig)(X1, X2, X3, X4, X5);
+ typedef true_type IsMethod;
+};
+
+// Const Method: Arity 5.
+template <typename R, typename T, typename X1, typename X2, typename X3,
+ typename X4, typename X5>
+struct FunctionTraits<R(T::*)(X1, X2, X3, X4, X5) const> {
+ typedef R (T::*NormalizedSig)(X1, X2, X3, X4, X5);
+ typedef true_type IsMethod;
+};
+
+// Function: Arity 6.
+template <typename R, typename X1, typename X2, typename X3, typename X4,
+ typename X5, typename X6>
+struct FunctionTraits<R(*)(X1, X2, X3, X4, X5, X6)> {
+ typedef R (*NormalizedSig)(X1, X2, X3, X4, X5, X6);
+ typedef false_type IsMethod;
+};
+
+// Method: Arity 6.
+template <typename R, typename T, typename X1, typename X2, typename X3,
+ typename X4, typename X5, typename X6>
+struct FunctionTraits<R(T::*)(X1, X2, X3, X4, X5, X6)> {
+ typedef R (T::*NormalizedSig)(X1, X2, X3, X4, X5, X6);
+ typedef true_type IsMethod;
+};
+
+// Const Method: Arity 6.
+template <typename R, typename T, typename X1, typename X2, typename X3,
+ typename X4, typename X5, typename X6>
+struct FunctionTraits<R(T::*)(X1, X2, X3, X4, X5, X6) const> {
+ typedef R (T::*NormalizedSig)(X1, X2, X3, X4, X5, X6);
+ typedef true_type IsMethod;
+};
+
+// InvokerN<>
+//
+// The InvokerN templates contain a static DoInvoke() function that is the key
+// to implementing type erasure in the Callback() classes.
//
-// The FunctionTraitsN contains a static DoInvoke() function that is the key to
-// implementing type erasure in the Callback() classes. DoInvoke() is a static
-// function with a fixed signature that is independent of StorageType; its
-// first argument is a pointer to the non-templated common baseclass of
-// StorageType. This lets us store pointer to DoInvoke() in a function pointer
-// that has knowledge of the specific StorageType, and thus no knowledge of the
-// bound function and bound parameter types.
+// DoInvoke() is a static function with a fixed signature that is independent
+// of StorageType; its first argument is a pointer to the non-templated common
+// baseclass of StorageType. This lets us store pointer to DoInvoke() in a
+// function pointer that has knowledge of the specific StorageType, and thus
+// no knowledge of the bound function and bound parameter types.
//
// As long as we ensure that DoInvoke() is only used with pointers there were
// upcasted from the correct StorageType, we can be sure that execution is
// safe.
+//
+// The InvokerN templates are the only point that knows the number of bound
+// and unbound arguments. This is intentional because it allows the other
+// templates classes in the system to only have as many specializations as
+// the max arity of function we wish to support.
-template <typename StorageType, typename Sig>
-struct FunctionTraits0;
+template <typename StorageType, typename NormalizedSig>
+struct Invoker0;
// Function: Arity 0 -> 0.
template <typename StorageType, typename R>
-struct FunctionTraits0<StorageType, R(*)()> {
- typedef base::false_type IsMethod;
-
+struct Invoker0<StorageType, R(*)()> {
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_();
@@ -58,13 +257,11 @@ struct FunctionTraits0<StorageType, R(*)()> {
// Function: Arity 1 -> 1.
template <typename StorageType, typename R,typename X1>
-struct FunctionTraits0<StorageType, R(*)(X1)> {
+struct Invoker0<StorageType, R(*)(X1)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(x1);
@@ -73,14 +270,12 @@ struct FunctionTraits0<StorageType, R(*)(X1)> {
// Function: Arity 2 -> 2.
template <typename StorageType, typename R,typename X1, typename X2>
-struct FunctionTraits0<StorageType, R(*)(X1, X2)> {
+struct Invoker0<StorageType, R(*)(X1, X2)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(x1, x2);
@@ -90,15 +285,13 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2)> {
// Function: Arity 3 -> 3.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3>
-struct FunctionTraits0<StorageType, R(*)(X1, X2, X3)> {
+struct Invoker0<StorageType, R(*)(X1, X2, X3)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
is_non_const_reference<X3>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
const X3& x3) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -109,7 +302,7 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3)> {
// Function: Arity 4 -> 4.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4>
-struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4)> {
+struct Invoker0<StorageType, R(*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -117,8 +310,6 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
const X3& x3, const X4& x4) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -129,7 +320,7 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4)> {
// Function: Arity 5 -> 5.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5>
-struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+struct Invoker0<StorageType, R(*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -138,8 +329,6 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
const X3& x3, const X4& x4, const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -150,7 +339,7 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5)> {
// Function: Arity 6 -> 6.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5, typename X6>
-struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+struct Invoker0<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -160,8 +349,6 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
is_non_const_reference<X6>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
const X3& x3, const X4& x4, const X5& x5, const X6& x6) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -169,18 +356,16 @@ struct FunctionTraits0<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
}
};
-template <typename StorageType, typename Sig>
-struct FunctionTraits1;
+template <typename StorageType, typename NormalizedSig>
+struct Invoker1;
// Function: Arity 1 -> 0.
template <typename StorageType, typename R,typename X1>
-struct FunctionTraits1<StorageType, R(*)(X1)> {
+struct Invoker1<StorageType, R(*)(X1)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_));
@@ -189,36 +374,21 @@ struct FunctionTraits1<StorageType, R(*)(X1)> {
// Method: Arity 0 -> 0.
template <typename StorageType, typename R, typename T>
-struct FunctionTraits1<StorageType, R(T::*)()> {
- typedef base::true_type IsMethod;
-
+struct Invoker1<StorageType, R(T::*)()> {
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)();
}
};
-// Const Method: Arity 0 -> 0.
-template <typename StorageType, typename R, typename T>
-struct FunctionTraits1<StorageType, R(T::*)() const> {
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base ) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)();
- }
-};
-
// Function: Arity 2 -> 1.
template <typename StorageType, typename R,typename X1, typename X2>
-struct FunctionTraits1<StorageType, R(*)(X1, X2)> {
+struct Invoker1<StorageType, R(*)(X1, X2)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X2& x2) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), x2);
@@ -227,46 +397,27 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2)> {
// Method: Arity 1 -> 1.
template <typename StorageType, typename R, typename T, typename X1>
-struct FunctionTraits1<StorageType, R(T::*)(X1)> {
+struct Invoker1<StorageType, R(T::*)(X1)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(x1);
}
};
-// Const Method: Arity 1 -> 1.
-template <typename StorageType, typename R, typename T, typename X1>
-struct FunctionTraits1<StorageType, R(T::*)(X1) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X1& x1) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(x1);
- }
-};
-
// Function: Arity 3 -> 2.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3>
-struct FunctionTraits1<StorageType, R(*)(X1, X2, X3)> {
+struct Invoker1<StorageType, R(*)(X1, X2, X3)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
is_non_const_reference<X3>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), x2, x3);
@@ -276,41 +427,22 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3)> {
// Method: Arity 2 -> 2.
template <typename StorageType, typename R, typename T, typename X1,
typename X2>
-struct FunctionTraits1<StorageType, R(T::*)(X1, X2)> {
+struct Invoker1<StorageType, R(T::*)(X1, X2)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2);
}
};
-// Const Method: Arity 2 -> 2.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2>
-struct FunctionTraits1<StorageType, R(T::*)(X1, X2) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2);
- }
-};
-
// Function: Arity 4 -> 3.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4>
-struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4)> {
+struct Invoker1<StorageType, R(*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -318,8 +450,6 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
const X4& x4) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -330,15 +460,13 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4)> {
// Method: Arity 3 -> 3.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3>
-struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3)> {
+struct Invoker1<StorageType, R(T::*)(X1, X2, X3)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
is_non_const_reference<X3>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
const X3& x3) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -346,28 +474,10 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3)> {
}
};
-// Const Method: Arity 3 -> 3.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3>
-struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
- const X3& x3) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3);
- }
-};
-
// Function: Arity 5 -> 4.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5>
-struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+struct Invoker1<StorageType, R(*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -376,8 +486,6 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
const X4& x4, const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -388,7 +496,7 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5)> {
// Method: Arity 4 -> 4.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4>
-struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4)> {
+struct Invoker1<StorageType, R(T::*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -396,8 +504,6 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
const X3& x3, const X4& x4) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -405,29 +511,10 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4)> {
}
};
-// Const Method: Arity 4 -> 4.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4>
-struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
- const X3& x3, const X4& x4) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3, x4);
- }
-};
-
// Function: Arity 6 -> 5.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5, typename X6>
-struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+struct Invoker1<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -437,8 +524,6 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
is_non_const_reference<X6>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
const X4& x4, const X5& x5, const X6& x6) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -449,7 +534,7 @@ struct FunctionTraits1<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
// Method: Arity 5 -> 5.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+struct Invoker1<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -458,8 +543,6 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
const X3& x3, const X4& x4, const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -467,39 +550,17 @@ struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
}
};
-// Const Method: Arity 5 -> 5.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits1<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ||
- is_non_const_reference<X5>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X1& x1, const X2& x2,
- const X3& x3, const X4& x4, const X5& x5) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(x1, x2, x3, x4, x5);
- }
-};
-
-template <typename StorageType, typename Sig>
-struct FunctionTraits2;
+template <typename StorageType, typename NormalizedSig>
+struct Invoker2;
// Function: Arity 2 -> 0.
template <typename StorageType, typename R,typename X1, typename X2>
-struct FunctionTraits2<StorageType, R(*)(X1, X2)> {
+struct Invoker2<StorageType, R(*)(X1, X2)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_));
@@ -508,46 +569,27 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2)> {
// Method: Arity 1 -> 0.
template <typename StorageType, typename R, typename T, typename X1>
-struct FunctionTraits2<StorageType, R(T::*)(X1)> {
+struct Invoker2<StorageType, R(T::*)(X1)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_));
}
};
-// Const Method: Arity 1 -> 0.
-template <typename StorageType, typename R, typename T, typename X1>
-struct FunctionTraits2<StorageType, R(T::*)(X1) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base ) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_));
- }
-};
-
// Function: Arity 3 -> 1.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3>
-struct FunctionTraits2<StorageType, R(*)(X1, X2, X3)> {
+struct Invoker2<StorageType, R(*)(X1, X2, X3)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
is_non_const_reference<X3>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X3& x3) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), x3);
@@ -557,41 +599,22 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3)> {
// Method: Arity 2 -> 1.
template <typename StorageType, typename R, typename T, typename X1,
typename X2>
-struct FunctionTraits2<StorageType, R(T::*)(X1, X2)> {
+struct Invoker2<StorageType, R(T::*)(X1, X2)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X2& x2) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2);
}
};
-// Const Method: Arity 2 -> 1.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2>
-struct FunctionTraits2<StorageType, R(T::*)(X1, X2) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X2& x2) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2);
- }
-};
-
// Function: Arity 4 -> 2.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4>
-struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4)> {
+struct Invoker2<StorageType, R(*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -599,8 +622,6 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_), x3, x4);
@@ -610,42 +631,23 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4)> {
// Method: Arity 3 -> 2.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3>
-struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3)> {
+struct Invoker2<StorageType, R(T::*)(X1, X2, X3)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
is_non_const_reference<X3>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3);
}
};
-// Const Method: Arity 3 -> 2.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3>
-struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3);
- }
-};
-
// Function: Arity 5 -> 3.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5>
-struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+struct Invoker2<StorageType, R(*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -654,8 +656,6 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4,
const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -666,7 +666,7 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5)> {
// Method: Arity 4 -> 3.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4>
-struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4)> {
+struct Invoker2<StorageType, R(T::*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -674,8 +674,6 @@ struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
const X4& x4) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -684,30 +682,10 @@ struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4)> {
}
};
-// Const Method: Arity 4 -> 3.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4>
-struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
- const X4& x4) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3,
- x4);
- }
-};
-
// Function: Arity 6 -> 4.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5, typename X6>
-struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+struct Invoker2<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -717,8 +695,6 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
is_non_const_reference<X6>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4,
const X5& x5, const X6& x6) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -730,7 +706,7 @@ struct FunctionTraits2<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
// Method: Arity 5 -> 4.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+struct Invoker2<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -739,8 +715,6 @@ struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
const X4& x4, const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -749,42 +723,19 @@ struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
}
};
-// Const Method: Arity 5 -> 4.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits2<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ||
- is_non_const_reference<X5>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X2& x2, const X3& x3,
- const X4& x4, const X5& x5) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_), x2, x3,
- x4, x5);
- }
-};
-
-template <typename StorageType, typename Sig>
-struct FunctionTraits3;
+template <typename StorageType, typename NormalizedSig>
+struct Invoker3;
// Function: Arity 3 -> 0.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3>
-struct FunctionTraits3<StorageType, R(*)(X1, X2, X3)> {
+struct Invoker3<StorageType, R(*)(X1, X2, X3)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
is_non_const_reference<X3>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
@@ -795,14 +746,12 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3)> {
// Method: Arity 2 -> 0.
template <typename StorageType, typename R, typename T, typename X1,
typename X2>
-struct FunctionTraits3<StorageType, R(T::*)(X1, X2)> {
+struct Invoker3<StorageType, R(T::*)(X1, X2)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
@@ -810,28 +759,10 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2)> {
}
};
-// Const Method: Arity 2 -> 0.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2>
-struct FunctionTraits3<StorageType, R(T::*)(X1, X2) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base ) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_));
- }
-};
-
// Function: Arity 4 -> 1.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4>
-struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4)> {
+struct Invoker3<StorageType, R(*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -839,8 +770,6 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X4& x4) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
@@ -851,15 +780,13 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4)> {
// Method: Arity 3 -> 1.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3>
-struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3)> {
+struct Invoker3<StorageType, R(T::*)(X1, X2, X3)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
is_non_const_reference<X3>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X3& x3) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
@@ -867,28 +794,10 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3)> {
}
};
-// Const Method: Arity 3 -> 1.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3>
-struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X3& x3) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_), x3);
- }
-};
-
// Function: Arity 5 -> 2.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5>
-struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+struct Invoker3<StorageType, R(*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -897,8 +806,6 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
@@ -909,7 +816,7 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5)> {
// Method: Arity 4 -> 2.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4>
-struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4)> {
+struct Invoker3<StorageType, R(T::*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -917,8 +824,6 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
@@ -926,29 +831,10 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4)> {
}
};
-// Const Method: Arity 4 -> 2.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4>
-struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_), x3, x4);
- }
-};
-
// Function: Arity 6 -> 3.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5, typename X6>
-struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+struct Invoker3<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -958,8 +844,6 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
is_non_const_reference<X6>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5,
const X6& x6) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -971,7 +855,7 @@ struct FunctionTraits3<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
// Method: Arity 5 -> 3.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+struct Invoker3<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -980,8 +864,6 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4,
const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
@@ -990,34 +872,13 @@ struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
}
};
-// Const Method: Arity 5 -> 3.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits3<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ||
- is_non_const_reference<X5>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X3& x3, const X4& x4,
- const X5& x5) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_), x3, x4, x5);
- }
-};
-
-template <typename StorageType, typename Sig>
-struct FunctionTraits4;
+template <typename StorageType, typename NormalizedSig>
+struct Invoker4;
// Function: Arity 4 -> 0.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4>
-struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4)> {
+struct Invoker4<StorageType, R(*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1025,8 +886,6 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
@@ -1037,15 +896,13 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4)> {
// Method: Arity 3 -> 0.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3>
-struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3)> {
+struct Invoker4<StorageType, R(T::*)(X1, X2, X3)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
is_non_const_reference<X3>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
@@ -1053,28 +910,10 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3)> {
}
};
-// Const Method: Arity 3 -> 0.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3>
-struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base ) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_), Unwrap(invoker->p4_));
- }
-};
-
// Function: Arity 5 -> 1.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5>
-struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+struct Invoker4<StorageType, R(*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1083,8 +922,6 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
@@ -1095,7 +932,7 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5)> {
// Method: Arity 4 -> 1.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4>
-struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4)> {
+struct Invoker4<StorageType, R(T::*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1103,8 +940,6 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X4& x4) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
@@ -1112,29 +947,10 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4)> {
}
};
-// Const Method: Arity 4 -> 1.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4>
-struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X4& x4) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_), Unwrap(invoker->p4_), x4);
- }
-};
-
// Function: Arity 6 -> 2.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5, typename X6>
-struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+struct Invoker4<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1144,8 +960,6 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
is_non_const_reference<X6>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X5& x5, const X6& x6) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
@@ -1156,7 +970,7 @@ struct FunctionTraits4<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
// Method: Arity 5 -> 2.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+struct Invoker4<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1165,8 +979,6 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
@@ -1174,33 +986,13 @@ struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
}
};
-// Const Method: Arity 5 -> 2.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits4<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ||
- is_non_const_reference<X5>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X4& x4, const X5& x5) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_), Unwrap(invoker->p4_), x4, x5);
- }
-};
-
-template <typename StorageType, typename Sig>
-struct FunctionTraits5;
+template <typename StorageType, typename NormalizedSig>
+struct Invoker5;
// Function: Arity 5 -> 0.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5>
-struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5)> {
+struct Invoker5<StorageType, R(*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1209,8 +1001,6 @@ struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
@@ -1221,7 +1011,7 @@ struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5)> {
// Method: Arity 4 -> 0.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4>
-struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4)> {
+struct Invoker5<StorageType, R(T::*)(X1, X2, X3, X4)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1229,8 +1019,6 @@ struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4)> {
is_non_const_reference<X4>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
@@ -1238,29 +1026,10 @@ struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4)> {
}
};
-// Const Method: Arity 4 -> 0.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4>
-struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base ) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_));
- }
-};
-
// Function: Arity 6 -> 1.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5, typename X6>
-struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+struct Invoker5<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1270,8 +1039,6 @@ struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
is_non_const_reference<X6>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X6& x6) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
@@ -1282,7 +1049,7 @@ struct FunctionTraits5<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
// Method: Arity 5 -> 1.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+struct Invoker5<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1291,8 +1058,6 @@ struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base, const X5& x5) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
@@ -1300,33 +1065,13 @@ struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
}
};
-// Const Method: Arity 5 -> 1.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits5<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ||
- is_non_const_reference<X5>::value ),
- do_not_bind_functions_with_nonconst_ref);
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base, const X5& x5) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_), x5);
- }
-};
-
-template <typename StorageType, typename Sig>
-struct FunctionTraits6;
+template <typename StorageType, typename NormalizedSig>
+struct Invoker6;
// Function: Arity 6 -> 0.
template <typename StorageType, typename R,typename X1, typename X2,
typename X3, typename X4, typename X5, typename X6>
-struct FunctionTraits6<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
+struct Invoker6<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1336,8 +1081,6 @@ struct FunctionTraits6<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
is_non_const_reference<X6>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return invoker->f_(Unwrap(invoker->p1_), Unwrap(invoker->p2_),
@@ -1349,7 +1092,7 @@ struct FunctionTraits6<StorageType, R(*)(X1, X2, X3, X4, X5, X6)> {
// Method: Arity 5 -> 0.
template <typename StorageType, typename R, typename T, typename X1,
typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
+struct Invoker6<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
COMPILE_ASSERT(
!( is_non_const_reference<X1>::value ||
is_non_const_reference<X2>::value ||
@@ -1358,8 +1101,6 @@ struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
is_non_const_reference<X5>::value ),
do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base) {
StorageType* invoker = static_cast<StorageType*>(base);
return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
@@ -1368,47 +1109,28 @@ struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5)> {
}
};
-// Const Method: Arity 5 -> 0.
-template <typename StorageType, typename R, typename T, typename X1,
- typename X2, typename X3, typename X4, typename X5>
-struct FunctionTraits6<StorageType, R(T::*)(X1, X2, X3, X4, X5) const> {
- COMPILE_ASSERT(
- !(is_non_const_reference<X1>::value || is_non_const_reference<X2>::value
- || is_non_const_reference<X3>::value ||
- is_non_const_reference<X4>::value ||
- is_non_const_reference<X5>::value ),
- do_not_bind_functions_with_nonconst_ref);
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base ) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)(Unwrap(invoker->p2_),
- Unwrap(invoker->p3_), Unwrap(invoker->p4_), Unwrap(invoker->p5_),
- Unwrap(invoker->p6_));
- }
-};
-
-
-// These are the actual storage classes for the invokers.
+// InvokerStorageN<>
+//
+// These are the actual storage classes for the Invokers.
//
// Though these types are "classes", they are being used as structs with
// all member variable public. We cannot make it a struct because it inherits
// from a class which causes a compiler warning. We cannot add a "Run()" method
// that forwards the unbound arguments because that would require we unwrap the
-// Sig type like in FunctionTraitsN above to know the return type, and the arity
+// Sig type like in InvokerN above to know the return type, and the arity
// of Run().
//
-// An alternate solution would be to merge FunctionTraitsN and InvokerStorageN,
+// An alternate solution would be to merge InvokerN and InvokerStorageN,
// but the generated code seemed harder to read.
template <typename Sig>
class InvokerStorage0 : public InvokerStorageBase {
public:
typedef InvokerStorage0 StorageType;
- typedef FunctionTraits0<StorageType, Sig> FunctionTraits;
- typedef typename FunctionTraits::IsMethod IsMethod;
-
+ typedef FunctionTraits<Sig> TargetTraits;
+ typedef Invoker0<StorageType, typename TargetTraits::NormalizedSig> Invoker;
+ typedef typename TargetTraits::IsMethod IsMethod;
InvokerStorage0(Sig f)
@@ -1424,9 +1146,9 @@ template <typename Sig, typename P1>
class InvokerStorage1 : public InvokerStorageBase {
public:
typedef InvokerStorage1 StorageType;
- typedef FunctionTraits1<StorageType, Sig> FunctionTraits;
- typedef typename FunctionTraits::IsMethod IsMethod;
-
+ typedef FunctionTraits<Sig> TargetTraits;
+ typedef Invoker1<StorageType, typename TargetTraits::NormalizedSig> Invoker;
+ typedef typename TargetTraits::IsMethod IsMethod;
// For methods, we need to be careful for parameter 1. We skip the
// scoped_refptr check because the binder itself takes care of this. We also
// disallow binding of an array as the method's target object.
@@ -1454,9 +1176,9 @@ template <typename Sig, typename P1, typename P2>
class InvokerStorage2 : public InvokerStorageBase {
public:
typedef InvokerStorage2 StorageType;
- typedef FunctionTraits2<StorageType, Sig> FunctionTraits;
- typedef typename FunctionTraits::IsMethod IsMethod;
-
+ typedef FunctionTraits<Sig> TargetTraits;
+ typedef Invoker2<StorageType, typename TargetTraits::NormalizedSig> Invoker;
+ typedef typename TargetTraits::IsMethod IsMethod;
// For methods, we need to be careful for parameter 1. We skip the
// scoped_refptr check because the binder itself takes care of this. We also
// disallow binding of an array as the method's target object.
@@ -1488,9 +1210,9 @@ template <typename Sig, typename P1, typename P2, typename P3>
class InvokerStorage3 : public InvokerStorageBase {
public:
typedef InvokerStorage3 StorageType;
- typedef FunctionTraits3<StorageType, Sig> FunctionTraits;
- typedef typename FunctionTraits::IsMethod IsMethod;
-
+ typedef FunctionTraits<Sig> TargetTraits;
+ typedef Invoker3<StorageType, typename TargetTraits::NormalizedSig> Invoker;
+ typedef typename TargetTraits::IsMethod IsMethod;
// For methods, we need to be careful for parameter 1. We skip the
// scoped_refptr check because the binder itself takes care of this. We also
// disallow binding of an array as the method's target object.
@@ -1526,9 +1248,9 @@ template <typename Sig, typename P1, typename P2, typename P3, typename P4>
class InvokerStorage4 : public InvokerStorageBase {
public:
typedef InvokerStorage4 StorageType;
- typedef FunctionTraits4<StorageType, Sig> FunctionTraits;
- typedef typename FunctionTraits::IsMethod IsMethod;
-
+ typedef FunctionTraits<Sig> TargetTraits;
+ typedef Invoker4<StorageType, typename TargetTraits::NormalizedSig> Invoker;
+ typedef typename TargetTraits::IsMethod IsMethod;
// For methods, we need to be careful for parameter 1. We skip the
// scoped_refptr check because the binder itself takes care of this. We also
// disallow binding of an array as the method's target object.
@@ -1569,9 +1291,9 @@ template <typename Sig, typename P1, typename P2, typename P3, typename P4,
class InvokerStorage5 : public InvokerStorageBase {
public:
typedef InvokerStorage5 StorageType;
- typedef FunctionTraits5<StorageType, Sig> FunctionTraits;
- typedef typename FunctionTraits::IsMethod IsMethod;
-
+ typedef FunctionTraits<Sig> TargetTraits;
+ typedef Invoker5<StorageType, typename TargetTraits::NormalizedSig> Invoker;
+ typedef typename TargetTraits::IsMethod IsMethod;
// For methods, we need to be careful for parameter 1. We skip the
// scoped_refptr check because the binder itself takes care of this. We also
// disallow binding of an array as the method's target object.
@@ -1617,9 +1339,9 @@ template <typename Sig, typename P1, typename P2, typename P3, typename P4,
class InvokerStorage6 : public InvokerStorageBase {
public:
typedef InvokerStorage6 StorageType;
- typedef FunctionTraits6<StorageType, Sig> FunctionTraits;
- typedef typename FunctionTraits::IsMethod IsMethod;
-
+ typedef FunctionTraits<Sig> TargetTraits;
+ typedef Invoker6<StorageType, typename TargetTraits::NormalizedSig> Invoker;
+ typedef typename TargetTraits::IsMethod IsMethod;
// For methods, we need to be careful for parameter 1. We skip the
// scoped_refptr check because the binder itself takes care of this. We also
// disallow binding of an array as the method's target object.
diff --git a/base/bind_internal.h.pump b/base/bind_internal.h.pump
index 132b0db..84fb2ef 100644
--- a/base/bind_internal.h.pump
+++ b/base/bind_internal.h.pump
@@ -16,8 +16,13 @@ $var MAX_ARITY = 6
#pragma once
#include "base/bind_helpers.h"
-#include "base/callback_helpers.h"
+#include "base/callback_internal.h"
#include "base/template_util.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/bind_internal_win.h"
+#endif
namespace base {
namespace internal {
@@ -25,32 +30,103 @@ namespace internal {
// The method by which a function is invoked is determined by 3 different
// dimensions:
//
-// 1) The type of function (normal, method, const-method)
-// 2) The arity of the function
+// 1) The type of function (normal or method).
+// 2) The arity of the function.
// 3) The number of bound parameters.
//
-// The FunctionTraitsN classes unwrap the function signature type to
-// specialize based on the first two dimensions. The N in FunctionTraitsN
-// specifies the 3rd dimension. We could have specified the unbound parameters
-// via template parameters, but this method looked cleaner.
+// The templates below handle the determination of each of these dimensions.
+// In brief:
+//
+// FunctionTraits<> -- Provides a normalied signature, and other traits.
+// InvokerN<> -- Provides a DoInvoke() function that actually executes
+// a calback.
+// InvokerStorageN<> -- Provides storage for the bound parameters, and
+// typedefs to the above.
+//
+// More details about the design of each class is included in a comment closer
+// to their defition.
+
+// FunctionTraits<>
+//
+// The FunctionTraits<> template determines the type of function, and also
+// creates a NormalizedType used to select the InvokerN classes. It turns out
+// that syntactically, you only really have 2 variations when invoking a
+// funciton pointer: normal, and method. One is invoked func_ptr(arg1). The
+// other is invoked (*obj_->method_ptr(arg1)).
+//
+// However, in the type system, there are many more distinctions. In standard
+// C++, there's all variations of const, and volatile on the function pointer.
+// In Windows, there are additional calling conventions (eg., __stdcall,
+// __fastcall, etc.). FunctionTraits<> handles categorizing each of these into
+// a normalized signature.
//
-// The FunctionTraitsN contains a static DoInvoke() function that is the key to
-// implementing type erasure in the Callback() classes. DoInvoke() is a static
-// function with a fixed signature that is independent of StorageType; its
-// first argument is a pointer to the non-templated common baseclass of
-// StorageType. This lets us store pointer to DoInvoke() in a function pointer
-// that has knowledge of the specific StorageType, and thus no knowledge of the
-// bound function and bound parameter types.
+// Having a NormalizedSignature signature, reduces the combinatoric
+// complexity of defintions for the InvokerN<> later. Even though there are
+// only 2 syntactic variations on invoking a function, without normalizing the
+// signature, there would need to be one specialization of InvokerN for each
+// unique (function_type, bound_arg, unbound_args) tuple in order to match all
+// function signatures.
+//
+// By normalizing the function signature, we reduce function_type to exactly 2.
+
+template <typename Sig>
+struct FunctionTraits;
+
+$range ARITY 0..MAX_ARITY
+$for ARITY [[
+$range ARG 1..ARITY
+
+// Function: Arity $(ARITY).
+template <typename R[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
+struct FunctionTraits<R(*)($for ARG , [[X$(ARG)]])> {
+ typedef R (*NormalizedSig)($for ARG , [[X$(ARG)]]);
+ typedef false_type IsMethod;
+};
+
+// Method: Arity $(ARITY).
+template <typename R, typename T[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
+struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]])> {
+ typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]);
+ typedef true_type IsMethod;
+};
+
+// Const Method: Arity $(ARITY).
+template <typename R, typename T[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
+struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]]) const> {
+ typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]);
+ typedef true_type IsMethod;
+};
+
+]] $$for ARITY
+
+// InvokerN<>
+//
+// The InvokerN templates contain a static DoInvoke() function that is the key
+// to implementing type erasure in the Callback() classes.
+//
+// DoInvoke() is a static function with a fixed signature that is independent
+// of StorageType; its first argument is a pointer to the non-templated common
+// baseclass of StorageType. This lets us store pointer to DoInvoke() in a
+// function pointer that has knowledge of the specific StorageType, and thus
+// no knowledge of the bound function and bound parameter types.
//
// As long as we ensure that DoInvoke() is only used with pointers there were
// upcasted from the correct StorageType, we can be sure that execution is
// safe.
+//
+// The InvokerN templates are the only point that knows the number of bound
+// and unbound arguments. This is intentional because it allows the other
+// templates classes in the system to only have as many specializations as
+// the max arity of function we wish to support.
$range BOUND 0..MAX_ARITY
$for BOUND [[
-template <typename StorageType, typename Sig>
-struct FunctionTraits$(BOUND);
+template <typename StorageType, typename NormalizedSig>
+struct Invoker$(BOUND);
$range ARITY 0..MAX_ARITY
$for ARITY [[
@@ -74,7 +150,7 @@ $range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY
template <typename StorageType, typename R[[]]
$if ARITY > 0 [[,]][[]]
$for ARG , [[typename X$(ARG)]]>
-struct FunctionTraits$(BOUND)<StorageType, R(*)($for ARG , [[X$(ARG)]])> {
+struct Invoker$(BOUND)<StorageType, R(*)($for ARG , [[X$(ARG)]])> {
$if ARITY > 0 [[
COMPILE_ASSERT(
@@ -83,8 +159,6 @@ $if ARITY > 0 [[
]]
- typedef base::false_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base[[]]
$if UNBOUND != 0 [[, ]][[]]
$for UNBOUND_ARG , [[const X$(UNBOUND_ARG)& x$(UNBOUND_ARG)]]) {
@@ -101,7 +175,7 @@ $if BOUND > 0 [[
// Method: Arity $(M_ARITY) -> $(UNBOUND).
template <typename StorageType, typename R, typename T[[]]
$if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]>
-struct FunctionTraits$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> {
+struct Invoker$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> {
$if M_ARITY > 0 [[
COMPILE_ASSERT(
@@ -110,8 +184,6 @@ $if M_ARITY > 0 [[
]]
- typedef base::true_type IsMethod;
-
static R DoInvoke(InvokerStorageBase* base[[]]
$if UNBOUND > 0 [[, ]][[]]
$for M_UNBOUND_ARG , [[const X$(M_UNBOUND_ARG)& x$(M_UNBOUND_ARG)]]) {
@@ -123,31 +195,6 @@ $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
}
};
-// Const Method: Arity $(M_ARITY) -> $(UNBOUND).
-template <typename StorageType, typename R, typename T[[]]
-$if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]>
-struct FunctionTraits$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]]) const> {
-$if M_ARITY > 0 [[
-
- COMPILE_ASSERT(
- !($for M_ARG || [[is_non_const_reference<X$(M_ARG)>::value ]]),
- do_not_bind_functions_with_nonconst_ref);
-
-]]
-
- typedef base::true_type IsMethod;
-
- static R DoInvoke(InvokerStorageBase* base[[]]
-$if UNBOUND > 0 [[, ]]
-[[]] $for M_UNBOUND_ARG , [[const X$(M_UNBOUND_ARG)& x$(M_UNBOUND_ARG)]]) {
- StorageType* invoker = static_cast<StorageType*>(base);
- return (Unwrap(invoker->p1_)->*invoker->f_)([[]]
-$for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]]
-$if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]]
-$for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
- }
-};
-
]] $$ if BOUND
]] $$ if UNBOUND
@@ -155,16 +202,18 @@ $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
]] $$ for BOUND
-// These are the actual storage classes for the invokers.
+// InvokerStorageN<>
+//
+// These are the actual storage classes for the Invokers.
//
// Though these types are "classes", they are being used as structs with
// all member variable public. We cannot make it a struct because it inherits
// from a class which causes a compiler warning. We cannot add a "Run()" method
// that forwards the unbound arguments because that would require we unwrap the
-// Sig type like in FunctionTraitsN above to know the return type, and the arity
+// Sig type like in InvokerN above to know the return type, and the arity
// of Run().
//
-// An alternate solution would be to merge FunctionTraitsN and InvokerStorageN,
+// An alternate solution would be to merge InvokerN and InvokerStorageN,
// but the generated code seemed harder to read.
$for BOUND [[
@@ -176,9 +225,9 @@ $for BOUND_ARG , [[typename P$(BOUND_ARG)]]>
class InvokerStorage$(BOUND) : public InvokerStorageBase {
public:
typedef InvokerStorage$(BOUND) StorageType;
- typedef FunctionTraits$(BOUND)<StorageType, Sig> FunctionTraits;
- typedef typename FunctionTraits::IsMethod IsMethod;
-
+ typedef FunctionTraits<Sig> TargetTraits;
+ typedef Invoker$(BOUND)<StorageType, typename TargetTraits::NormalizedSig> Invoker;
+ typedef typename TargetTraits::IsMethod IsMethod;
$for BOUND_ARG [[
$if BOUND_ARG == 1 [[
diff --git a/base/bind_internal_win.h b/base/bind_internal_win.h
new file mode 100644
index 0000000..dab8d51
--- /dev/null
+++ b/base/bind_internal_win.h
@@ -0,0 +1,128 @@
+// This file was GENERATED by command:
+// pump.py bind_internal_win.h.pump
+// DO NOT EDIT BY HAND!!!
+
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Specializations of FunctionTraits<> for Windows specific calling
+// conventions. Please see base/bind_internal.h for more info.
+
+#ifndef BASE_BIND_INTERNAL_WIN_H_
+#define BASE_BIND_INTERNAL_WIN_H_
+#pragma once
+
+namespace base {
+namespace internal {
+
+template <typename Sig>
+struct FunctionTraits;
+
+// __stdcall Function: Arity 0.
+template <typename R>
+struct FunctionTraits<R(__stdcall *)()> {
+ typedef R (*NormalizedSig)();
+ typedef false_type IsMethod;
+};
+
+// __fastcall Function: Arity 0.
+template <typename R>
+struct FunctionTraits<R(__fastcall *)()> {
+ typedef R (*NormalizedSig)();
+ typedef false_type IsMethod;
+};
+
+// __stdcall Function: Arity 1.
+template <typename R, typename X1>
+struct FunctionTraits<R(__stdcall *)(X1)> {
+ typedef R (*NormalizedSig)(X1);
+ typedef false_type IsMethod;
+};
+
+// __fastcall Function: Arity 1.
+template <typename R, typename X1>
+struct FunctionTraits<R(__fastcall *)(X1)> {
+ typedef R (*NormalizedSig)(X1);
+ typedef false_type IsMethod;
+};
+
+// __stdcall Function: Arity 2.
+template <typename R, typename X1, typename X2>
+struct FunctionTraits<R(__stdcall *)(X1, X2)> {
+ typedef R (*NormalizedSig)(X1, X2);
+ typedef false_type IsMethod;
+};
+
+// __fastcall Function: Arity 2.
+template <typename R, typename X1, typename X2>
+struct FunctionTraits<R(__fastcall *)(X1, X2)> {
+ typedef R (*NormalizedSig)(X1, X2);
+ typedef false_type IsMethod;
+};
+
+// __stdcall Function: Arity 3.
+template <typename R, typename X1, typename X2, typename X3>
+struct FunctionTraits<R(__stdcall *)(X1, X2, X3)> {
+ typedef R (*NormalizedSig)(X1, X2, X3);
+ typedef false_type IsMethod;
+};
+
+// __fastcall Function: Arity 3.
+template <typename R, typename X1, typename X2, typename X3>
+struct FunctionTraits<R(__fastcall *)(X1, X2, X3)> {
+ typedef R (*NormalizedSig)(X1, X2, X3);
+ typedef false_type IsMethod;
+};
+
+// __stdcall Function: Arity 4.
+template <typename R, typename X1, typename X2, typename X3, typename X4>
+struct FunctionTraits<R(__stdcall *)(X1, X2, X3, X4)> {
+ typedef R (*NormalizedSig)(X1, X2, X3, X4);
+ typedef false_type IsMethod;
+};
+
+// __fastcall Function: Arity 4.
+template <typename R, typename X1, typename X2, typename X3, typename X4>
+struct FunctionTraits<R(__fastcall *)(X1, X2, X3, X4)> {
+ typedef R (*NormalizedSig)(X1, X2, X3, X4);
+ typedef false_type IsMethod;
+};
+
+// __stdcall Function: Arity 5.
+template <typename R, typename X1, typename X2, typename X3, typename X4,
+ typename X5>
+struct FunctionTraits<R(__stdcall *)(X1, X2, X3, X4, X5)> {
+ typedef R (*NormalizedSig)(X1, X2, X3, X4, X5);
+ typedef false_type IsMethod;
+};
+
+// __fastcall Function: Arity 5.
+template <typename R, typename X1, typename X2, typename X3, typename X4,
+ typename X5>
+struct FunctionTraits<R(__fastcall *)(X1, X2, X3, X4, X5)> {
+ typedef R (*NormalizedSig)(X1, X2, X3, X4, X5);
+ typedef false_type IsMethod;
+};
+
+// __stdcall Function: Arity 6.
+template <typename R, typename X1, typename X2, typename X3, typename X4,
+ typename X5, typename X6>
+struct FunctionTraits<R(__stdcall *)(X1, X2, X3, X4, X5, X6)> {
+ typedef R (*NormalizedSig)(X1, X2, X3, X4, X5, X6);
+ typedef false_type IsMethod;
+};
+
+// __fastcall Function: Arity 6.
+template <typename R, typename X1, typename X2, typename X3, typename X4,
+ typename X5, typename X6>
+struct FunctionTraits<R(__fastcall *)(X1, X2, X3, X4, X5, X6)> {
+ typedef R (*NormalizedSig)(X1, X2, X3, X4, X5, X6);
+ typedef false_type IsMethod;
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_BIND_INTERNAL_WIN_H_
diff --git a/base/bind_internal_win.h.pump b/base/bind_internal_win.h.pump
new file mode 100644
index 0000000..4d213a3
--- /dev/null
+++ b/base/bind_internal_win.h.pump
@@ -0,0 +1,52 @@
+$$ This is a pump file for generating file templates. Pump is a python
+$$ script that is part of the Google Test suite of utilities. Description
+$$ can be found here:
+$$
+$$ http://code.google.com/p/googletest/wiki/PumpManual
+$$
+
+$var MAX_ARITY = 6
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Specializations of FunctionTraits<> for Windows specific calling
+// conventions. Please see base/bind_internal.h for more info.
+
+#ifndef BASE_BIND_INTERNAL_WIN_H_
+#define BASE_BIND_INTERNAL_WIN_H_
+#pragma once
+
+namespace base {
+namespace internal {
+
+template <typename Sig>
+struct FunctionTraits;
+
+$range ARITY 0..MAX_ARITY
+$for ARITY [[
+$range ARG 1..ARITY
+
+// __stdcall Function: Arity $(ARITY).
+template <typename R[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
+struct FunctionTraits<R(__stdcall *)($for ARG , [[X$(ARG)]])> {
+ typedef R (*NormalizedSig)($for ARG , [[X$(ARG)]]);
+ typedef false_type IsMethod;
+};
+
+// __fastcall Function: Arity $(ARITY).
+template <typename R[[]]
+$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
+struct FunctionTraits<R(__fastcall *)($for ARG , [[X$(ARG)]])> {
+ typedef R (*NormalizedSig)($for ARG , [[X$(ARG)]]);
+ typedef false_type IsMethod;
+};
+
+]] $$for ARITY
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_BIND_INTERNAL_WIN_H_
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc
index 47d971a..061808b 100644
--- a/base/bind_unittest.cc
+++ b/base/bind_unittest.cc
@@ -212,18 +212,6 @@ class BindTest : public ::testing::Test {
StrictMock<NoRef>* BindTest::static_func_mock_ptr;
-// Ensure we can create unbound callbacks. We need this to be able to store
-// them in class members that can be initialized later.
-TEST_F(BindTest, DefaultConstruction) {
- Callback<void(void)> c0;
- Callback<void(int)> c1;
- Callback<void(int,int)> c2;
- Callback<void(int,int,int)> c3;
- Callback<void(int,int,int,int)> c4;
- Callback<void(int,int,int,int,int)> c5;
- Callback<void(int,int,int,int,int,int)> c6;
-}
-
// Sanity check that we can instantiate a callback for each arity.
TEST_F(BindTest, ArityTest) {
Callback<int(void)> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1);
@@ -593,5 +581,26 @@ TEST_F(BindTest, NoCompile) {
}
+#if defined(OS_WIN)
+int __fastcall FastCallFunc(int n) {
+ return n;
+}
+
+int __stdcall StdCallFunc(int n) {
+ return n;
+}
+
+// Windows specific calling convention support.
+// - Can bind a __fastcall function.
+// - Can bind a __stdcall function.
+TEST_F(BindTest, WindowsCallingConventions) {
+ Callback<int(void)> fastcall_cb = Bind(&FastCallFunc, 1);
+ EXPECT_EQ(1, fastcall_cb.Run());
+
+ Callback<int(void)> stdcall_cb = Bind(&StdCallFunc, 2);
+ EXPECT_EQ(2, stdcall_cb.Run());
+}
+#endif
+
} // namespace
} // namespace base
diff --git a/base/callback.h b/base/callback.h
index 05a7182..bcc3dfd 100644
--- a/base/callback.h
+++ b/base/callback.h
@@ -11,7 +11,7 @@
#define BASE_CALLBACK_H_
#pragma once
-#include "base/callback_helpers.h"
+#include "base/callback_internal.h"
#include "base/callback_old.h"
// New, super-duper, unified Callback system. This will eventually replace
@@ -223,11 +223,11 @@ template <typename Sig>
class Callback;
template <typename R>
-class Callback<R(void)> {
+class Callback<R(void)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -238,25 +238,25 @@ class Callback<R(void)> {
// return the exact Callback<> type. See base/bind.h for details.
template <typename T>
Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
- : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
- invoker_storage_.swap(invoker_holder.invoker_storage_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
- R Run(void) const {
- return polymorphic_invoke_(invoker_storage_.get());
- }
+ R Run() const {
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get());
+ }
};
template <typename R, typename A1>
-class Callback<R(A1)> {
+class Callback<R(A1)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -267,26 +267,26 @@ class Callback<R(A1)> {
// return the exact Callback<> type. See base/bind.h for details.
template <typename T>
Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
- : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
- invoker_storage_.swap(invoker_holder.invoker_storage_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1);
- }
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get(), a1);
+ }
};
template <typename R, typename A1, typename A2>
-class Callback<R(A1, A2)> {
+class Callback<R(A1, A2)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -297,29 +297,29 @@ class Callback<R(A1, A2)> {
// return the exact Callback<> type. See base/bind.h for details.
template <typename T>
Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
- : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
- invoker_storage_.swap(invoker_holder.invoker_storage_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1,
const A2& a2) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1,
- a2);
- }
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get(), a1,
+ a2);
+ }
};
template <typename R, typename A1, typename A2, typename A3>
-class Callback<R(A1, A2, A3)> {
+class Callback<R(A1, A2, A3)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&,
const A3&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -330,32 +330,32 @@ class Callback<R(A1, A2, A3)> {
// return the exact Callback<> type. See base/bind.h for details.
template <typename T>
Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
- : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
- invoker_storage_.swap(invoker_holder.invoker_storage_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1,
const A2& a2,
const A3& a3) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1,
- a2,
- a3);
- }
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get(), a1,
+ a2,
+ a3);
+ }
};
template <typename R, typename A1, typename A2, typename A3, typename A4>
-class Callback<R(A1, A2, A3, A4)> {
+class Callback<R(A1, A2, A3, A4)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&,
const A3&,
const A4&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -366,28 +366,28 @@ class Callback<R(A1, A2, A3, A4)> {
// return the exact Callback<> type. See base/bind.h for details.
template <typename T>
Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
- : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
- invoker_storage_.swap(invoker_holder.invoker_storage_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1,
const A2& a2,
const A3& a3,
const A4& a4) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1,
- a2,
- a3,
- a4);
- }
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
+ return f(invoker_storage_.get(), a1,
+ a2,
+ a3,
+ a4);
+ }
};
template <typename R, typename A1, typename A2, typename A3, typename A4,
typename A5>
-class Callback<R(A1, A2, A3, A4, A5)> {
+class Callback<R(A1, A2, A3, A4, A5)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&,
@@ -395,7 +395,7 @@ class Callback<R(A1, A2, A3, A4, A5)> {
const A4&,
const A5&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -406,8 +406,9 @@ class Callback<R(A1, A2, A3, A4, A5)> {
// return the exact Callback<> type. See base/bind.h for details.
template <typename T>
Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
- : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
- invoker_storage_.swap(invoker_holder.invoker_storage_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1,
@@ -415,21 +416,20 @@ class Callback<R(A1, A2, A3, A4, A5)> {
const A3& a3,
const A4& a4,
const A5& a5) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1,
- a2,
- a3,
- a4,
- a5);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+ return f(invoker_storage_.get(), a1,
+ a2,
+ a3,
+ a4,
+ a5);
}
-
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
};
template <typename R, typename A1, typename A2, typename A3, typename A4,
typename A5, typename A6>
-class Callback<R(A1, A2, A3, A4, A5, A6)> {
+class Callback<R(A1, A2, A3, A4, A5, A6)> : public internal::CallbackBase {
public:
typedef R(*PolymorphicInvoke)(internal::InvokerStorageBase*, const A1&,
const A2&,
@@ -438,7 +438,7 @@ class Callback<R(A1, A2, A3, A4, A5, A6)> {
const A5&,
const A6&);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -449,8 +449,9 @@ class Callback<R(A1, A2, A3, A4, A5, A6)> {
// return the exact Callback<> type. See base/bind.h for details.
template <typename T>
Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
- : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
- invoker_storage_.swap(invoker_holder.invoker_storage_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
R Run(const A1& a1,
@@ -459,17 +460,16 @@ class Callback<R(A1, A2, A3, A4, A5, A6)> {
const A4& a4,
const A5& a5,
const A6& a6) const {
- return polymorphic_invoke_(invoker_storage_.get(), a1,
- a2,
- a3,
- a4,
- a5,
- a6);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+ return f(invoker_storage_.get(), a1,
+ a2,
+ a3,
+ a4,
+ a5,
+ a6);
}
-
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
};
diff --git a/base/callback.h.pump b/base/callback.h.pump
index 9fc4b0b..34b0eb0 100644
--- a/base/callback.h.pump
+++ b/base/callback.h.pump
@@ -15,7 +15,7 @@ $var MAX_ARITY = 6
#define BASE_CALLBACK_H_
#pragma once
-#include "base/callback_helpers.h"
+#include "base/callback_internal.h"
#include "base/callback_old.h"
// New, super-duper, unified Callback system. This will eventually replace
@@ -233,10 +233,10 @@ $range ARG 1..ARITY
$if ARITY == 0 [[
template <typename R>
-class Callback<R(void)> {
+class Callback<R(void)> : public internal::CallbackBase {
]] $else [[
template <typename R, $for ARG , [[typename A$(ARG)]]>
-class Callback<R($for ARG , [[A$(ARG)]])> {
+class Callback<R($for ARG , [[A$(ARG)]])> : public internal::CallbackBase {
]]
public:
@@ -245,7 +245,7 @@ $if ARITY != 0 [[, ]]
$for ARG ,
[[const A$(ARG)&]]);
- Callback() : polymorphic_invoke_(NULL) { }
+ Callback() : CallbackBase(NULL, NULL) { }
// We pass InvokerStorageHolder by const ref to avoid incurring an
// unnecessary AddRef/Unref pair even though we will modify the object.
@@ -256,27 +256,21 @@ $for ARG ,
// return the exact Callback<> type. See base/bind.h for details.
template <typename T>
Callback(const internal::InvokerStorageHolder<T>& invoker_holder)
- : polymorphic_invoke_(&T::FunctionTraits::DoInvoke) {
- invoker_storage_.swap(invoker_holder.invoker_storage_);
+ : CallbackBase(
+ reinterpret_cast<InvokeFuncStorage>(&T::Invoker::DoInvoke),
+ &invoker_holder.invoker_storage_) {
}
-
-$if ARITY == 0 [[
- R Run(void) const {
-]] $else [[
R Run($for ARG ,
[[const A$(ARG)& a$(ARG)]]) const {
-]]
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
- return polymorphic_invoke_(invoker_storage_.get()[[]]
+ return f(invoker_storage_.get()[[]]
$if ARITY != 0 [[, ]]
$for ARG ,
- [[a$(ARG)]]);
+ [[a$(ARG)]]);
}
-
- private:
- scoped_refptr<internal::InvokerStorageBase> invoker_storage_;
- PolymorphicInvoke polymorphic_invoke_;
};
diff --git a/base/callback_internal.cc b/base/callback_internal.cc
new file mode 100644
index 0000000..d9d1e6f
--- /dev/null
+++ b/base/callback_internal.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/callback_internal.h"
+
+namespace base {
+namespace internal {
+
+bool CallbackBase::is_null() const {
+ return invoker_storage_.get() == NULL;
+}
+
+void CallbackBase::Reset() {
+ invoker_storage_ = NULL;
+ polymorphic_invoke_ = NULL;
+}
+
+bool CallbackBase::Equals(const CallbackBase& other) const {
+ return invoker_storage_.get() == other.invoker_storage_.get() &&
+ polymorphic_invoke_ == other.polymorphic_invoke_;
+}
+
+CallbackBase::CallbackBase(InvokeFuncStorage polymorphic_invoke,
+ scoped_refptr<InvokerStorageBase>* invoker_storage)
+ : polymorphic_invoke_(polymorphic_invoke) {
+ if (invoker_storage) {
+ invoker_storage_.swap(*invoker_storage);
+ }
+}
+
+CallbackBase::~CallbackBase() {
+}
+
+} // namespace base
+} // namespace internal
diff --git a/base/callback_helpers.h b/base/callback_internal.h
index 86b0df1..4f1d3c3 100644
--- a/base/callback_helpers.h
+++ b/base/callback_internal.h
@@ -5,8 +5,8 @@
// This file contains utility functions and classes that help the
// implementation, and management of the Callback objects.
-#ifndef BASE_CALLBACK_HELPERS_H_
-#define BASE_CALLBACK_HELPERS_H_
+#ifndef BASE_CALLBACK_INTERNAL_H_
+#define BASE_CALLBACK_INTERNAL_H_
#pragma once
#include "base/ref_counted.h"
@@ -49,7 +49,38 @@ InvokerStorageHolder<T> MakeInvokerStorageHolder(T* o) {
return InvokerStorageHolder<T>(o);
}
+// Holds the Callback methods that don't require specialization to reduce
+// template bloat.
+class CallbackBase {
+ public:
+ // Returns true if Callback is null (doesn't refer to anything).
+ bool is_null() const;
+
+ // Returns the Callback into an uninitalized state.
+ void Reset();
+
+ bool Equals(const CallbackBase& other) const;
+
+ protected:
+ // In C++, it is safe to cast function pointers to function pointers of
+ // another type. It is not okay to use void*. We create a InvokeFuncStorage
+ // that that can store our function pointer, and then cast it back to
+ // the original type on usage.
+ typedef void(*InvokeFuncStorage)(void);
+
+ CallbackBase(InvokeFuncStorage polymorphic_invoke,
+ scoped_refptr<InvokerStorageBase>* invoker_storage);
+
+ // Force the destructor to be instaniated inside this translation unit so
+ // that our subclasses will not get inlined versions. Avoids more template
+ // bloat.
+ ~CallbackBase();
+
+ scoped_refptr<InvokerStorageBase> invoker_storage_;
+ InvokeFuncStorage polymorphic_invoke_;
+};
+
} // namespace internal
} // namespace base
-#endif // BASE_CALLBACK_HELPERS_H_
+#endif // BASE_CALLBACK_INTERNAL_H_
diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc
index bc15927..f327412 100644
--- a/base/callback_unittest.cc
+++ b/base/callback_unittest.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include "base/callback.h"
+#include "base/callback_internal.h"
#include "base/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace base {
namespace {
class HelperObject {
@@ -19,9 +21,24 @@ class HelperObject {
int next_number_;
};
-} // namespace
+struct FakeInvoker {
+ static void DoInvoke(internal::InvokerStorageBase*) {
+ }
+};
+
+// White-box testpoints to inject into a Callback<> object for checking
+// comparators and emptiness APIs.
+class FakeInvokerStorage1 : public internal::InvokerStorageBase {
+ public:
+ typedef FakeInvoker Invoker;
+};
+
+class FakeInvokerStorage2 : public internal::InvokerStorageBase {
+ public:
+ typedef FakeInvoker Invoker;
+};
-TEST(Callback, OneArg) {
+TEST(CallbackOld, OneArg) {
HelperObject obj;
scoped_ptr<Callback1<int*>::Type> callback(
NewCallback(&obj, &HelperObject::GetNextNumberArg));
@@ -31,10 +48,83 @@ TEST(Callback, OneArg) {
EXPECT_EQ(number, 1);
}
-TEST(Callback, ReturnValue) {
+TEST(CallbackOld, ReturnValue) {
HelperObject obj;
scoped_ptr<CallbackWithReturnValue<int>::Type> callback(
NewCallbackWithReturnValue(&obj, &HelperObject::GetNextNumber));
EXPECT_EQ(callback->Run(), 1);
}
+
+class CallbackTest : public ::testing::Test {
+ public:
+ CallbackTest()
+ : callback_a_(MakeInvokerStorageHolder(new FakeInvokerStorage1())),
+ callback_b_(MakeInvokerStorageHolder(new FakeInvokerStorage2())) {
+ }
+
+ virtual ~CallbackTest() {
+ }
+
+ protected:
+ Callback<void(void)> callback_a_;
+ const Callback<void(void)> callback_b_; // Ensure APIs work with const.
+ Callback<void(void)> null_callback_;
+};
+
+// Ensure we can create unbound callbacks. We need this to be able to store
+// them in class members that can be initialized later.
+TEST_F(CallbackTest, DefaultConstruction) {
+ Callback<void(void)> c0;
+ Callback<void(int)> c1;
+ Callback<void(int,int)> c2;
+ Callback<void(int,int,int)> c3;
+ Callback<void(int,int,int,int)> c4;
+ Callback<void(int,int,int,int,int)> c5;
+ Callback<void(int,int,int,int,int,int)> c6;
+
+ EXPECT_TRUE(c0.is_null());
+ EXPECT_TRUE(c1.is_null());
+ EXPECT_TRUE(c2.is_null());
+ EXPECT_TRUE(c3.is_null());
+ EXPECT_TRUE(c4.is_null());
+ EXPECT_TRUE(c5.is_null());
+ EXPECT_TRUE(c6.is_null());
+}
+
+TEST_F(CallbackTest, IsNull) {
+ EXPECT_TRUE(null_callback_.is_null());
+ EXPECT_FALSE(callback_a_.is_null());
+ EXPECT_FALSE(callback_b_.is_null());
+}
+
+TEST_F(CallbackTest, Equals) {
+ EXPECT_TRUE(callback_a_.Equals(callback_a_));
+ EXPECT_FALSE(callback_a_.Equals(callback_b_));
+ EXPECT_FALSE(callback_b_.Equals(callback_a_));
+
+ // We should compare based on instance, not type.
+ Callback<void(void)> callback_c(
+ MakeInvokerStorageHolder(new FakeInvokerStorage1()));
+ Callback<void(void)> callback_a2 = callback_a_;
+ EXPECT_TRUE(callback_a_.Equals(callback_a2));
+ EXPECT_FALSE(callback_a_.Equals(callback_c));
+
+ // Empty, however, is always equal to empty.
+ Callback<void(void)> empty2;
+ EXPECT_TRUE(null_callback_.Equals(empty2));
+}
+
+TEST_F(CallbackTest, Reset) {
+ // Resetting should bring us back to empty.
+ ASSERT_FALSE(callback_a_.is_null());
+ ASSERT_FALSE(callback_a_.Equals(null_callback_));
+
+ callback_a_.Reset();
+
+ EXPECT_TRUE(callback_a_.is_null());
+ EXPECT_TRUE(callback_a_.Equals(null_callback_));
+}
+
+} // namespace
+} // namespace base
diff --git a/base/command_line.cc b/base/command_line.cc
index 66b4437..fcb2294 100644
--- a/base/command_line.cc
+++ b/base/command_line.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -27,114 +27,184 @@
CommandLine* CommandLine::current_process_commandline_ = NULL;
-// Since we use a lazy match, make sure that longer versions (like L"--")
-// are listed before shorter versions (like L"-") of similar prefixes.
+namespace {
+typedef CommandLine::StringType::value_type CharType;
+
+const CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--");
+const CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("=");
+// Since we use a lazy match, make sure that longer versions (like "--") are
+// listed before shorter versions (like "-") of similar prefixes.
#if defined(OS_WIN)
-const wchar_t* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
-const wchar_t kSwitchTerminator[] = L"--";
-const wchar_t kSwitchValueSeparator[] = L"=";
+const CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
#elif defined(OS_POSIX)
// Unixes don't use slash as a switch.
-const char* const kSwitchPrefixes[] = {"--", "-"};
-const char kSwitchTerminator[] = "--";
-const char kSwitchValueSeparator[] = "=";
+const CharType* const kSwitchPrefixes[] = {"--", "-"};
#endif
#if defined(OS_WIN)
-// Lowercase a string. This is used to lowercase switch names.
-// Is this what we really want? It seems crazy to me. I've left it in
-// for backwards compatibility on Windows.
-static void Lowercase(std::string* parameter) {
- transform(parameter->begin(), parameter->end(), parameter->begin(),
- tolower);
-}
-#endif
-
-CommandLine::~CommandLine() {
-}
-
-#if defined(OS_WIN)
-CommandLine::CommandLine(NoProgram no_program) {
+// Lowercase a string for case-insensitivity of switches.
+// Is this desirable? It exists for backwards compatibility on Windows.
+void Lowercase(std::string* arg) {
+ transform(arg->begin(), arg->end(), arg->begin(), tolower);
}
-void CommandLine::ParseFromString(const std::wstring& command_line) {
- TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
-
- if (command_line_string_.empty())
- return;
+// Quote a string if necessary, such that CommandLineToArgvW() will always
+// process it as a single argument.
+std::wstring WindowsStyleQuote(const std::wstring& arg) {
+ // We follow the quoting rules of CommandLineToArgvW.
+ // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+ if (arg.find_first_of(L" \\\"") == std::wstring::npos) {
+ // No quoting necessary.
+ return arg;
+ }
- int num_args = 0;
- wchar_t** args = NULL;
+ std::wstring out;
+ out.push_back(L'"');
+ for (size_t i = 0; i < arg.size(); ++i) {
+ if (arg[i] == '\\') {
+ // Find the extent of this run of backslashes.
+ size_t start = i, end = start + 1;
+ for (; end < arg.size() && arg[end] == '\\'; ++end)
+ /* empty */;
+ size_t backslash_count = end - start;
- args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
+ // Backslashes are escapes only if the run is followed by a double quote.
+ // Since we also will end the string with a double quote, we escape for
+ // either a double quote or the end of the string.
+ if (end == arg.size() || arg[end] == '"') {
+ // To quote, we need to output 2x as many backslashes.
+ backslash_count *= 2;
+ }
+ for (size_t j = 0; j < backslash_count; ++j)
+ out.push_back('\\');
- // Populate program_ with the trimmed version of the first arg.
- TrimWhitespace(args[0], TRIM_ALL, &program_);
+ // Advance i to one before the end to balance i++ in loop.
+ i = end - 1;
+ } else if (arg[i] == '"') {
+ out.push_back('\\');
+ out.push_back('"');
+ } else {
+ out.push_back(arg[i]);
+ }
+ }
+ out.push_back('"');
- bool parse_switches = true;
- for (int i = 1; i < num_args; ++i) {
- std::wstring arg;
- TrimWhitespace(args[i], TRIM_ALL, &arg);
+ return out;
+}
+#endif
- if (!parse_switches) {
- args_.push_back(arg);
- continue;
- }
+// Returns true and fills in |switch_string| and |switch_value| if
+// |parameter_string| represents a switch.
+bool IsSwitch(const CommandLine::StringType& parameter_string,
+ std::string* switch_string,
+ CommandLine::StringType* switch_value) {
+ switch_string->clear();
+ switch_value->clear();
- if (arg == kSwitchTerminator) {
- parse_switches = false;
+ for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
+ CommandLine::StringType prefix(kSwitchPrefixes[i]);
+ if (parameter_string.find(prefix) != 0)
continue;
- }
- std::string switch_string;
- std::wstring switch_value;
- if (IsSwitch(arg, &switch_string, &switch_value)) {
- switches_[switch_string] = switch_value;
+ const size_t switch_start = prefix.length();
+ const size_t equals_position = parameter_string.find(
+ kSwitchValueSeparator, switch_start);
+ CommandLine::StringType switch_native;
+ if (equals_position == CommandLine::StringType::npos) {
+ switch_native = parameter_string.substr(switch_start);
} else {
- args_.push_back(arg);
+ switch_native = parameter_string.substr(
+ switch_start, equals_position - switch_start);
+ *switch_value = parameter_string.substr(equals_position + 1);
}
+#if defined(OS_WIN)
+ *switch_string = WideToASCII(switch_native);
+ Lowercase(switch_string);
+#else
+ *switch_string = switch_native;
+#endif
+
+ return true;
}
- if (args)
- LocalFree(args);
+ return false;
}
-// static
-CommandLine CommandLine::FromString(const std::wstring& command_line) {
- CommandLine cmd;
- cmd.ParseFromString(command_line);
- return cmd;
+} // namespace
+
+CommandLine::CommandLine(NoProgram no_program) {
+#if defined(OS_POSIX)
+ // Push an empty argument, because we always assume argv_[0] is a program.
+ argv_.push_back("");
+#endif
}
CommandLine::CommandLine(const FilePath& program) {
+#if defined(OS_WIN)
if (!program.empty()) {
program_ = program.value();
// TODO(evanm): proper quoting here.
command_line_string_ = L'"' + program.value() + L'"';
}
-}
-
#elif defined(OS_POSIX)
-CommandLine::CommandLine(NoProgram no_program) {
- // Push an empty argument, because we always assume argv_[0] is a program.
- argv_.push_back("");
+ argv_.push_back(program.value());
+#endif
}
+#if defined(OS_POSIX)
CommandLine::CommandLine(int argc, const char* const* argv) {
InitFromArgv(argc, argv);
}
-CommandLine::CommandLine(const std::vector<std::string>& argv) {
+CommandLine::CommandLine(const StringVector& argv) {
InitFromArgv(argv);
}
+#endif // OS_POSIX
+
+CommandLine::~CommandLine() {
+}
+
+// static
+void CommandLine::Init(int argc, const char* const* argv) {
+ delete current_process_commandline_;
+ current_process_commandline_ = new CommandLine;
+#if defined(OS_WIN)
+ current_process_commandline_->ParseFromString(::GetCommandLineW());
+#elif defined(OS_POSIX)
+ current_process_commandline_->InitFromArgv(argc, argv);
+#endif
+}
+
+// static
+void CommandLine::Reset() {
+ DCHECK(current_process_commandline_);
+ delete current_process_commandline_;
+ current_process_commandline_ = NULL;
+}
+// static
+CommandLine* CommandLine::ForCurrentProcess() {
+ DCHECK(current_process_commandline_);
+ return current_process_commandline_;
+}
+
+#if defined(OS_WIN)
+// static
+CommandLine CommandLine::FromString(const std::wstring& command_line) {
+ CommandLine cmd;
+ cmd.ParseFromString(command_line);
+ return cmd;
+}
+#endif // OS_WIN
+
+#if defined(OS_POSIX)
void CommandLine::InitFromArgv(int argc, const char* const* argv) {
for (int i = 0; i < argc; ++i)
argv_.push_back(argv[i]);
InitFromArgv(argv_);
}
-void CommandLine::InitFromArgv(const std::vector<std::string>& argv) {
+void CommandLine::InitFromArgv(const StringVector& argv) {
argv_ = argv;
bool parse_switches = true;
for (size_t i = 1; i < argv_.size(); ++i) {
@@ -151,7 +221,7 @@ void CommandLine::InitFromArgv(const std::vector<std::string>& argv) {
}
std::string switch_string;
- std::string switch_value;
+ StringType switch_value;
if (IsSwitch(arg, &switch_string, &switch_value)) {
switches_[switch_string] = switch_value;
} else {
@@ -159,72 +229,25 @@ void CommandLine::InitFromArgv(const std::vector<std::string>& argv) {
}
}
}
+#endif // OS_POSIX
-CommandLine::CommandLine(const FilePath& program) {
- argv_.push_back(program.value());
-}
-
-#endif
-
-// static
-bool CommandLine::IsSwitch(const StringType& parameter_string,
- std::string* switch_string,
- StringType* switch_value) {
- switch_string->clear();
- switch_value->clear();
-
- for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
- StringType prefix(kSwitchPrefixes[i]);
- if (parameter_string.find(prefix) != 0)
- continue;
-
- const size_t switch_start = prefix.length();
- const size_t equals_position = parameter_string.find(
- kSwitchValueSeparator, switch_start);
- StringType switch_native;
- if (equals_position == StringType::npos) {
- switch_native = parameter_string.substr(switch_start);
- } else {
- switch_native = parameter_string.substr(
- switch_start, equals_position - switch_start);
- *switch_value = parameter_string.substr(equals_position + 1);
- }
+CommandLine::StringType CommandLine::command_line_string() const {
#if defined(OS_WIN)
- *switch_string = WideToASCII(switch_native);
- Lowercase(switch_string);
-#else
- *switch_string = switch_native;
+ return command_line_string_;
+#elif defined(OS_POSIX)
+ return JoinString(argv_, ' ');
#endif
-
- return true;
- }
-
- return false;
}
-// static
-void CommandLine::Init(int argc, const char* const* argv) {
- delete current_process_commandline_;
- current_process_commandline_ = new CommandLine;
+FilePath CommandLine::GetProgram() const {
#if defined(OS_WIN)
- current_process_commandline_->ParseFromString(::GetCommandLineW());
-#elif defined(OS_POSIX)
- current_process_commandline_->InitFromArgv(argc, argv);
+ return FilePath(program_);
+#else
+ DCHECK_GT(argv_.size(), 0U);
+ return FilePath(argv_[0]);
#endif
}
-void CommandLine::Reset() {
- DCHECK(current_process_commandline_ != NULL);
- delete current_process_commandline_;
- current_process_commandline_ = NULL;
-}
-
-// static
-CommandLine* CommandLine::ForCurrentProcess() {
- DCHECK(current_process_commandline_);
- return current_process_commandline_;
-}
-
bool CommandLine::HasSwitch(const std::string& switch_string) const {
std::string lowercased_switch(switch_string);
#if defined(OS_WIN)
@@ -259,8 +282,7 @@ CommandLine::StringType CommandLine::GetSwitchValueNative(
Lowercase(&lowercased_switch);
#endif
- std::map<std::string, StringType>::const_iterator result =
- switches_.find(lowercased_switch);
+ SwitchMap::const_iterator result = switches_.find(lowercased_switch);
if (result == switches_.end()) {
return CommandLine::StringType();
@@ -269,80 +291,30 @@ CommandLine::StringType CommandLine::GetSwitchValueNative(
}
}
-FilePath CommandLine::GetProgram() const {
-#if defined(OS_WIN)
- return FilePath(program_);
-#else
- DCHECK_GT(argv_.size(), 0U);
- return FilePath(argv_[0]);
-#endif
+size_t CommandLine::GetSwitchCount() const {
+ return switches_.size();
}
-#if defined(OS_POSIX)
-std::string CommandLine::command_line_string() const {
- return JoinString(argv_, ' ');
-}
-#endif
-
-#if defined(OS_WIN)
void CommandLine::AppendSwitch(const std::string& switch_string) {
+#if defined(OS_WIN)
command_line_string_.append(L" ");
command_line_string_.append(kSwitchPrefixes[0] + ASCIIToWide(switch_string));
switches_[switch_string] = L"";
+#elif defined(OS_POSIX)
+ argv_.push_back(kSwitchPrefixes[0] + switch_string);
+ switches_[switch_string] = "";
+#endif
}
-void CommandLine::AppendSwitchASCII(const std::string& switch_string,
- const std::string& value_string) {
- AppendSwitchNative(switch_string, ASCIIToWide(value_string));
-}
-
-// Quote a string if necessary, such that CommandLineToArgvW() will
-// always process it as a single argument.
-static std::wstring WindowsStyleQuote(const std::wstring& arg) {
- // We follow the quoting rules of CommandLineToArgvW.
- // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
- if (arg.find_first_of(L" \\\"") == std::wstring::npos) {
- // No quoting necessary.
- return arg;
- }
-
- std::wstring out;
- out.push_back(L'"');
- for (size_t i = 0; i < arg.size(); ++i) {
- if (arg[i] == '\\') {
- // Find the extent of this run of backslashes.
- size_t start = i, end = start + 1;
- for (; end < arg.size() && arg[end] == '\\'; ++end)
- /* empty */;
- size_t backslash_count = end - start;
-
- // Backslashes are escapes only if the run is followed by a double quote.
- // Since we also will end the string with a double quote, we escape for
- // either a double quote or the end of the string.
- if (end == arg.size() || arg[end] == '"') {
- // To quote, we need to output 2x as many backslashes.
- backslash_count *= 2;
- }
- for (size_t j = 0; j < backslash_count; ++j)
- out.push_back('\\');
-
- // Advance i to one before the end to balance i++ in loop.
- i = end - 1;
- } else if (arg[i] == '"') {
- out.push_back('\\');
- out.push_back('"');
- } else {
- out.push_back(arg[i]);
- }
- }
- out.push_back('"');
-
- return out;
+void CommandLine::AppendSwitchPath(const std::string& switch_string,
+ const FilePath& path) {
+ AppendSwitchNative(switch_string, path.value());
}
void CommandLine::AppendSwitchNative(const std::string& switch_string,
- const std::wstring& value) {
- std::wstring combined_switch_string =
+ const CommandLine::StringType& value) {
+#if defined(OS_WIN)
+ StringType combined_switch_string =
kSwitchPrefixes[0] + ASCIIToWide(switch_string);
if (!value.empty())
combined_switch_string += kSwitchValueSeparator + WindowsStyleQuote(value);
@@ -351,24 +323,81 @@ void CommandLine::AppendSwitchNative(const std::string& switch_string,
command_line_string_.append(combined_switch_string);
switches_[switch_string] = value;
+#elif defined(OS_POSIX)
+ StringType combined_switch_string = kSwitchPrefixes[0] + switch_string;
+ if (!value.empty())
+ combined_switch_string += kSwitchValueSeparator + value;
+ argv_.push_back(combined_switch_string);
+ switches_[switch_string] = value;
+#endif
+}
+
+void CommandLine::AppendSwitchASCII(const std::string& switch_string,
+ const std::string& value_string) {
+#if defined(OS_WIN)
+ AppendSwitchNative(switch_string, ASCIIToWide(value_string));
+#elif defined(OS_POSIX)
+ AppendSwitchNative(switch_string, value_string);
+#endif
+}
+
+void CommandLine::AppendSwitches(const CommandLine& other) {
+ SwitchMap::const_iterator i;
+ for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
+ AppendSwitchNative(i->first, i->second);
+}
+
+void CommandLine::CopySwitchesFrom(const CommandLine& source,
+ const char* const switches[],
+ size_t count) {
+ for (size_t i = 0; i < count; ++i) {
+ if (source.HasSwitch(switches[i])) {
+ StringType value = source.GetSwitchValueNative(switches[i]);
+ AppendSwitchNative(switches[i], value);
+ }
+ }
}
void CommandLine::AppendArg(const std::string& value) {
+#if defined(OS_WIN)
DCHECK(IsStringUTF8(value));
AppendArgNative(UTF8ToWide(value));
+#elif defined(OS_POSIX)
+ AppendArgNative(value);
+#endif
+}
+
+void CommandLine::AppendArgPath(const FilePath& path) {
+ AppendArgNative(path.value());
}
-void CommandLine::AppendArgNative(const std::wstring& value) {
+void CommandLine::AppendArgNative(const CommandLine::StringType& value) {
+#if defined(OS_WIN)
command_line_string_.append(L" ");
command_line_string_.append(WindowsStyleQuote(value));
args_.push_back(value);
+#elif defined(OS_POSIX)
+ DCHECK(IsStringUTF8(value));
+ argv_.push_back(value);
+#endif
+}
+
+void CommandLine::AppendArgs(const CommandLine& other) {
+ if(other.args_.size() <= 0)
+ return;
+#if defined(OS_WIN)
+ command_line_string_.append(L" --");
+#endif // OS_WIN
+ StringVector::const_iterator i;
+ for (i = other.args_.begin(); i != other.args_.end(); ++i)
+ AppendArgNative(*i);
}
void CommandLine::AppendArguments(const CommandLine& other,
bool include_program) {
+#if defined(OS_WIN)
// Verify include_program is used correctly.
- // Logic could be shorter but this is clearer.
- DCHECK_EQ(include_program, !other.GetProgram().empty());
+ DCHECK(!include_program || !other.GetProgram().empty());
if (include_program)
program_ = other.program_;
@@ -376,54 +405,7 @@ void CommandLine::AppendArguments(const CommandLine& other,
command_line_string_ += L' ';
command_line_string_ += other.command_line_string_;
-
- std::map<std::string, StringType>::const_iterator i;
- for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
- switches_[i->first] = i->second;
-}
-
-void CommandLine::PrependWrapper(const std::wstring& wrapper) {
- if (wrapper.empty())
- return;
- // The wrapper may have embedded arguments (like "gdb --args"). In this case,
- // we don't pretend to do anything fancy, we just split on spaces.
- std::vector<std::wstring> wrapper_and_args;
- base::SplitString(wrapper, ' ', &wrapper_and_args);
- program_ = wrapper_and_args[0];
- command_line_string_ = wrapper + L" " + command_line_string_;
-}
-
#elif defined(OS_POSIX)
-void CommandLine::AppendSwitch(const std::string& switch_string) {
- argv_.push_back(kSwitchPrefixes[0] + switch_string);
- switches_[switch_string] = "";
-}
-
-void CommandLine::AppendSwitchNative(const std::string& switch_string,
- const std::string& value) {
- std::string combined_switch_string = kSwitchPrefixes[0] + switch_string;
- if (!value.empty())
- combined_switch_string += kSwitchValueSeparator + value;
- argv_.push_back(combined_switch_string);
- switches_[switch_string] = value;
-}
-
-void CommandLine::AppendSwitchASCII(const std::string& switch_string,
- const std::string& value_string) {
- AppendSwitchNative(switch_string, value_string);
-}
-
-void CommandLine::AppendArg(const std::string& value) {
- AppendArgNative(value);
-}
-
-void CommandLine::AppendArgNative(const std::string& value) {
- DCHECK(IsStringUTF8(value));
- argv_.push_back(value);
-}
-
-void CommandLine::AppendArguments(const CommandLine& other,
- bool include_program) {
// Verify include_program is used correctly.
// Logic could be shorter but this is clearer.
DCHECK_EQ(include_program, !other.GetProgram().empty());
@@ -435,48 +417,72 @@ void CommandLine::AppendArguments(const CommandLine& other,
// arguments to our arg vector.
for (size_t i = 1; i < other.argv_.size(); ++i)
argv_.push_back(other.argv_[i]);
+#endif
- std::map<std::string, StringType>::const_iterator i;
+ SwitchMap::const_iterator i;
for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
switches_[i->first] = i->second;
}
-void CommandLine::PrependWrapper(const std::string& wrapper) {
+void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
// The wrapper may have embedded arguments (like "gdb --args"). In this case,
// we don't pretend to do anything fancy, we just split on spaces.
- std::vector<std::string> wrapper_and_args;
+ if (wrapper.empty())
+ return;
+ StringVector wrapper_and_args;
+#if defined(OS_WIN)
+ base::SplitString(wrapper, ' ', &wrapper_and_args);
+ program_ = wrapper_and_args[0];
+ command_line_string_ = wrapper + L" " + command_line_string_;
+#elif defined(OS_POSIX)
base::SplitString(wrapper, ' ', &wrapper_and_args);
argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end());
+#endif
}
-#endif
+#if defined(OS_WIN)
+void CommandLine::ParseFromString(const std::wstring& command_line) {
+ TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
-void CommandLine::AppendArgPath(const FilePath& path) {
- AppendArgNative(path.value());
-}
+ if (command_line_string_.empty())
+ return;
-void CommandLine::AppendSwitchPath(const std::string& switch_string,
- const FilePath& path) {
- AppendSwitchNative(switch_string, path.value());
-}
+ int num_args = 0;
+ wchar_t** args = NULL;
-void CommandLine::CopySwitchesFrom(const CommandLine& source,
- const char* const switches[],
- size_t count) {
- for (size_t i = 0; i < count; ++i) {
- if (source.HasSwitch(switches[i])) {
- StringType value = source.GetSwitchValueNative(switches[i]);
- AppendSwitchNative(switches[i], value);
+ args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
+
+ // Populate program_ with the trimmed version of the first arg.
+ TrimWhitespace(args[0], TRIM_ALL, &program_);
+
+ bool parse_switches = true;
+ for (int i = 1; i < num_args; ++i) {
+ std::wstring arg;
+ TrimWhitespace(args[i], TRIM_ALL, &arg);
+
+ if (!parse_switches) {
+ args_.push_back(arg);
+ continue;
+ }
+
+ if (arg == kSwitchTerminator) {
+ parse_switches = false;
+ continue;
+ }
+
+ std::string switch_string;
+ std::wstring switch_value;
+ if (IsSwitch(arg, &switch_string, &switch_value)) {
+ switches_[switch_string] = switch_value;
+ } else {
+ args_.push_back(arg);
}
}
-}
-// private
-CommandLine::CommandLine() {
+ if (args)
+ LocalFree(args);
}
+#endif
-// static
-CommandLine* CommandLine::ForCurrentProcessMutable() {
- DCHECK(current_process_commandline_);
- return current_process_commandline_;
+CommandLine::CommandLine() {
}
diff --git a/base/command_line.h b/base/command_line.h
index b8bbba9..7ff5ab0 100644
--- a/base/command_line.h
+++ b/base/command_line.h
@@ -3,15 +3,13 @@
// found in the LICENSE file.
// This class works with command lines: building and parsing.
-// Switches can optionally have a value attached using an equals sign,
-// as in "-switch=value". Arguments that aren't prefixed with a
-// switch prefix are saved as extra arguments. An argument of "--"
-// will terminate switch parsing, causing everything after to be
-// considered as extra arguments.
+// Switches can optionally have a value attached using an equals sign, as in
+// "-switch=value". Arguments that aren't prefixed with a switch prefix are
+// saved as extra arguments. An argument of "--" will terminate switch parsing,
+// causing everything after to be considered as extra arguments.
-// There is a singleton read-only CommandLine that represents the command
-// line that the current process was started with. It must be initialized
-// in main() (or whatever the platform's equivalent function is).
+// There is a singleton read-only CommandLine that represents the command line
+// that the current process was started with. It must be initialized in main().
#ifndef BASE_COMMAND_LINE_H_
#define BASE_COMMAND_LINE_H_
@@ -25,179 +23,158 @@
#include "build/build_config.h"
class FilePath;
-class InProcessBrowserTest;
class CommandLine {
public:
#if defined(OS_WIN)
- // The type of native command line arguments.
+ // The native command line string type.
typedef std::wstring StringType;
#elif defined(OS_POSIX)
- // The type of native command line arguments.
typedef std::string StringType;
#endif
+ typedef std::vector<StringType> StringVector;
// The type of map for parsed-out switch key and values.
typedef std::map<std::string, StringType> SwitchMap;
- // A constructor for CommandLines that are used only to carry switches and
- // arguments.
+ // A constructor for CommandLines that only carry switches and arguments.
enum NoProgram { NO_PROGRAM };
explicit CommandLine(NoProgram no_program);
- // Construct a new, empty command line.
- // |program| is the name of the program to run (aka argv[0]).
+ // Construct a new command line with |program| as argv[0].
explicit CommandLine(const FilePath& program);
#if defined(OS_POSIX)
CommandLine(int argc, const char* const* argv);
- explicit CommandLine(const std::vector<std::string>& argv);
+ explicit CommandLine(const StringVector& argv);
#endif
~CommandLine();
-#if defined(OS_WIN)
- // Initialize by parsing the given command-line string.
- // The program name is assumed to be the first item in the string.
- void ParseFromString(const std::wstring& command_line);
- static CommandLine FromString(const std::wstring& command_line);
-#elif defined(OS_POSIX)
- // Initialize from an argv vector.
- void InitFromArgv(int argc, const char* const* argv);
- void InitFromArgv(const std::vector<std::string>& argv);
-#endif
-
- // Initialize the current process CommandLine singleton. On Windows,
- // ignores its arguments (we instead parse GetCommandLineW()
- // directly) because we don't trust the CRT's parsing of the command
- // line, but it still must be called to set up the command line.
+ // Initialize the current process CommandLine singleton. On Windows, ignores
+ // its arguments (we instead parse GetCommandLineW() directly) because we
+ // don't trust the CRT's parsing of the command line, but it still must be
+ // called to set up the command line.
static void Init(int argc, const char* const* argv);
// Destroys the current process CommandLine singleton. This is necessary if
- // you want to reset the base library to its initial state (for example in an
+ // you want to reset the base library to its initial state (for example, in an
// outer library that needs to be able to terminate, and be re-initialized).
- // If Init is called only once, e.g. in main(), calling Reset() is not
- // necessary.
+ // If Init is called only once, as in main(), Reset() is not necessary.
static void Reset();
// Get the singleton CommandLine representing the current process's
- // command line. Note: returned value is mutable, but not thread safe;
+ // command line. Note: returned value is mutable, but not thread safe;
// only mutate if you know what you're doing!
static CommandLine* ForCurrentProcess();
+#if defined(OS_WIN)
+ static CommandLine FromString(const std::wstring& command_line);
+#endif
+
+#if defined(OS_POSIX)
+ // Initialize from an argv vector.
+ void InitFromArgv(int argc, const char* const* argv);
+ void InitFromArgv(const StringVector& argv);
+#endif
+
+ // Returns the represented command line string.
+ // CAUTION! This should be avoided because quoting behavior is unclear.
+ StringType command_line_string() const;
+
+#if defined(OS_POSIX)
+ // Returns the original command line string as a vector of strings.
+ const StringVector& argv() const { return argv_; }
+#endif
+
+ // Returns the program part of the command line string (the first item).
+ FilePath GetProgram() const;
+
// Returns true if this command line contains the given switch.
- // (Switch names are case-insensitive.)
+ // (Switch names are case-insensitive).
bool HasSwitch(const std::string& switch_string) const;
- // Returns the value associated with the given switch. If the
- // switch has no value or isn't present, this method returns
- // the empty string.
+ // Returns the value associated with the given switch. If the switch has no
+ // value or isn't present, this method returns the empty string.
std::string GetSwitchValueASCII(const std::string& switch_string) const;
FilePath GetSwitchValuePath(const std::string& switch_string) const;
StringType GetSwitchValueNative(const std::string& switch_string) const;
// Get the number of switches in this process.
- size_t GetSwitchCount() const { return switches_.size(); }
+ // TODO(msw): Remove unnecessary API.
+ size_t GetSwitchCount() const;
- // Get a copy of all switches, along with their values
- const SwitchMap& GetSwitches() const {
- return switches_;
- }
+ // Get a copy of all switches, along with their values.
+ const SwitchMap& GetSwitches() const { return switches_; }
- // Get the remaining arguments to the command.
- const std::vector<StringType>& args() const { return args_; }
-
-#if defined(OS_WIN)
- // Returns the original command line string.
- const std::wstring& command_line_string() const {
- return command_line_string_;
- }
-#elif defined(OS_POSIX)
- // Returns the original command line string as a vector of strings.
- const std::vector<std::string>& argv() const {
- return argv_;
- }
- // Try to match the same result as command_line_string() would get you
- // on windows.
- std::string command_line_string() const;
-#endif
-
- // Returns the program part of the command line string (the first item).
- FilePath GetProgram() const;
-
- // Append a switch to the command line.
+ // Append a switch [with optional value] to the command line.
+ // CAUTION! Appending a switch after the "--" switch terminator is futile!
void AppendSwitch(const std::string& switch_string);
-
- // Append a switch and value to the command line.
void AppendSwitchPath(const std::string& switch_string, const FilePath& path);
void AppendSwitchNative(const std::string& switch_string,
const StringType& value);
void AppendSwitchASCII(const std::string& switch_string,
const std::string& value);
+ void AppendSwitches(const CommandLine& other);
+
+ // Copy a set of switches (and any values) from another command line.
+ // Commonly used when launching a subprocess.
+ void CopySwitchesFrom(const CommandLine& source, const char* const switches[],
+ size_t count);
+
+ // Get the remaining arguments to the command.
+ const StringVector& args() const { return args_; }
- // Append an argument to the command line.
- // Note on quoting: the argument will be quoted properly such that it is
- // interpreted as one argument to the target command.
- // AppendArg is primarily for ASCII; non-ASCII input will be
- // interpreted as UTF-8.
+ // Append an argument to the command line. Note that the argument is quoted
+ // properly such that it is interpreted as one argument to the target command.
+ // AppendArg is primarily for ASCII; non-ASCII input is interpreted as UTF-8.
void AppendArg(const std::string& value);
void AppendArgPath(const FilePath& value);
void AppendArgNative(const StringType& value);
+ void AppendArgs(const CommandLine& other);
// Append the arguments from another command line to this one.
// If |include_program| is true, include |other|'s program as well.
void AppendArguments(const CommandLine& other,
bool include_program);
- // Insert a command before the current command. Common for debuggers,
- // like "valgrind" or "gdb --args".
+ // Insert a command before the current command.
+ // Common for debuggers, like "valgrind" or "gdb --args".
void PrependWrapper(const StringType& wrapper);
- // Copy a set of switches (and their values, if any) from another command
- // line. Commonly used when launching a subprocess.
- void CopySwitchesFrom(const CommandLine& source, const char* const switches[],
- size_t count);
+#if defined(OS_WIN)
+ // Initialize by parsing the given command line string.
+ // The program name is assumed to be the first item in the string.
+ void ParseFromString(const std::wstring& command_line);
+#endif
private:
- friend class InProcessBrowserTest;
-
+ // Disallow public default construction; a program name must be specified.
CommandLine();
- // Used by InProcessBrowserTest.
- static CommandLine* ForCurrentProcessMutable();
-
- // Returns true and fills in |switch_string| and |switch_value|
- // if |parameter_string| represents a switch.
- static bool IsSwitch(const StringType& parameter_string,
- std::string* switch_string,
- StringType* switch_value);
-
- // The singleton CommandLine instance representing the current process's
- // command line.
+ // The singleton CommandLine representing the current process's command line.
static CommandLine* current_process_commandline_;
// We store a platform-native version of the command line, used when building
- // up a new command line to be executed. This ifdef delimits that code.
-
+ // up a new command line to be executed. This ifdef delimits that code.
#if defined(OS_WIN)
- // The quoted, space-separated command-line string.
- std::wstring command_line_string_;
+ // The quoted, space-separated command line string.
+ StringType command_line_string_;
// The name of the program.
- std::wstring program_;
+ StringType program_;
#elif defined(OS_POSIX)
// The argv array, with the program name in argv_[0].
- std::vector<std::string> argv_;
+ StringVector argv_;
#endif
- // Parsed-out values.
+ // Parsed-out switch keys and values.
SwitchMap switches_;
- // Non-switch command-line arguments.
- std::vector<StringType> args_;
+ // Non-switch command line arguments.
+ StringVector args_;
- // We allow copy constructors, because a common pattern is to grab a
- // copy of the current process's command line and then add some
- // flags to it. E.g.:
+ // Allow the copy constructor. A common pattern is to copy the current
+ // process's command line and then add some flags to it. For example:
// CommandLine cl(*CommandLine::ForCurrentProcess());
// cl.AppendSwitch(...);
};
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
index 6fd6440..5ce6911 100644
--- a/base/command_line_unittest.cc
+++ b/base/command_line_unittest.cc
@@ -109,9 +109,9 @@ TEST(CommandLineTest, EmptyString) {
EXPECT_TRUE(cl.GetProgram().empty());
#elif defined(OS_POSIX)
CommandLine cl(0, NULL);
- EXPECT_TRUE(cl.argv().size() == 0);
+ EXPECT_TRUE(cl.argv().empty());
#endif
- EXPECT_EQ(0U, cl.args().size());
+ EXPECT_TRUE(cl.args().empty());
}
// Test methods for appending switches to a command line.
diff --git a/base/cpu.cc b/base/cpu.cc
index 0fef897..3232f15 100644
--- a/base/cpu.cc
+++ b/base/cpu.cc
@@ -1,10 +1,16 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-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/cpu.h"
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#if defined(_MSC_VER)
#include <intrin.h>
-#include <string>
+#endif
+#endif
+
+#include <string.h>
namespace base {
@@ -15,11 +21,66 @@ CPU::CPU()
stepping_(0),
ext_model_(0),
ext_family_(0),
+ has_mmx_(false),
+ has_sse_(false),
+ has_sse2_(false),
+ has_sse3_(false),
+ has_ssse3_(false),
+ has_sse41_(false),
+ has_sse42_(false),
cpu_vendor_("unknown") {
Initialize();
}
+#if defined(ARCH_CPU_X86_FAMILY)
+#ifndef _MSC_VER
+
+#if defined(__pic__) && defined(__i386__)
+
+void __cpuid(int cpu_info[4], int info_type) {
+ __asm__ volatile (
+ "mov %%ebx, %%edi\n"
+ "cpuid\n"
+ "xchg %%edi, %%ebx\n"
+ : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+ : "a"(info_type)
+ );
+}
+
+void __cpuidex(int cpu_info[4], int info_type, int info_index) {
+ __asm__ volatile (
+ "mov %%ebx, %%edi\n"
+ "cpuid\n"
+ "xchg %%edi, %%ebx\n"
+ : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+ : "a"(info_type), "c"(info_index)
+ );
+}
+
+#else
+
+void __cpuid(int cpu_info[4], int info_type) {
+ __asm__ volatile (
+ "cpuid \n\t"
+ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+ : "a"(info_type)
+ );
+}
+
+void __cpuidex(int cpu_info[4], int info_type, int info_index) {
+ __asm__ volatile (
+ "cpuid \n\t"
+ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+ : "a"(info_type), "c"(info_index)
+ );
+}
+
+#endif
+#endif // _MSC_VER
+#endif // ARCH_CPU_X86_FAMILY
+
void CPU::Initialize() {
+#if defined(ARCH_CPU_X86_FAMILY)
int cpu_info[4] = {-1};
char cpu_string[0x20];
@@ -42,13 +103,23 @@ void CPU::Initialize() {
if (num_ids > 0) {
__cpuid(cpu_info, 1);
stepping_ = cpu_info[0] & 0xf;
- model_ = (cpu_info[0] >> 4) & 0xf;
+ model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
family_ = (cpu_info[0] >> 8) & 0xf;
type_ = (cpu_info[0] >> 12) & 0x3;
ext_model_ = (cpu_info[0] >> 16) & 0xf;
ext_family_ = (cpu_info[0] >> 20) & 0xff;
cpu_vendor_ = cpu_string;
+ has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
+ has_sse_ = (cpu_info[3] & 0x02000000) != 0;
+ has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
+ has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
+ has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
+ has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
+ has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
}
+#endif
}
+
+
} // namespace base
diff --git a/base/cpu.h b/base/cpu.h
index 963da1a..1634bf9 100644
--- a/base/cpu.h
+++ b/base/cpu.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-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.
@@ -6,6 +6,8 @@
#define BASE_CPU_H_
#pragma once
+#include "build/build_config.h"
+
#include <string>
namespace base {
@@ -24,6 +26,13 @@ class CPU {
int type() const { return type_; }
int extended_model() const { return ext_model_; }
int extended_family() const { return ext_family_; }
+ int has_mmx() const { return has_mmx_; }
+ int has_sse() const { return has_sse_; }
+ int has_sse2() const { return has_sse2_; }
+ int has_sse3() const { return has_sse3_; }
+ int has_ssse3() const { return has_ssse3_; }
+ int has_sse41() const { return has_sse41_; }
+ int has_sse42() const { return has_sse42_; }
private:
// Query the processor for CPUID information.
@@ -35,6 +44,13 @@ class CPU {
int stepping_; // processor revision number
int ext_model_;
int ext_family_;
+ bool has_mmx_;
+ bool has_sse_;
+ bool has_sse2_;
+ bool has_sse3_;
+ bool has_ssse3_;
+ bool has_sse41_;
+ bool has_sse42_;
std::string cpu_vendor_;
};
diff --git a/base/cpu_unittest.cc b/base/cpu_unittest.cc
new file mode 100644
index 0000000..f9351cc
--- /dev/null
+++ b/base/cpu_unittest.cc
@@ -0,0 +1,91 @@
+// 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/cpu.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Tests whether we can run extended instructions represented by the CPU
+// information. This test actually executes some extended instructions (such as
+// MMX, SSE, etc.) supported by the CPU and sees we can run them without
+// "undefined instruction" exceptions. That is, this test succeeds when this
+// test finishes without a crash.
+TEST(CPU, RunExtendedInstructions) {
+#if defined(ARCH_CPU_X86_FAMILY)
+ // Retrieve the CPU information.
+ base::CPU cpu;
+
+#if defined(OS_WIN)
+ ASSERT_TRUE(cpu.has_mmx());
+
+ // Execute an MMX instruction.
+ __asm emms;
+
+ if (cpu.has_sse()) {
+ // Execute an SSE instruction.
+ __asm xorps xmm0, xmm0;
+ }
+
+ if (cpu.has_sse2()) {
+ // Execute an SSE 2 instruction.
+ __asm psrldq xmm0, 0;
+ }
+
+ if (cpu.has_sse3()) {
+ // Execute an SSE 3 instruction.
+ __asm addsubpd xmm0, xmm0;
+ }
+
+ if (cpu.has_ssse3()) {
+ // Execute a Supplimental SSE 3 instruction.
+ __asm psignb xmm0, xmm0;
+ }
+
+ if (cpu.has_sse41()) {
+ // Execute an SSE 4.1 instruction.
+ __asm pmuldq xmm0, xmm0;
+ }
+
+ if (cpu.has_sse42()) {
+ // Execute an SSE 4.2 instruction.
+ __asm crc32 eax, eax;
+ }
+#elif defined(OS_POSIX) && defined(__x86_64__)
+ ASSERT_TRUE(cpu.has_mmx());
+
+ // Execute an MMX instruction.
+ __asm__ __volatile__("emms\n" : : : "mm0");
+
+ if (cpu.has_sse()) {
+ // Execute an SSE instruction.
+ __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0");
+ }
+
+ if (cpu.has_sse2()) {
+ // Execute an SSE 2 instruction.
+ __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0");
+ }
+
+ if (cpu.has_sse3()) {
+ // Execute an SSE 3 instruction.
+ __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0");
+ }
+
+ if (cpu.has_ssse3()) {
+ // Execute a Supplimental SSE 3 instruction.
+ __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0");
+ }
+
+ if (cpu.has_sse41()) {
+ // Execute an SSE 4.1 instruction.
+ __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0");
+ }
+
+ if (cpu.has_sse42()) {
+ // Execute an SSE 4.2 instruction.
+ __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax");
+ }
+#endif
+#endif
+}
diff --git a/base/crypto/encryptor_mac.cc b/base/crypto/encryptor_mac.cc
index d27c62e..e26c6bd 100644
--- a/base/crypto/encryptor_mac.cc
+++ b/base/crypto/encryptor_mac.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -12,7 +12,9 @@
namespace base {
-Encryptor::Encryptor() {
+Encryptor::Encryptor()
+ : key_(NULL),
+ mode_(CBC) {
}
Encryptor::~Encryptor() {
diff --git a/base/crypto/encryptor_nss.cc b/base/crypto/encryptor_nss.cc
index 737e8f2..3b9f7f3 100644
--- a/base/crypto/encryptor_nss.cc
+++ b/base/crypto/encryptor_nss.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -13,7 +13,9 @@
namespace base {
-Encryptor::Encryptor() {
+Encryptor::Encryptor()
+ : key_(NULL),
+ mode_(CBC) {
EnsureNSSInit();
}
@@ -83,7 +85,7 @@ bool Encryptor::Encrypt(const std::string& plaintext, std::string* ciphertext) {
}
bool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) {
- if (ciphertext.size() == 0)
+ if (ciphertext.empty())
return false;
ScopedPK11Context context(PK11_CreateContextBySymKey(CKM_AES_CBC_PAD,
diff --git a/base/crypto/encryptor_openssl.cc b/base/crypto/encryptor_openssl.cc
index 7e09545..0e101a0 100644
--- a/base/crypto/encryptor_openssl.cc
+++ b/base/crypto/encryptor_openssl.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -45,7 +45,8 @@ class ScopedCipherCTX {
} // namespace
Encryptor::Encryptor()
- : key_(NULL) {
+ : key_(NULL),
+ mode_(CBC) {
}
Encryptor::~Encryptor() {
diff --git a/base/crypto/encryptor_win.cc b/base/crypto/encryptor_win.cc
index 4a137b3..1d732b5 100644
--- a/base/crypto/encryptor_win.cc
+++ b/base/crypto/encryptor_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -28,7 +28,10 @@ DWORD GetCipherBlockSize(HCRYPTKEY key) {
} // namespace
-Encryptor::Encryptor() {
+Encryptor::Encryptor()
+ : key_(NULL),
+ mode_(CBC),
+ block_size_(0) {
}
Encryptor::~Encryptor() {
diff --git a/base/debug/debug_on_start_win.cc b/base/debug/debug_on_start_win.cc
index b5c1094..6ca88dd 100644
--- a/base/debug/debug_on_start_win.cc
+++ b/base/debug/debug_on_start_win.cc
@@ -20,7 +20,7 @@ namespace debug {
// /-/argument.
// Note: command_line is non-destructively modified.
bool DebugOnStart::FindArgument(wchar_t* command_line, const char* argument_c) {
- wchar_t argument[50];
+ wchar_t argument[50] = {};
for (int i = 0; argument_c[i]; ++i)
argument[i] = argument_c[i];
diff --git a/base/event_recorder.cc b/base/event_recorder.cc
index 7c3336b..1119b4f 100644
--- a/base/event_recorder.cc
+++ b/base/event_recorder.cc
@@ -49,7 +49,7 @@ bool EventRecorder::StartRecording(const FilePath& filename) {
return false;
// Open the recording file.
- DCHECK(file_ == NULL);
+ DCHECK(!file_);
file_ = file_util::OpenFile(filename, "wb+");
if (!file_) {
DLOG(ERROR) << "EventRecorder could not open log file";
@@ -100,7 +100,7 @@ bool EventRecorder::StartPlayback(const FilePath& filename) {
return false;
// Open the recording file.
- DCHECK(file_ == NULL);
+ DCHECK(!file_);
file_ = file_util::OpenFile(filename, "rb");
if (!file_) {
DLOG(ERROR) << "EventRecorder Playback could not open log file";
diff --git a/base/file_path.cc b/base/file_path.cc
index 5f1375a..29ec7a8 100644
--- a/base/file_path.cc
+++ b/base/file_path.cc
@@ -249,9 +249,8 @@ bool FilePath::AppendRelativePath(const FilePath& child,
GetComponents(&parent_components);
child.GetComponents(&child_components);
- if (parent_components.size() >= child_components.size())
- return false;
- if (parent_components.size() == 0)
+ if (parent_components.empty() ||
+ parent_components.size() >= child_components.size())
return false;
std::vector<StringType>::const_iterator parent_comp =
@@ -520,6 +519,12 @@ string16 FilePath::LossyDisplayName() const {
return WideToUTF16(base::SysNativeMBToWide(path_));
}
+std::string FilePath::MaybeAsASCII() const {
+ if (IsStringASCII(path_))
+ return path_;
+ return "";
+}
+
// The *Hack functions are temporary while we fix the remainder of the code.
// Remember to remove the #includes at the top when you remove these.
@@ -535,6 +540,12 @@ string16 FilePath::LossyDisplayName() const {
return path_;
}
+std::string FilePath::MaybeAsASCII() const {
+ if (IsStringASCII(path_))
+ return WideToASCII(path_);
+ return "";
+}
+
// static
FilePath FilePath::FromWStringHack(const std::wstring& wstring) {
return FilePath(wstring);
diff --git a/base/file_path.h b/base/file_path.h
index 84bb350..1afa7a6 100644
--- a/base/file_path.h
+++ b/base/file_path.h
@@ -283,6 +283,11 @@ class FilePath {
// want to stuff a string16 into some other API.
string16 LossyDisplayName() const;
+ // Return the path as ASCII, or the empty string if the path is not ASCII.
+ // This should only be used for cases where the FilePath is representing a
+ // known-ASCII filename.
+ std::string MaybeAsASCII() const;
+
// Older Chromium code assumes that paths are always wstrings.
// These functions convert wstrings to/from FilePaths, and are
// useful to smooth porting that old code to the FilePath API.
diff --git a/base/file_util.cc b/base/file_util.cc
index c9661e7..7cf67dd 100644
--- a/base/file_util.cc
+++ b/base/file_util.cc
@@ -341,7 +341,7 @@ bool MemoryMappedFile::Initialize(base::PlatformFile file) {
return true;
}
-bool MemoryMappedFile::IsValid() {
+bool MemoryMappedFile::IsValid() const {
return data_ != NULL;
}
diff --git a/base/file_util.h b/base/file_util.h
index ab6906d..108c998 100644
--- a/base/file_util.h
+++ b/base/file_util.h
@@ -506,11 +506,17 @@ class MemoryMappedFile {
// ownership of |file| and close it when done.
bool Initialize(base::PlatformFile file);
+#if defined(OS_WIN)
+ // Opens an existing file and maps it as an image section. Please refer to
+ // the Initialize function above for additional information.
+ bool InitializeAsImageSection(const FilePath& file_name);
+#endif // OS_WIN
+
const uint8* data() const { return data_; }
size_t length() const { return length_; }
// Is file_ a valid file handle that points to an open, memory mapped file?
- bool IsValid();
+ bool IsValid() const;
private:
// Open the given file and pass it to MapFileToMemoryInternal().
@@ -523,10 +529,14 @@ class MemoryMappedFile {
// Closes all open handles. Later we may want to make this public.
void CloseHandles();
- base::PlatformFile file_;
#if defined(OS_WIN)
+ // MapFileToMemoryInternal calls this function. It provides the ability to
+ // pass in flags which control the mapped section.
+ bool MapFileToMemoryInternalEx(int flags);
+
HANDLE file_mapping_;
#endif
+ base::PlatformFile file_;
uint8* data_;
size_t length_;
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index 7dd4127..9a2d90a 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -633,7 +633,7 @@ FileEnumerator::FileEnumerator(const FilePath& root_path,
// The Windows version of this code appends the pattern to the root_path,
// potentially only matching against items in the top-most directory.
// Do the same here.
- if (pattern.size() == 0)
+ if (pattern.empty())
pattern_ = FilePath::StringType();
pending_paths_.push(root_path);
}
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index 51bcb4e..2c26a16 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -606,13 +606,11 @@ bool CreateTemporaryDirInDir(const FilePath& base_dir,
for (int count = 0; count < 50; ++count) {
// Try create a new temporary directory with random generated name. If
// the one exists, keep trying another path name until we reach some limit.
- path_to_create = base_dir;
-
string16 new_dir_name;
new_dir_name.assign(prefix);
new_dir_name.append(base::IntToString16(rand() % kint16max));
- path_to_create = path_to_create.Append(new_dir_name);
+ path_to_create = base_dir.Append(new_dir_name);
if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
*new_dir = path_to_create;
return true;
@@ -940,7 +938,31 @@ MemoryMappedFile::MemoryMappedFile()
length_(INVALID_FILE_SIZE) {
}
+bool MemoryMappedFile::InitializeAsImageSection(const FilePath& file_name) {
+ if (IsValid())
+ return false;
+ file_ = base::CreatePlatformFile(
+ file_name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
+ NULL, NULL);
+
+ if (file_ == base::kInvalidPlatformFileValue) {
+ LOG(ERROR) << "Couldn't open " << file_name.value();
+ return false;
+ }
+
+ if (!MapFileToMemoryInternalEx(SEC_IMAGE)) {
+ CloseHandles();
+ return false;
+ }
+
+ return true;
+}
+
bool MemoryMappedFile::MapFileToMemoryInternal() {
+ return MapFileToMemoryInternalEx(0);
+}
+
+bool MemoryMappedFile::MapFileToMemoryInternalEx(int flags) {
base::ThreadRestrictions::AssertIOAllowed();
if (file_ == INVALID_HANDLE_VALUE)
@@ -952,7 +974,7 @@ bool MemoryMappedFile::MapFileToMemoryInternal() {
// length_ value comes from GetFileSize() above. GetFileSize() returns DWORD,
// therefore the cast here is safe.
- file_mapping_ = ::CreateFileMapping(file_, NULL, PAGE_READONLY,
+ file_mapping_ = ::CreateFileMapping(file_, NULL, PAGE_READONLY | flags,
0, static_cast<DWORD>(length_), NULL);
if (!file_mapping_) {
// According to msdn, system error codes are only reserved up to 15999.
diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h
index 879edb3..d8cb1a6 100644
--- a/base/file_version_info_mac.h
+++ b/base/file_version_info_mac.h
@@ -20,6 +20,7 @@ class NSBundle;
class FileVersionInfoMac : public FileVersionInfo {
public:
explicit FileVersionInfoMac(NSBundle *bundle);
+ virtual ~FileVersionInfoMac();
// Accessors to the different version properties.
// Returns an empty string if the property is not found.
@@ -41,8 +42,6 @@ class FileVersionInfoMac : public FileVersionInfo {
virtual bool is_official_build();
private:
-
-
// Returns a string16 value for a property name.
// Returns the empty string if the property does not exist.
string16 GetString16Value(CFStringRef name);
diff --git a/base/file_version_info_mac.mm b/base/file_version_info_mac.mm
index f716ccc..bcfd854 100644
--- a/base/file_version_info_mac.mm
+++ b/base/file_version_info_mac.mm
@@ -14,6 +14,8 @@
FileVersionInfoMac::FileVersionInfoMac(NSBundle *bundle) : bundle_(bundle) {
}
+FileVersionInfoMac::~FileVersionInfoMac() {}
+
// static
FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForCurrentModule() {
return CreateFileVersionInfo(base::mac::MainAppBundlePath());
diff --git a/base/i18n/bidi_line_iterator.cc b/base/i18n/bidi_line_iterator.cc
index 3222a3a..5e9cd11 100644
--- a/base/i18n/bidi_line_iterator.cc
+++ b/base/i18n/bidi_line_iterator.cc
@@ -22,7 +22,7 @@ BiDiLineIterator::~BiDiLineIterator() {
bool BiDiLineIterator::Open(const string16& text,
bool right_to_left,
bool url) {
- DCHECK(bidi_ == NULL);
+ DCHECK(!bidi_);
UErrorCode error = U_ZERO_ERROR;
bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
if (U_FAILURE(error))
diff --git a/base/i18n/icu_string_conversions.cc b/base/i18n/icu_string_conversions.cc
index c353feb..6b46537 100644
--- a/base/i18n/icu_string_conversions.cc
+++ b/base/i18n/icu_string_conversions.cc
@@ -221,8 +221,9 @@ bool WideToCodepage(const std::wstring& wide,
// in case each code points translates to a UTF-16 surrogate pair,
// and leave room for a NUL terminator.
std::vector<UChar> utf16(wide.length() * 2 + 1);
- u_strFromWCS(&utf16[0], utf16.size(), &utf16_len,
- wide.c_str(), wide.length(), &status);
+ u_strFromUTF32(&utf16[0], utf16.size(), &utf16_len,
+ reinterpret_cast<const UChar32*>(wide.c_str()),
+ wide.length(), &status);
DCHECK(U_SUCCESS(status)) << "failed to convert wstring to UChar*";
return ConvertFromUTF16(converter, &utf16[0], utf16_len, on_error, encoded);
diff --git a/base/id_map.h b/base/id_map.h
index 9a41d74..5aea98e 100644
--- a/base/id_map.h
+++ b/base/id_map.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// 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.
@@ -11,6 +11,7 @@
#include "base/basictypes.h"
#include "base/hash_tables.h"
#include "base/logging.h"
+#include "base/threading/non_thread_safe.h"
// Ownership semantics - own pointer means the pointer is deleted in Remove()
// & during destruction
@@ -31,16 +32,23 @@ enum IDMapOwnershipSemantics {
// This class does not have a virtual destructor, do not inherit from it when
// ownership semantics are set to own because pointers will leak.
template<typename T, IDMapOwnershipSemantics OS = IDMapExternalPointer>
-class IDMap {
+class IDMap : public base::NonThreadSafe {
private:
typedef int32 KeyType;
typedef base::hash_map<KeyType, T*> HashTable;
public:
IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) {
+ // A number of consumers of IDMap create it on one thread but always access
+ // it from a different, but consitent, thread post-construction.
+ DetachFromThread();
}
~IDMap() {
+ // Many IDMap's are static, and hence will be destroyed on the main thread.
+ // However, all the accesses may take place on another thread, such as the
+ // IO thread. Detaching again to clean this up.
+ DetachFromThread();
Releaser<OS, 0>::release_all(&data_);
}
@@ -49,6 +57,7 @@ class IDMap {
// Adds a view with an automatically generated unique ID. See AddWithID.
KeyType Add(T* data) {
+ DCHECK(CalledOnValidThread());
CHECK(!check_on_null_data_ || data);
KeyType this_id = next_id_;
DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item";
@@ -62,12 +71,14 @@ class IDMap {
// this function, or allow this object to generate IDs and call Add. These
// two methods may not be mixed, or duplicate IDs may be generated
void AddWithID(T* data, KeyType id) {
+ DCHECK(CalledOnValidThread());
CHECK(!check_on_null_data_ || data);
DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
data_[id] = data;
}
void Remove(KeyType id) {
+ DCHECK(CalledOnValidThread());
typename HashTable::iterator i = data_.find(id);
if (i == data_.end()) {
NOTREACHED() << "Attempting to remove an item not in the list";
@@ -83,10 +94,12 @@ class IDMap {
}
bool IsEmpty() const {
+ DCHECK(CalledOnValidThread());
return size() == 0u;
}
T* Lookup(KeyType id) const {
+ DCHECK(CalledOnValidThread());
typename HashTable::const_iterator i = data_.find(id);
if (i == data_.end())
return NULL;
@@ -94,6 +107,7 @@ class IDMap {
}
size_t size() const {
+ DCHECK(CalledOnValidThread());
return data_.size() - removed_ids_.size();
}
@@ -105,28 +119,34 @@ class IDMap {
Iterator(IDMap<T, OS>* map)
: map_(map),
iter_(map_->data_.begin()) {
+ DCHECK(map->CalledOnValidThread());
++map_->iteration_depth_;
SkipRemovedEntries();
}
~Iterator() {
+ DCHECK(map_->CalledOnValidThread());
if (--map_->iteration_depth_ == 0)
map_->Compact();
}
bool IsAtEnd() const {
+ DCHECK(map_->CalledOnValidThread());
return iter_ == map_->data_.end();
}
KeyType GetCurrentKey() const {
+ DCHECK(map_->CalledOnValidThread());
return iter_->first;
}
ReturnType* GetCurrentValue() const {
+ DCHECK(map_->CalledOnValidThread());
return iter_->second;
}
void Advance() {
+ DCHECK(map_->CalledOnValidThread());
++iter_;
SkipRemovedEntries();
}
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
index f4cfda0..a22dbf3 100644
--- a/base/lazy_instance.h
+++ b/base/lazy_instance.h
@@ -88,7 +88,7 @@ class LazyInstanceHelper {
STATE_CREATED = 2
};
- explicit LazyInstanceHelper(LinkerInitialized x) { /* state_ is 0 */ }
+ explicit LazyInstanceHelper(LinkerInitialized /*unused*/) {/* state_ is 0 */}
// Declaring a destructor (even if it's empty) will cause MSVC to register a
// static initializer to register the empty destructor with atexit().
@@ -127,7 +127,7 @@ class LazyInstance : public LazyInstanceHelper {
NeedsInstance()) {
// Create the instance in the space provided by |buf_|.
instance_ = Traits::New(buf_);
- // Traits::Delete will be null for LeakyLazyInstannceTraits
+ // Traits::Delete will be null for LeakyLazyInstanceTraits
void (*dtor)(void*) = Traits::Delete;
CompleteInstance(this, (dtor == NULL) ? NULL : OnExit);
}
@@ -141,6 +141,19 @@ class LazyInstance : public LazyInstanceHelper {
return instance_;
}
+ bool operator==(Type* p) {
+ switch (base::subtle::NoBarrier_Load(&state_)) {
+ case STATE_EMPTY:
+ return p == NULL;
+ case STATE_CREATING:
+ return static_cast<int8*>(static_cast<void*>(p)) == buf_;
+ case STATE_CREATED:
+ return p == instance_;
+ default:
+ return false;
+ }
+ }
+
private:
// Adapter function for use with AtExit. This should be called single
// threaded, so don't use atomic operations.
diff --git a/base/logging.cc b/base/logging.cc
index 27bf6c2..57a2a89 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -14,7 +14,6 @@ typedef HANDLE MutexHandle;
// Windows doesn't define STDERR_FILENO. Define it here.
#define STDERR_FILENO 2
#elif defined(OS_MACOSX)
-#include <CoreFoundation/CoreFoundation.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h>
@@ -57,10 +56,6 @@ typedef pthread_mutex_t* MutexHandle;
#if defined(OS_POSIX)
#include "base/safe_strerror_posix.h"
#endif
-#if defined(OS_MACOSX)
-#include "base/mac/scoped_cftyperef.h"
-#include "base/sys_string_conversions.h"
-#endif
namespace logging {
@@ -509,12 +504,6 @@ void DisplayDebugMessageInDialog(const std::string& str) {
MessageBoxW(NULL, &cmdline[0], L"Fatal error",
MB_OK | MB_ICONHAND | MB_TOPMOST);
}
-#elif defined(OS_MACOSX)
- base::mac::ScopedCFTypeRef<CFStringRef> message(
- base::SysUTF8ToCFStringRef(str));
- CFUserNotificationDisplayNotice(0, kCFUserNotificationStopAlertLevel,
- NULL, NULL, NULL, CFSTR("Fatal Error"),
- message, NULL);
#else
// We intentionally don't implement a dialog on other platforms.
// You can just look at stderr.
diff --git a/base/logging.h b/base/logging.h
index b1bc0b0..baf8eb6 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -382,6 +382,23 @@ const LogSeverity LOG_0 = LOG_ERROR;
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) \
@@ -539,6 +556,7 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#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
@@ -555,6 +573,7 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#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
@@ -589,6 +608,8 @@ enum { DEBUG_MODE = ENABLE_DLOG };
#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
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
index d75fb6e..990197d 100644
--- a/base/mac/mac_util.h
+++ b/base/mac/mac_util.h
@@ -110,57 +110,76 @@ void RemoveFromLoginItems();
// 'Login Item' with 'hide on startup' flag. Used to suppress opening windows.
bool WasLaunchedAsHiddenLoginItem();
-#if defined(__OBJC__)
+} // namespace mac
+} // namespace base
+
+#if !defined(__OBJC__)
+#define OBJC_CPP_CLASS_DECL(x) class x;
+#else // __OBJC__
+#define OBJC_CPP_CLASS_DECL(x)
+#endif // __OBJC__
-// Convert toll-free bridged CFTypes to NSTypes. This does not autorelease
-// |cf_val|. This is useful for the case where there is a CFType in a call that
-// expects an NSType and the compiler is complaining about const casting
-// problems.
-// The call is used like this:
+// Convert toll-free bridged CFTypes to NSTypes and vice-versa. This does not
+// autorelease |cf_val|. This is useful for the case where there is a CFType in
+// a call that expects an NSType and the compiler is complaining about const
+// casting problems.
+// The calls are used like this:
// NSString *foo = CFToNSCast(CFSTR("Hello"));
+// CFStringRef foo2 = NSToCFCast(@"Hello");
// The macro magic below is to enforce safe casting. It could possibly have
// been done using template function specialization, but template function
// specialization doesn't always work intuitively,
// (http://www.gotw.ca/publications/mill17.htm) so the trusty combination
// of macros and function overloading is used instead.
-#define CF_TO_NS_CAST(TypeCF, TypeNS) \
-inline TypeNS* CFToNSCast(TypeCF cf_val) { \
- TypeNS* ns_val = \
- const_cast<TypeNS*>(reinterpret_cast<const TypeNS*>(cf_val)); \
- DCHECK(!ns_val || [ns_val isKindOfClass:[TypeNS class]]); \
- return ns_val; \
-}
+#define CF_TO_NS_CAST_DECL(TypeCF, TypeNS) \
+OBJC_CPP_CLASS_DECL(TypeNS) \
+\
+namespace base { \
+namespace mac { \
+TypeNS* CFToNSCast(TypeCF##Ref cf_val); \
+TypeCF##Ref NSToCFCast(TypeNS* ns_val); \
+} \
+} \
+
+#define CF_TO_NS_MUTABLE_CAST_DECL(name) \
+CF_TO_NS_CAST_DECL(CF##name, NS##name) \
+OBJC_CPP_CLASS_DECL(NSMutable##name) \
+\
+namespace base { \
+namespace mac { \
+NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val); \
+CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val); \
+} \
+} \
// List of toll-free bridged types taken from:
// http://www.cocoadev.com/index.pl?TollFreeBridged
-CF_TO_NS_CAST(CFArrayRef, NSArray);
-CF_TO_NS_CAST(CFMutableArrayRef, NSMutableArray);
-CF_TO_NS_CAST(CFAttributedStringRef, NSAttributedString);
-CF_TO_NS_CAST(CFMutableAttributedStringRef, NSMutableAttributedString);
-CF_TO_NS_CAST(CFCalendarRef, NSCalendar);
-CF_TO_NS_CAST(CFCharacterSetRef, NSCharacterSet);
-CF_TO_NS_CAST(CFMutableCharacterSetRef, NSMutableCharacterSet);
-CF_TO_NS_CAST(CFDataRef, NSData);
-CF_TO_NS_CAST(CFMutableDataRef, NSMutableData);
-CF_TO_NS_CAST(CFDateRef, NSDate);
-CF_TO_NS_CAST(CFDictionaryRef, NSDictionary);
-CF_TO_NS_CAST(CFMutableDictionaryRef, NSMutableDictionary);
-CF_TO_NS_CAST(CFNumberRef, NSNumber);
-CF_TO_NS_CAST(CFRunLoopTimerRef, NSTimer);
-CF_TO_NS_CAST(CFSetRef, NSSet);
-CF_TO_NS_CAST(CFMutableSetRef, NSMutableSet);
-CF_TO_NS_CAST(CFStringRef, NSString);
-CF_TO_NS_CAST(CFMutableStringRef, NSMutableString);
-CF_TO_NS_CAST(CFURLRef, NSURL);
-CF_TO_NS_CAST(CFTimeZoneRef, NSTimeZone);
-CF_TO_NS_CAST(CFReadStreamRef, NSInputStream);
-CF_TO_NS_CAST(CFWriteStreamRef, NSOutputStream);
-
-#endif // __OBJC__
-
-} // namespace mac
-} // namespace base
+CF_TO_NS_MUTABLE_CAST_DECL(Array);
+CF_TO_NS_MUTABLE_CAST_DECL(AttributedString);
+CF_TO_NS_CAST_DECL(CFCalendar, NSCalendar);
+CF_TO_NS_MUTABLE_CAST_DECL(CharacterSet);
+CF_TO_NS_MUTABLE_CAST_DECL(Data);
+CF_TO_NS_CAST_DECL(CFDate, NSDate);
+CF_TO_NS_MUTABLE_CAST_DECL(Dictionary);
+CF_TO_NS_CAST_DECL(CFError, NSError);
+CF_TO_NS_CAST_DECL(CFLocale, NSLocale);
+CF_TO_NS_CAST_DECL(CFNumber, NSNumber);
+CF_TO_NS_CAST_DECL(CFRunLoopTimer, NSTimer);
+CF_TO_NS_CAST_DECL(CFTimeZone, NSTimeZone);
+CF_TO_NS_MUTABLE_CAST_DECL(Set);
+CF_TO_NS_CAST_DECL(CFReadStream, NSInputStream);
+CF_TO_NS_CAST_DECL(CFWriteStream, NSOutputStream);
+CF_TO_NS_MUTABLE_CAST_DECL(String);
+CF_TO_NS_CAST_DECL(CFURL, NSURL);
+
+// Stream operations for CFTypes. They can be used with NSTypes as well
+// by using the NSToCFCast methods above.
+// e.g. LOG(INFO) << base::mac::NSToCFCast(@"foo");
+// Operator << can not be overloaded for ObjectiveC types as the compiler
+// can not distinguish between overloads for id with overloads for void*.
+extern std::ostream& operator<<(std::ostream& o, const CFErrorRef err);
+extern std::ostream& operator<<(std::ostream& o, const CFStringRef str);
#endif // BASE_MAC_MAC_UTIL_H_
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
index 7f3be18..2eddeae 100644
--- a/base/mac/mac_util.mm
+++ b/base/mac/mac_util.mm
@@ -480,5 +480,77 @@ bool WasLaunchedAsHiddenLoginItem() {
return IsHiddenLoginItem(item);
}
+// Definitions for the corresponding CF_TO_NS_CAST_DECL macros in mac_util.h.
+#define CF_TO_NS_CAST_DEFN(TypeCF, TypeNS) \
+\
+TypeNS* CFToNSCast(TypeCF##Ref cf_val) { \
+ DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
+ TypeNS* ns_val = \
+ const_cast<TypeNS*>(reinterpret_cast<const TypeNS*>(cf_val)); \
+ return ns_val; \
+} \
+\
+TypeCF##Ref NSToCFCast(TypeNS* ns_val) { \
+ TypeCF##Ref cf_val = reinterpret_cast<TypeCF##Ref>(ns_val); \
+ DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
+ return cf_val; \
+} \
+
+#define CF_TO_NS_MUTABLE_CAST_DEFN(name) \
+CF_TO_NS_CAST_DEFN(CF##name, NS##name) \
+\
+NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val) { \
+ DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
+ NSMutable##name* ns_val = reinterpret_cast<NSMutable##name*>(cf_val); \
+ return ns_val; \
+} \
+\
+CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val) { \
+ CFMutable##name##Ref cf_val = \
+ reinterpret_cast<CFMutable##name##Ref>(ns_val); \
+ DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
+ return cf_val; \
+} \
+
+CF_TO_NS_MUTABLE_CAST_DEFN(Array);
+CF_TO_NS_MUTABLE_CAST_DEFN(AttributedString);
+CF_TO_NS_CAST_DEFN(CFCalendar, NSCalendar);
+CF_TO_NS_MUTABLE_CAST_DEFN(CharacterSet);
+CF_TO_NS_MUTABLE_CAST_DEFN(Data);
+CF_TO_NS_CAST_DEFN(CFDate, NSDate);
+CF_TO_NS_MUTABLE_CAST_DEFN(Dictionary);
+CF_TO_NS_CAST_DEFN(CFError, NSError);
+CF_TO_NS_CAST_DEFN(CFLocale, NSLocale);
+CF_TO_NS_CAST_DEFN(CFNumber, NSNumber);
+CF_TO_NS_CAST_DEFN(CFRunLoopTimer, NSTimer);
+CF_TO_NS_CAST_DEFN(CFTimeZone, NSTimeZone);
+CF_TO_NS_MUTABLE_CAST_DEFN(Set);
+CF_TO_NS_CAST_DEFN(CFReadStream, NSInputStream);
+CF_TO_NS_CAST_DEFN(CFWriteStream, NSOutputStream);
+CF_TO_NS_MUTABLE_CAST_DEFN(String);
+CF_TO_NS_CAST_DEFN(CFURL, NSURL);
+
} // namespace mac
} // namespace base
+
+std::ostream& operator<<(std::ostream& o, const CFStringRef string) {
+ return o << base::SysCFStringRefToUTF8(string);
+}
+
+std::ostream& operator<<(std::ostream& o, const CFErrorRef err) {
+ base::mac::ScopedCFTypeRef<CFStringRef> desc(CFErrorCopyDescription(err));
+ base::mac::ScopedCFTypeRef<CFDictionaryRef> user_info(
+ CFErrorCopyUserInfo(err));
+ CFStringRef errorDesc = NULL;
+ if (user_info.get()) {
+ errorDesc = reinterpret_cast<CFStringRef>(
+ CFDictionaryGetValue(user_info.get(), kCFErrorDescriptionKey));
+ }
+ o << "Code: " << CFErrorGetCode(err)
+ << " Domain: " << CFErrorGetDomain(err)
+ << " Desc: " << desc.get();
+ if(errorDesc) {
+ o << "(" << errorDesc << ")";
+ }
+ return o;
+}
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 2ec872f..348ace7 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -4,6 +4,11 @@
#include "base/message_loop.h"
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#endif
+
#include <algorithm>
#include "base/compiler_specific.h"
@@ -669,7 +674,17 @@ void MessageLoopForUI::DidProcessMessage(const MSG& message) {
}
#endif // defined(OS_WIN)
+<<<<<<< HEAD
#if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(ANDROID)
+=======
+#if defined(USE_X11)
+Display* MessageLoopForUI::GetDisplay() {
+ return gdk_x11_get_default_xdisplay();
+}
+#endif // defined(USE_X11)
+
+#if !defined(OS_MACOSX) && !defined(OS_NACL)
+>>>>>>> chromium.org at r11.0.696.0
void MessageLoopForUI::AddObserver(Observer* observer) {
pump_ui()->AddObserver(observer);
}
diff --git a/base/message_loop.h b/base/message_loop.h
index d238997..c1dce43 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -24,6 +24,7 @@
#include "base/message_pump_libevent.h"
#if !defined(OS_MACOSX)
#include "base/message_pump_glib.h"
+typedef struct _XDisplay Display;
#endif
#endif
#if defined(TOUCH_UI)
@@ -464,9 +465,9 @@ class MessageLoop : public base::MessagePump::Delegate {
scoped_refptr<base::Histogram> message_histogram_;
// A null terminated list which creates an incoming_queue of tasks that are
- // acquired under a mutex for processing on this instance's thread. These tasks
- // have not yet been sorted out into items for our work_queue_ vs items that
- // will be handled by the TimerManager.
+ // acquired under a mutex for processing on this instance's thread. These
+ // tasks have not yet been sorted out into items for our work_queue_ vs
+ // items that will be handled by the TimerManager.
TaskQueue incoming_queue_;
// Protect access to incoming_queue_.
mutable base::Lock incoming_queue_lock_;
@@ -508,6 +509,18 @@ class MessageLoopForUI : public MessageLoop {
void DidProcessMessage(const MSG& message);
#endif // defined(OS_WIN)
+#if defined(USE_X11)
+ // Returns the Xlib Display that backs the MessagePump for this MessageLoop.
+ //
+ // This allows for raw access to the X11 server in situations where our
+ // abstractions do not provide enough power.
+ //
+ // Be careful how this is used. The MessagePump in general expects
+ // exclusive access to the Display. Calling things like XNextEvent() will
+ // likely break things in subtle, hard to detect, ways.
+ Display* GetDisplay();
+#endif // defined(OS_X11)
+
#if !defined(OS_MACOSX)
// Please see message_pump_win/message_pump_glib for definitions of these
// methods.
diff --git a/base/message_loop_unittest.cc b/base/message_loop_unittest.cc
index 9576a58..2869bb8 100644
--- a/base/message_loop_unittest.cc
+++ b/base/message_loop_unittest.cc
@@ -768,6 +768,18 @@ class RecursiveTask : public OrderedTasks {
bool is_reentrant_;
};
+class RecursiveSlowTask : public RecursiveTask {
+ public:
+ RecursiveSlowTask(int depth, TaskList* order, int cookie, bool is_reentrant)
+ : RecursiveTask(depth, order, cookie, is_reentrant) {
+ }
+
+ virtual void Run() {
+ RecursiveTask::Run();
+ PlatformThread::Sleep(10); // milliseconds
+ }
+};
+
class QuitTask : public OrderedTasks {
public:
QuitTask(TaskList* order, int cookie)
@@ -893,6 +905,42 @@ void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) {
EXPECT_EQ(order[13], TaskItem(RECURSIVE, 2, false));
}
+void RunTest_RecursiveDenial3(MessageLoop::Type message_loop_type) {
+ MessageLoop loop(message_loop_type);
+
+ EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
+ TaskList order;
+ MessageLoop::current()->PostTask(FROM_HERE,
+ new RecursiveSlowTask(2, &order, 1, false));
+ MessageLoop::current()->PostTask(FROM_HERE,
+ new RecursiveSlowTask(2, &order, 2, false));
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ new OrderedTasks(&order, 3), 5);
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ new QuitTask(&order, 4), 5);
+
+ MessageLoop::current()->Run();
+
+ // FIFO order.
+ ASSERT_EQ(16U, order.size());
+ EXPECT_EQ(order[ 0], TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order[ 1], TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order[ 2], TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order[ 3], TaskItem(RECURSIVE, 2, false));
+ EXPECT_EQ(order[ 4], TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order[ 5], TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order[ 6], TaskItem(ORDERERD, 3, true));
+ EXPECT_EQ(order[ 7], TaskItem(ORDERERD, 3, false));
+ EXPECT_EQ(order[ 8], TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order[ 9], TaskItem(RECURSIVE, 2, false));
+ EXPECT_EQ(order[10], TaskItem(QUITMESSAGELOOP, 4, true));
+ EXPECT_EQ(order[11], TaskItem(QUITMESSAGELOOP, 4, false));
+ EXPECT_EQ(order[12], TaskItem(RECURSIVE, 1, true));
+ EXPECT_EQ(order[13], TaskItem(RECURSIVE, 1, false));
+ EXPECT_EQ(order[14], TaskItem(RECURSIVE, 2, true));
+ EXPECT_EQ(order[15], TaskItem(RECURSIVE, 2, false));
+}
+
void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) {
MessageLoop loop(message_loop_type);
@@ -1426,6 +1474,12 @@ TEST(MessageLoopTest, RecursiveDenial1) {
RunTest_RecursiveDenial1(MessageLoop::TYPE_IO);
}
+TEST(MessageLoopTest, RecursiveDenial3) {
+ RunTest_RecursiveDenial3(MessageLoop::TYPE_DEFAULT);
+ RunTest_RecursiveDenial3(MessageLoop::TYPE_UI);
+ RunTest_RecursiveDenial3(MessageLoop::TYPE_IO);
+}
+
TEST(MessageLoopTest, RecursiveSupport1) {
RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT);
RunTest_RecursiveSupport1(MessageLoop::TYPE_UI);
diff --git a/base/message_pump.h b/base/message_pump.h
index a354724..866b33a 100644
--- a/base/message_pump.h
+++ b/base/message_pump.h
@@ -22,7 +22,8 @@ class MessagePump : public RefCountedThreadSafe<MessagePump> {
// Called from within Run in response to ScheduleWork or when the message
// pump would otherwise call DoDelayedWork. Returns true to indicate that
- // work was done. DoDelayedWork will not be called if DoWork returns true.
+ // work was done. DoDelayedWork will still be called if DoWork returns
+ // true, but DoIdleWork will not.
virtual bool DoWork() = 0;
// Called from within Run in response to ScheduleDelayedWork or when the
@@ -61,7 +62,8 @@ class MessagePump : public RefCountedThreadSafe<MessagePump> {
// if (should_quit_)
// break;
//
- // did_work |= delegate_->DoDelayedWork();
+ // TimeTicks next_time;
+ // did_work |= delegate_->DoDelayedWork(&next_time);
// if (should_quit_)
// break;
//
@@ -84,9 +86,9 @@ class MessagePump : public RefCountedThreadSafe<MessagePump> {
// blocks until there is more work of any type to do.
//
// Notice that the run loop cycles between calling DoInternalWork, DoWork,
- // and DoDelayedWork methods. This helps ensure that neither work queue
- // starves the other. This is important for message pumps that are used to
- // drive animations, for example.
+ // and DoDelayedWork methods. This helps ensure that none of these work
+ // queues starve the others. This is important for message pumps that are
+ // used to drive animations, for example.
//
// Notice also that after each callout to foreign code, the run loop checks
// to see if it should quit. The Quit method is responsible for setting this
diff --git a/base/message_pump_glib_x.cc b/base/message_pump_glib_x.cc
index e27a07a..06a156e 100644
--- a/base/message_pump_glib_x.cc
+++ b/base/message_pump_glib_x.cc
@@ -32,6 +32,11 @@ gboolean GtkWidgetRealizeCallback(GSignalInvocationHint* hint, guint nparams,
DCHECK(window); // TODO(sad): Remove once determined if necessary.
+ if (GDK_WINDOW_TYPE(window) != GDK_WINDOW_TOPLEVEL &&
+ GDK_WINDOW_TYPE(window) != GDK_WINDOW_CHILD &&
+ GDK_WINDOW_TYPE(window) != GDK_WINDOW_DIALOG)
+ return true;
+
// TODO(sad): Do we need to set a flag on |window| to make sure we don't
// select for the same GdkWindow multiple times? Does it matter?
msgpump->SetupXInput2ForXWindow(GDK_WINDOW_XID(window));
@@ -44,17 +49,27 @@ gboolean GtkWidgetRealizeCallback(GSignalInvocationHint* hint, guint nparams,
// signal for GTK+ widgets, so that whenever the signal triggers for any
// GtkWidget, which means the GtkWidget should now have a GdkWindow, we can
// setup XInput2 events for the GdkWindow.
+static guint realize_signal_id = 0;
+static guint realize_hook_id = 0;
+
void SetupGtkWidgetRealizeNotifier(base::MessagePumpGlibX* msgpump) {
- guint signal_id;
gpointer klass = g_type_class_ref(GTK_TYPE_WIDGET);
- g_signal_parse_name("realize", GTK_TYPE_WIDGET, &signal_id, NULL, FALSE);
- g_signal_add_emission_hook(signal_id, 0, GtkWidgetRealizeCallback,
- static_cast<gpointer>(msgpump), NULL);
+ g_signal_parse_name("realize", GTK_TYPE_WIDGET,
+ &realize_signal_id, NULL, FALSE);
+ realize_hook_id = g_signal_add_emission_hook(realize_signal_id, 0,
+ GtkWidgetRealizeCallback, static_cast<gpointer>(msgpump), NULL);
g_type_class_unref(klass);
}
+void RemoveGtkWidgetRealizeNotifier() {
+ if (realize_signal_id != 0)
+ g_signal_remove_emission_hook(realize_signal_id, realize_hook_id);
+ realize_signal_id = 0;
+ realize_hook_id = 0;
+}
+
#endif // HAVE_XINPUT2
} // namespace
@@ -80,6 +95,9 @@ MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(),
}
MessagePumpGlibX::~MessagePumpGlibX() {
+#if defined(HAVE_XINPUT2)
+ RemoveGtkWidgetRealizeNotifier();
+#endif
}
#if defined(HAVE_XINPUT2)
@@ -119,7 +137,7 @@ void MessagePumpGlibX::SetupXInput2ForXWindow(Window xwindow) {
bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) {
GdkDisplay* gdisp = gdk_display_get_default();
- if (!gdisp)
+ if (!gdisp || !GetDispatcher())
return MessagePumpForUI::RunOnce(context, block);
Display* display = GDK_DISPLAY_XDISPLAY(gdisp);
diff --git a/base/message_pump_libevent.cc b/base/message_pump_libevent.cc
index 933d795..28b4bfe 100644
--- a/base/message_pump_libevent.cc
+++ b/base/message_pump_libevent.cc
@@ -78,7 +78,7 @@ bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e,
bool is_persistent) {
DCHECK(e);
- DCHECK(event_ == NULL);
+ DCHECK(!event_);
is_persistent_ = is_persistent;
event_ = e;
diff --git a/base/message_pump_mac.h b/base/message_pump_mac.h
index c30a8ea..b903a1a 100644
--- a/base/message_pump_mac.h
+++ b/base/message_pump_mac.h
@@ -86,24 +86,17 @@ class MessagePumpCFRunLoopBase : public MessagePump {
private:
// Timer callback scheduled by ScheduleDelayedWork. This does not do any
- // work, but it signals delayed_work_source_ so that delayed work can be
- // performed within the appropriate priority constraints.
+ // work, but it signals work_source_ so that delayed work can be performed
+ // within the appropriate priority constraints.
static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info);
// Perform highest-priority work. This is associated with work_source_
- // signalled by ScheduleWork. The static method calls the instance method;
- // the instance method returns true if work was done.
+ // signalled by ScheduleWork or RunDelayedWorkTimer. The static method calls
+ // the instance method; the instance method returns true if it resignalled
+ // work_source_ to be called again from the loop.
static void RunWorkSource(void* info);
bool RunWork();
- // Perform delayed-priority work. This is associated with
- // delayed_work_source_ signalled by RunDelayedWorkTimer, and is responsible
- // for calling ScheduleDelayedWork again if appropriate. The static method
- // calls the instance method; the instance method returns true if more
- // delayed work is available.
- static void RunDelayedWorkSource(void* info);
- bool RunDelayedWork();
-
// Perform idle-priority work. This is normally called by PreWaitObserver,
// but is also associated with idle_work_source_. When this function
// actually does perform idle work, it will resignal that source. The
@@ -162,7 +155,6 @@ class MessagePumpCFRunLoopBase : public MessagePump {
// callbacks.
CFRunLoopTimerRef delayed_work_timer_;
CFRunLoopSourceRef work_source_;
- CFRunLoopSourceRef delayed_work_source_;
CFRunLoopSourceRef idle_work_source_;
CFRunLoopSourceRef nesting_deferred_work_source_;
CFRunLoopObserverRef pre_wait_observer_;
@@ -202,7 +194,6 @@ class MessagePumpCFRunLoopBase : public MessagePump {
// any call to Run on the stack. The Run method will check for delegateless
// work on entry and redispatch it as needed once a delegate is available.
bool delegateless_work_;
- bool delegateless_delayed_work_;
bool delegateless_idle_work_;
DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
diff --git a/base/message_pump_mac.mm b/base/message_pump_mac.mm
index 8c5461c..8feb56f 100644
--- a/base/message_pump_mac.mm
+++ b/base/message_pump_mac.mm
@@ -51,7 +51,6 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
run_nesting_level_(0),
deepest_nesting_level_(0),
delegateless_work_(false),
- delegateless_delayed_work_(false),
delegateless_idle_work_(false) {
run_loop_ = CFRunLoopGetCurrent();
CFRetain(run_loop_);
@@ -78,15 +77,9 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
&source_context);
CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes);
- source_context.perform = RunDelayedWorkSource;
- delayed_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
- 2, // priority
- &source_context);
- CFRunLoopAddSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
-
source_context.perform = RunIdleWorkSource;
idle_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
- 3, // priority
+ 2, // priority
&source_context);
CFRunLoopAddSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
@@ -169,9 +162,6 @@ MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
CFRelease(idle_work_source_);
- CFRunLoopRemoveSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
- CFRelease(delayed_work_source_);
-
CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes);
CFRelease(work_source_);
@@ -199,10 +189,6 @@ void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
CFRunLoopSourceSignal(work_source_);
delegateless_work_ = false;
}
- if (delegateless_delayed_work_) {
- CFRunLoopSourceSignal(delayed_work_source_);
- delegateless_delayed_work_ = false;
- }
if (delegateless_idle_work_) {
CFRunLoopSourceSignal(idle_work_source_);
delegateless_idle_work_ = false;
@@ -260,11 +246,10 @@ void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
self->delayed_work_fire_time_ = kCFTimeIntervalMax;
// CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources.
- // In order to establish the proper priority where delegate_->DoDelayedWork
- // can only be called if delegate_->DoWork returns false, the timer used
- // to schedule delayed work must signal a CFRunLoopSource set at a lower
- // priority than the one used for delegate_->DoWork.
- CFRunLoopSourceSignal(self->delayed_work_source_);
+ // In order to establish the proper priority in which work and delayed work
+ // are processed one for one, the timer used to schedule delayed work must
+ // signal a CFRunLoopSource used to dispatch both work and delayed work.
+ CFRunLoopSourceSignal(self->work_source_);
}
// Called from the run loop.
@@ -291,58 +276,39 @@ bool MessagePumpCFRunLoopBase::RunWork() {
// released promptly even in the absence of UI events.
MessagePumpScopedAutoreleasePool autorelease_pool(this);
- // Call DoWork once, and if something was done, arrange to come back here
- // again as long as the loop is still running.
+ // Call DoWork and DoDelayedWork once, and if something was done, arrange to
+ // come back here again as long as the loop is still running.
bool did_work = delegate_->DoWork();
- if (did_work) {
- CFRunLoopSourceSignal(work_source_);
- }
-
- return did_work;
-}
-
-// Called from the run loop.
-// static
-void MessagePumpCFRunLoopBase::RunDelayedWorkSource(void* info) {
- MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
- self->RunDelayedWork();
-}
-
-// Called by MessagePumpCFRunLoopBase::RunDelayedWorkSource.
-bool MessagePumpCFRunLoopBase::RunDelayedWork() {
- if (!delegate_) {
- // This point can be reached with a NULL delegate_ if Run is not on the
- // stack but foreign code is spinning the CFRunLoop. Arrange to come back
- // here when a delegate is available.
- delegateless_delayed_work_ = true;
- return false;
- }
-
- // The NSApplication-based run loop only drains the autorelease pool at each
- // UI event (NSEvent). The autorelease pool is not drained for each
- // CFRunLoopSource target that's run. Use a local pool for any autoreleased
- // objects if the app is not currently handling a UI event to ensure they're
- // released promptly even in the absence of UI events.
- MessagePumpScopedAutoreleasePool autorelease_pool(this);
+ bool resignal_work_source = did_work;
TimeTicks next_time;
delegate_->DoDelayedWork(&next_time);
-
- bool more_work = !next_time.is_null();
- if (more_work) {
- TimeDelta delay = next_time - TimeTicks::Now();
- if (delay > TimeDelta()) {
- // There's more delayed work to be done in the future.
- ScheduleDelayedWork(next_time);
- } else {
- // There's more delayed work to be done, and its time is in the past.
- // Arrange to come back here directly as long as the loop is still
- // running.
- CFRunLoopSourceSignal(delayed_work_source_);
+ if (!did_work) {
+ // Determine whether there's more delayed work, and if so, if it needs to
+ // be done at some point in the future or if it's already time to do it.
+ // Only do these checks if did_work is false. If did_work is true, this
+ // function, and therefore any additional delayed work, will get another
+ // chance to run before the loop goes to sleep.
+ bool more_delayed_work = !next_time.is_null();
+ if (more_delayed_work) {
+ TimeDelta delay = next_time - TimeTicks::Now();
+ if (delay > TimeDelta()) {
+ // There's more delayed work to be done in the future.
+ ScheduleDelayedWork(next_time);
+ } else {
+ // There's more delayed work to be done, and its time is in the past.
+ // Arrange to come back here directly as long as the loop is still
+ // running.
+ resignal_work_source = true;
+ }
}
}
- return more_work;
+ if (resignal_work_source) {
+ CFRunLoopSourceSignal(work_source_);
+ }
+
+ return resignal_work_source;
}
// Called from the run loop.
@@ -398,19 +364,12 @@ bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() {
// Immediately try work in priority order.
if (!RunWork()) {
- if (!RunDelayedWork()) {
- if (!RunIdleWork()) {
- return false;
- }
- } else {
- // There was no work, and delayed work was done. Arrange for the loop
- // to try non-nestable idle work on a subsequent pass.
- CFRunLoopSourceSignal(idle_work_source_);
+ if (!RunIdleWork()) {
+ return false;
}
} else {
- // Work was done. Arrange for the loop to try non-nestable delayed and
- // idle work on a subsequent pass.
- CFRunLoopSourceSignal(delayed_work_source_);
+ // Work was done. Arrange for the loop to try non-nestable idle work on
+ // a subsequent pass.
CFRunLoopSourceSignal(idle_work_source_);
}
@@ -672,6 +631,13 @@ MessagePumpNSApplication::MessagePumpNSApplication()
void MessagePumpNSApplication::DoRun(Delegate* delegate) {
bool last_running_own_loop_ = running_own_loop_;
+ // NSApp must be initialized by calling:
+ // [{some class which implements CrAppProtocol} sharedApplication]
+ // Most likely candidates are CrApplication or BrowserCrApplication.
+ // These can be initialized from C++ code by calling
+ // RegisterCrApp() or RegisterBrowserCrApp().
+ CHECK(NSApp);
+
if (![NSApp isRunning]) {
running_own_loop_ = false;
// NSApplication manages autorelease pools itself when run this way.
diff --git a/base/message_pump_win.cc b/base/message_pump_win.cc
index d3f3621..6098a4a 100644
--- a/base/message_pump_win.cc
+++ b/base/message_pump_win.cc
@@ -470,7 +470,7 @@ void MessagePumpForIO::DoRunLoop() {
void MessagePumpForIO::WaitForWork() {
// We do not support nested IO message loops. This is to avoid messy
// recursion problems.
- DCHECK(state_->run_depth == 1) << "Cannot nest an IO message loop!";
+ DCHECK_EQ(1, state_->run_depth) << "Cannot nest an IO message loop!";
int timeout = GetCurrentDelay();
if (timeout < 0) // Negative value means no timers waiting.
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index fceccde..c1416db 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -41,6 +41,7 @@ FieldTrial::FieldTrial(const std::string& name,
accumulated_group_probability_(0),
next_group_number_(kDefaultGroupNumber+1),
group_(kNotFinalized) {
+ DCHECK_GT(total_probability, 0);
DCHECK(!default_group_name_.empty());
FieldTrialList::Register(this);
@@ -53,7 +54,7 @@ FieldTrial::FieldTrial(const std::string& name,
base::Time::Exploded exploded;
exploded.year = year;
exploded.month = month;
- exploded.day_of_week = 0; // Should be unusued.
+ exploded.day_of_week = 0; // Should be unused.
exploded.day_of_month = day_of_month;
exploded.hour = 0;
exploded.minute = 0;
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index ec3a483..8b4a606 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -101,6 +101,7 @@ class FieldTrial : public RefCounted<FieldTrial> {
// Establish the name and probability of the next group in this trial.
// Sometimes, based on construction randomization, this call may cause the
// provided group to be *THE* group selected for use in this instance.
+ // The return value is the group number of the new group.
int AppendGroup(const std::string& name, Probability group_probability);
// Return the name of the FieldTrial (excluding the group name).
@@ -167,7 +168,7 @@ class FieldTrial : public RefCounted<FieldTrial> {
// The randomly selected probability that is used to select a group (or have
// the instance not participate). It is the product of divisor_ and a random
// number between [0, 1).
- Probability random_;
+ const Probability random_;
// Sum of the probabilities of all appended groups.
Probability accumulated_group_probability_;
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index a308932..1d6f884 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -21,8 +21,58 @@
namespace base {
+// Static table of checksums for all possible 8 bit bytes.
+const uint32 Histogram::kCrcTable[256] = {0x0, 0x77073096L, 0xee0e612cL,
+0x990951baL, 0x76dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L,
+0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL,
+0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL,
+0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L,
+0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL,
+0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L,
+0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL,
+0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL,
+0xb6662d3dL, 0x76dc4190L, 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L,
+0x6b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL,
+0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L,
+0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L,
+0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL,
+0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L,
+0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL,
+0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L,
+0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L,
+0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L,
+0x9abfb3b6L, 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L,
+0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL,
+0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L,
+0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L,
+0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L,
+0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L,
+0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL,
+0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L,
+0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L,
+0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, 0x95bf4a82L,
+0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L,
+0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL,
+0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL,
+0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL,
+0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L,
+0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L,
+0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL,
+0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+0x2d02ef8dL,
+};
+
typedef Histogram::Count Count;
+// static
+const size_t Histogram::kBucketCount_MAX = 16384u;
+
scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name,
Sample minimum, Sample maximum, size_t bucket_count, Flags flags) {
scoped_refptr<Histogram> histogram(NULL);
@@ -35,7 +85,8 @@ scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name,
if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
histogram = new Histogram(name, minimum, maximum, bucket_count);
- StatisticsRecorder::FindHistogram(name, &histogram);
+ histogram->InitializeBucketRange();
+ StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
}
DCHECK_EQ(HISTOGRAM, histogram->histogram_type());
@@ -158,7 +209,7 @@ std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
pickle.WriteInt(histogram.declared_min());
pickle.WriteInt(histogram.declared_max());
pickle.WriteSize(histogram.bucket_count());
- pickle.WriteInt(histogram.range_checksum());
+ pickle.WriteUInt32(histogram.range_checksum());
pickle.WriteInt(histogram.histogram_type());
pickle.WriteInt(histogram.flags());
@@ -178,7 +229,7 @@ bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
int declared_min;
int declared_max;
size_t bucket_count;
- int range_checksum;
+ uint32 range_checksum;
int histogram_type;
int pickle_flags;
SampleSet sample;
@@ -188,7 +239,7 @@ bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
!pickle.ReadInt(&iter, &declared_min) ||
!pickle.ReadInt(&iter, &declared_max) ||
!pickle.ReadSize(&iter, &bucket_count) ||
- !pickle.ReadInt(&iter, &range_checksum) ||
+ !pickle.ReadUInt32(&iter, &range_checksum) ||
!pickle.ReadInt(&iter, &histogram_type) ||
!pickle.ReadInt(&iter, &pickle_flags) ||
!sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
@@ -249,18 +300,16 @@ Histogram::Inconsistencies Histogram::FindCorruption(
const SampleSet& snapshot) const {
int inconsistencies = NO_INCONSISTENCIES;
Sample previous_range = -1; // Bottom range is always 0.
- Sample checksum = 0;
int64 count = 0;
for (size_t index = 0; index < bucket_count(); ++index) {
count += snapshot.counts(index);
int new_range = ranges(index);
- checksum += new_range;
if (previous_range >= new_range)
inconsistencies |= BUCKET_ORDER_ERROR;
previous_range = new_range;
}
- if (checksum != range_checksum_)
+ if (!HasValidRangeChecksum())
inconsistencies |= RANGE_CHECKSUM_ERROR;
int64 delta64 = snapshot.redundant_count() - count;
@@ -325,6 +374,10 @@ bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum,
(bucket_count == bucket_count_));
}
+bool Histogram::HasValidRangeChecksum() const {
+ return CalculateRangeChecksum() == range_checksum_;
+}
+
Histogram::Histogram(const std::string& name, Sample minimum,
Sample maximum, size_t bucket_count)
: histogram_name_(name),
@@ -360,11 +413,6 @@ Histogram::~Histogram() {
// Just to make sure most derived class did this properly...
DCHECK(ValidateBucketRanges());
- DCHECK(HasValidRangeChecksum());
-}
-
-bool Histogram::PrintEmptyBucket(size_t index) const {
- return true;
}
// Calculate what range of values are held in each bucket.
@@ -402,6 +450,10 @@ void Histogram::InitializeBucketRange() {
DCHECK_EQ(bucket_count(), bucket_index);
}
+bool Histogram::PrintEmptyBucket(size_t index) const {
+ return true;
+}
+
size_t Histogram::BucketIndex(Sample value) const {
// Use simple binary search. This is very general, but there are better
// approaches if we knew that the buckets were linearly distributed.
@@ -413,7 +465,7 @@ size_t Histogram::BucketIndex(Sample value) const {
do {
DCHECK_GE(over, under);
- mid = (over + under)/2;
+ mid = under + (over - under)/2;
if (mid == under)
break;
if (ranges(mid) <= value)
@@ -423,7 +475,7 @@ size_t Histogram::BucketIndex(Sample value) const {
} while (true);
DCHECK_LE(ranges(mid), value);
- DCHECK_GT(ranges(mid+1), value);
+ CHECK_GT(ranges(mid+1), value);
return mid;
}
@@ -475,6 +527,14 @@ bool Histogram::ValidateBucketRanges() const {
return true;
}
+uint32 Histogram::CalculateRangeChecksum() const {
+ DCHECK_EQ(ranges_.size(), bucket_count() + 1);
+ uint32 checksum = static_cast<uint32>(ranges_.size()); // Seed checksum.
+ for (size_t index = 0; index < bucket_count(); ++index)
+ checksum = Crc32(checksum, ranges(index));
+ return checksum;
+}
+
void Histogram::Initialize() {
sample_.Resize(*this);
if (declared_min_ < 1)
@@ -483,26 +543,47 @@ void Histogram::Initialize() {
declared_max_ = kSampleType_MAX - 1;
DCHECK_LE(declared_min_, declared_max_);
DCHECK_GT(bucket_count_, 1u);
+ CHECK_LT(bucket_count_, kBucketCount_MAX);
size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
DCHECK_LE(bucket_count_, maximal_bucket_count);
DCHECK_EQ(0, ranges_[0]);
ranges_[bucket_count_] = kSampleType_MAX;
- InitializeBucketRange();
- DCHECK(ValidateBucketRanges());
- StatisticsRecorder::Register(this);
}
-bool Histogram::HasValidRangeChecksum() const {
- return CalculateRangeChecksum() == range_checksum_;
-}
-
-Histogram::Sample Histogram::CalculateRangeChecksum() const {
- DCHECK_EQ(ranges_.size(), bucket_count() + 1);
- Sample checksum = 0;
- for (size_t index = 0; index < bucket_count(); ++index) {
- checksum += ranges(index);
+// We generate the CRC-32 using the low order bits to select whether to XOR in
+// the reversed polynomial 0xedb88320L. This is nice and simple, and allows us
+// to keep the quotient in a uint32. Since we're not concerned about the nature
+// of corruptions (i.e., we don't care about bit sequencing, since we are
+// handling memory changes, which are more grotesque) so we don't bother to
+// get the CRC correct for big-endian vs little-ending calculations. All we
+// need is a nice hash, that tends to depend on all the bits of the sample, with
+// very little chance of changes in one place impacting changes in another
+// place.
+uint32 Histogram::Crc32(uint32 sum, Histogram::Sample range) {
+ const bool kUseRealCrc = true; // TODO(jar): Switch to false and watch stats.
+ if (kUseRealCrc) {
+ union {
+ Histogram::Sample range;
+ unsigned char bytes[sizeof(Histogram::Sample)];
+ } converter;
+ converter.range = range;
+ for (size_t i = 0; i < sizeof(converter); ++i)
+ sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8);
+ } else {
+ // Use hash techniques provided in ReallyFastHash, except we don't care
+ // about "avalanching" (which would worsten the hash, and add collisions),
+ // and we don't care about edge cases since we have an even number of bytes.
+ union {
+ Histogram::Sample range;
+ uint16 ints[sizeof(Histogram::Sample) / 2];
+ } converter;
+ DCHECK_EQ(sizeof(Histogram::Sample), sizeof(converter));
+ converter.range = range;
+ sum += converter.ints[0];
+ sum = (sum << 16) ^ sum ^ (static_cast<uint32>(converter.ints[1]) << 11);
+ sum += sum >> 11;
}
- return checksum;
+ return sum;
}
//------------------------------------------------------------------------------
@@ -706,8 +787,11 @@ scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
maximum = kSampleType_MAX - 1;
if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
- histogram = new LinearHistogram(name, minimum, maximum, bucket_count);
- StatisticsRecorder::FindHistogram(name, &histogram);
+ LinearHistogram* linear_histogram =
+ new LinearHistogram(name, minimum, maximum, bucket_count);
+ linear_histogram->InitializeBucketRange();
+ histogram = linear_histogram;
+ StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
}
DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type());
@@ -742,8 +826,6 @@ LinearHistogram::LinearHistogram(const std::string& name,
Sample maximum,
size_t bucket_count)
: Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) {
- InitializeBucketRange();
- DCHECK(ValidateBucketRanges());
}
LinearHistogram::LinearHistogram(const std::string& name,
@@ -753,9 +835,6 @@ LinearHistogram::LinearHistogram(const std::string& name,
: Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ?
minimum : TimeDelta::FromMilliseconds(1),
maximum, bucket_count) {
- // Do a "better" (different) job at init than a base classes did...
- InitializeBucketRange();
- DCHECK(ValidateBucketRanges());
}
void LinearHistogram::InitializeBucketRange() {
@@ -801,8 +880,10 @@ scoped_refptr<Histogram> BooleanHistogram::FactoryGet(const std::string& name,
scoped_refptr<Histogram> histogram(NULL);
if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
- histogram = new BooleanHistogram(name);
- StatisticsRecorder::FindHistogram(name, &histogram);
+ BooleanHistogram* boolean_histogram = new BooleanHistogram(name);
+ boolean_histogram->InitializeBucketRange();
+ histogram = boolean_histogram;
+ StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
}
DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type());
@@ -846,8 +927,10 @@ scoped_refptr<Histogram> CustomHistogram::FactoryGet(
DCHECK_LT(ranges.back(), kSampleType_MAX);
if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
- histogram = new CustomHistogram(name, ranges);
- StatisticsRecorder::FindHistogram(name, &histogram);
+ CustomHistogram* custom_histogram = new CustomHistogram(name, ranges);
+ custom_histogram->InitializedCustomBucketRange(ranges);
+ histogram = custom_histogram;
+ StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
}
DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM);
@@ -867,16 +950,15 @@ CustomHistogram::CustomHistogram(const std::string& name,
custom_ranges.size()) {
DCHECK_GT(custom_ranges.size(), 1u);
DCHECK_EQ(custom_ranges[0], 0);
- ranges_vector_ = &custom_ranges;
- InitializeBucketRange();
- ranges_vector_ = NULL;
- DCHECK(ValidateBucketRanges());
}
-void CustomHistogram::InitializeBucketRange() {
- DCHECK_LE(ranges_vector_->size(), bucket_count());
- for (size_t index = 0; index < ranges_vector_->size(); ++index)
- SetBucketRange(index, (*ranges_vector_)[index]);
+void CustomHistogram::InitializedCustomBucketRange(
+ const std::vector<Sample>& custom_ranges) {
+ DCHECK_GT(custom_ranges.size(), 1u);
+ DCHECK_EQ(custom_ranges[0], 0);
+ DCHECK_LE(custom_ranges.size(), bucket_count());
+ for (size_t index = 0; index < custom_ranges.size(); ++index)
+ SetBucketRange(index, custom_ranges[index]);
ResetRangeChecksum();
}
@@ -941,16 +1023,21 @@ bool StatisticsRecorder::IsActive() {
// was passed to us, decremented it when we returned, and the instance would be
// destroyed before assignment (when value was returned by new).
// static
-void StatisticsRecorder::Register(Histogram* histogram) {
+void StatisticsRecorder::RegisterOrDiscardDuplicate(
+ scoped_refptr<Histogram>* histogram) {
+ DCHECK((*histogram)->HasValidRangeChecksum());
if (lock_ == NULL)
return;
base::AutoLock auto_lock(*lock_);
if (!histograms_)
return;
- const std::string name = histogram->histogram_name();
+ const std::string name = (*histogram)->histogram_name();
+ HistogramMap::iterator it = histograms_->find(name);
// Avoid overwriting a previous registration.
- if (histograms_->end() == histograms_->find(name))
- (*histograms_)[name] = histogram;
+ if (histograms_->end() == it)
+ (*histograms_)[name] = *histogram;
+ else
+ *histogram = it->second;
}
// static
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 3bb3f03..347932a 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -241,6 +241,8 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
typedef int Sample; // Used for samples (and ranges of samples).
typedef int Count; // Used to count samples in a bucket.
static const Sample kSampleType_MAX = INT_MAX;
+ // Initialize maximum number of buckets in histograms as 16,384.
+ static const size_t kBucketCount_MAX;
typedef std::vector<Count> Counts;
typedef std::vector<Sample> Ranges;
@@ -409,7 +411,7 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
Sample declared_min() const { return declared_min_; }
Sample declared_max() const { return declared_max_; }
virtual Sample ranges(size_t i) const;
- Sample range_checksum() const { return range_checksum_; }
+ uint32 range_checksum() const { return range_checksum_; }
virtual size_t bucket_count() const;
// Snapshot the current complete set of sample data.
// Override with atomic/locked snapshot if needed.
@@ -421,6 +423,8 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count);
+ // Return true iff the range_checksum_ matches current ranges_ vector.
+ bool HasValidRangeChecksum() const;
protected:
friend class base::RefCountedThreadSafe<Histogram>;
@@ -431,14 +435,15 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
virtual ~Histogram();
+ // Initialize ranges_ mapping.
+ void InitializeBucketRange();
+
// Method to override to skip the display of the i'th bucket if it's empty.
virtual bool PrintEmptyBucket(size_t index) const;
//----------------------------------------------------------------------------
// Methods to override to create histogram with different bucket widths.
//----------------------------------------------------------------------------
- // Initialize ranges_ mapping.
- virtual void InitializeBucketRange();
// Find bucket to increment for sample value.
virtual size_t BucketIndex(Sample value) const;
// Get normalized size, relative to the ranges_[i].
@@ -467,18 +472,20 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
// values relate properly to the declared_min_ and declared_max_)..
bool ValidateBucketRanges() const;
+ virtual uint32 CalculateRangeChecksum() const;
+
private:
// Allow tests to corrupt our innards for testing purposes.
FRIEND_TEST(HistogramTest, CorruptBucketBounds);
FRIEND_TEST(HistogramTest, CorruptSampleCounts);
+ FRIEND_TEST(HistogramTest, Crc32SampleHash);
+ FRIEND_TEST(HistogramTest, Crc32TableTest);
// Post constructor initialization.
void Initialize();
- // Return true iff the range_checksum_ matches current ranges_ vector.
- bool HasValidRangeChecksum() const;
-
- Sample CalculateRangeChecksum() const;
+ // Checksum function for accumulating range values into a checksum.
+ static uint32 Crc32(uint32 sum, Sample range);
//----------------------------------------------------------------------------
// Helpers for emitting Ascii graphic. Each method appends data to output.
@@ -506,6 +513,9 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
std::string* output) const;
//----------------------------------------------------------------------------
+ // Table for generating Crc32 values.
+ static const uint32 kCrcTable[256];
+ //----------------------------------------------------------------------------
// Invariant values set at/near construction time
// ASCII version of original name given to the constructor. All identically
@@ -524,10 +534,10 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
// The dimension of ranges_ is bucket_count + 1.
Ranges ranges_;
- // For redundancy, we store the sum of all the sample ranges when ranges are
- // generated. If ever there is ever a difference, then the histogram must
+ // For redundancy, we store a checksum of all the sample ranges when ranges
+ // are generated. If ever there is ever a difference, then the histogram must
// have been corrupted.
- Sample range_checksum_;
+ uint32 range_checksum_;
// Finally, provide the state that changes with the addition of each new
// sample.
@@ -567,7 +577,7 @@ class LinearHistogram : public Histogram {
TimeDelta maximum, size_t bucket_count);
// Initialize ranges_ mapping.
- virtual void InitializeBucketRange();
+ void InitializeBucketRange();
virtual double GetBucketSize(Count current, size_t i) const;
// If we have a description for a bucket, then return that. Otherwise
@@ -623,13 +633,9 @@ class CustomHistogram : public Histogram {
const std::vector<Sample>& custom_ranges);
// Initialize ranges_ mapping.
- virtual void InitializeBucketRange();
+ void InitializedCustomBucketRange(const std::vector<Sample>& custom_ranges);
virtual double GetBucketSize(Count current, size_t i) const;
- private:
- // Temporary pointer used during construction/initialization, and then NULLed.
- const std::vector<Sample>* ranges_vector_;
-
DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
};
@@ -649,8 +655,11 @@ class StatisticsRecorder {
// Find out if histograms can now be registered into our list.
static bool IsActive();
- // Register, or add a new histogram to the collection of statistics.
- static void Register(Histogram* histogram);
+ // Register, or add a new histogram to the collection of statistics. If an
+ // identically named histogram is already registered, then the argument
+ // |histogram| will be replaced by the previously registered value, discarding
+ // the referenced argument.
+ static void RegisterOrDiscardDuplicate(scoped_refptr<Histogram>* histogram);
// Methods for printing histograms. Only histograms which have query as
// a substring are written to output (an empty string will process all
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index b9c51ad..afa69a6 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -348,7 +348,8 @@ TEST(HistogramTest, CorruptBucketBounds) {
EXPECT_EQ(0, histogram->FindCorruption(snapshot)); // No default corruption.
std::swap(histogram->ranges_[1], histogram->ranges_[2]);
- EXPECT_EQ(Histogram::BUCKET_ORDER_ERROR, histogram->FindCorruption(snapshot));
+ EXPECT_EQ(Histogram::BUCKET_ORDER_ERROR | Histogram::RANGE_CHECKSUM_ERROR,
+ histogram->FindCorruption(snapshot));
std::swap(histogram->ranges_[1], histogram->ranges_[2]);
EXPECT_EQ(0, histogram->FindCorruption(snapshot));
@@ -357,8 +358,30 @@ TEST(HistogramTest, CorruptBucketBounds) {
EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR,
histogram->FindCorruption(snapshot));
+ // Show that two simple changes don't offset each other
+ --histogram->ranges_[4];
+ EXPECT_EQ(Histogram::RANGE_CHECKSUM_ERROR,
+ histogram->FindCorruption(snapshot));
+
// Repair histogram so that destructor won't DCHECK().
--histogram->ranges_[3];
+ ++histogram->ranges_[4];
+}
+
+// Table was generated similarly to sample code for CRC-32 given on:
+// http://www.w3.org/TR/PNG/#D-CRCAppendix.
+TEST(HistogramTest, Crc32TableTest) {
+ for (int i = 0; i < 256; ++i) {
+ uint32 checksum = i;
+ for (int j = 0; j < 8; ++j) {
+ const uint32 kReversedPolynomial = 0xedb88320L;
+ if (checksum & 1)
+ checksum = kReversedPolynomial ^ (checksum >> 1);
+ else
+ checksum >>= 1;
+ }
+ EXPECT_EQ(Histogram::kCrcTable[i], checksum);
+ }
}
} // namespace base
diff --git a/base/mime_util_xdg.cc b/base/mime_util_xdg.cc
index 5215d01..4dd7a3e 100644
--- a/base/mime_util_xdg.cc
+++ b/base/mime_util_xdg.cc
@@ -525,7 +525,7 @@ FilePath LookupIconInDefaultTheme(const std::string& icon_name, int size) {
EnsureUpdated();
MimeUtilConstants* constants = MimeUtilConstants::GetInstance();
std::map<std::string, IconTheme*>* icon_themes = constants->icon_themes_;
- if (icon_themes->size() == 0)
+ if (icon_themes->empty())
InitDefaultThemes();
FilePath icon_path;
diff --git a/base/pickle.cc b/base/pickle.cc
index e7d5768..116d3f1 100644
--- a/base/pickle.cc
+++ b/base/pickle.cc
@@ -157,6 +157,20 @@ bool Pickle::ReadSize(void** iter, size_t* result) const {
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)
diff --git a/base/pickle.h b/base/pickle.h
index ad08b7c..9d449ae 100644
--- a/base/pickle.h
+++ b/base/pickle.h
@@ -68,6 +68,7 @@ class Pickle {
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;
@@ -97,6 +98,9 @@ class Pickle {
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));
}
@@ -143,12 +147,12 @@ class Pickle {
// to the Pickle constructor.
template <class T>
T* headerT() {
- DCHECK(sizeof(T) == header_size_);
+ DCHECK_EQ(header_size_, sizeof(T));
return static_cast<T*>(header_);
}
template <class T>
const T* headerT() const {
- DCHECK(sizeof(T) == header_size_);
+ DCHECK_EQ(header_size_, sizeof(T));
return static_cast<const T*>(header_);
}
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
index 39eaa1b..51330c7 100644
--- a/base/pickle_unittest.cc
+++ b/base/pickle_unittest.cc
@@ -19,6 +19,7 @@ const char testdata[] = "AAA\0BBB\0";
const int testdatalen = arraysize(testdata) - 1;
const bool testbool1 = false;
const bool testbool2 = true;
+const uint16 testuint16 = 32123;
// checks that the result
void VerifyResult(const Pickle& pickle) {
@@ -42,6 +43,10 @@ void VerifyResult(const Pickle& pickle) {
EXPECT_TRUE(pickle.ReadBool(&iter, &outbool));
EXPECT_EQ(testbool2, outbool);
+ uint16 outuint16;
+ EXPECT_TRUE(pickle.ReadUInt16(&iter, &outuint16));
+ EXPECT_EQ(testuint16, outuint16);
+
const char* outdata;
int outdatalen;
EXPECT_TRUE(pickle.ReadData(&iter, &outdata, &outdatalen));
@@ -66,6 +71,7 @@ TEST(PickleTest, EncodeDecode) {
EXPECT_TRUE(pickle.WriteWString(testwstr));
EXPECT_TRUE(pickle.WriteBool(testbool1));
EXPECT_TRUE(pickle.WriteBool(testbool2));
+ EXPECT_TRUE(pickle.WriteUInt16(testuint16));
EXPECT_TRUE(pickle.WriteData(testdata, testdatalen));
// Over allocate BeginWriteData so we can test TrimWriteData.
diff --git a/base/platform_file_posix.cc b/base/platform_file_posix.cc
index 901c298..4e20e25 100644
--- a/base/platform_file_posix.cc
+++ b/base/platform_file_posix.cc
@@ -65,7 +65,7 @@ PlatformFile CreatePlatformFile(const FilePath& name, int flags,
open_flags |= O_TRUNC;
}
- DCHECK(O_RDONLY == 0);
+ COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
int descriptor = open(name.value().c_str(), open_flags, S_IRUSR | S_IWUSR);
diff --git a/base/process_util.h b/base/process_util.h
index a7f8496..29b08ca 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -162,9 +162,6 @@ void CloseProcessHandle(ProcessHandle process);
ProcessId GetProcId(ProcessHandle process);
#if defined(OS_LINUX)
-// Returns the ID for the parent of the given process.
-ProcessId GetParentProcessId(ProcessHandle process);
-
// Returns the path to the executable of the given process.
FilePath GetProcessExecutablePath(ProcessHandle process);
@@ -182,6 +179,9 @@ bool AdjustOOMScore(ProcessId process, int score);
#endif
#if defined(OS_POSIX)
+// Returns the ID for the parent of the given process.
+ProcessId GetParentProcessId(ProcessHandle process);
+
// Close all file descriptors, except those which are a destination in the
// given multimap. Only call this function in a child process where you know
// that there aren't any other threads.
@@ -359,7 +359,7 @@ bool KillProcessById(ProcessId process_id, int exit_code, bool wait);
// will no longer be available).
TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code);
-// Waits for process to exit. In POSIX systems, if the process hasn't been
+// Waits for process to exit. On POSIX systems, if the process hasn't been
// signaled then puts the exit code in |exit_code|; otherwise it's considered
// a failure. On Windows |exit_code| is always filled. Returns true on success,
// and closes |handle| in any case.
@@ -382,9 +382,9 @@ bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
const ProcessFilter* filter);
// Wait for a single process to exit. Return true if it exited cleanly within
-// the given time limit.
-bool WaitForSingleProcess(ProcessHandle handle,
- int64 wait_milliseconds);
+// the given time limit. On Linux |handle| must be a child process, however
+// on Mac and Windows it can be any process.
+bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds);
// Returns true when |wait_milliseconds| have elapsed and the process
// is still running.
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index aa0f14d..39eabac 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -124,13 +124,13 @@ bool ProcessIterator::CheckForNextProcess() {
// Find out what size buffer we need.
size_t data_len = 0;
if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
- LOG(ERROR) << "failed to figure out the buffer size for a commandline";
+ DVPLOG(1) << "failed to figure out the buffer size for a commandline";
continue;
}
data.resize(data_len);
if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
- LOG(ERROR) << "failed to fetch a commandline";
+ DVPLOG(1) << "failed to fetch a commandline";
continue;
}
@@ -880,4 +880,17 @@ void EnableTerminationOnOutOfMemory() {
reinterpret_cast<IMP>(oom_killer_allocWithZone));
}
+ProcessId GetParentProcessId(ProcessHandle process) {
+ struct kinfo_proc info;
+ size_t length = sizeof(struct kinfo_proc);
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process };
+ if (sysctl(mib, 4, &info, &length, NULL, 0) < 0) {
+ PLOG(ERROR) << "sysctl";
+ return -1;
+ }
+ if (length == 0)
+ return -1;
+ return info.kp_eproc.e_ppid;
+}
+
} // namespace base
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index ce19bc6..ce56625 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -32,6 +32,7 @@
#if defined(OS_MACOSX)
#include <crt_externs.h>
+#include <sys/event.h>
#define environ (*_NSGetEnviron())
#else
extern char** environ;
@@ -404,7 +405,7 @@ char** AlterEnvironment(const environment_vector& changes,
}
// if !found, then we have a new element to add.
- if (!found && j->second.size() > 0) {
+ if (!found && !j->second.empty()) {
count++;
size += j->first.size() + 1 /* '=' */ + j->second.size() + 1 /* NUL */;
}
@@ -455,7 +456,7 @@ char** AlterEnvironment(const environment_vector& changes,
// Now handle new elements
for (environment_vector::const_iterator
j = changes.begin(); j != changes.end(); j++) {
- if (j->second.size() == 0)
+ if (j->second.empty())
continue;
bool found = false;
@@ -501,17 +502,20 @@ bool LaunchAppImpl(
scoped_array<char*> new_environ(AlterEnvironment(env_changes, environ));
pid = fork();
- if (pid < 0)
+ if (pid < 0) {
+ PLOG(ERROR) << "fork";
return false;
-
+ }
if (pid == 0) {
// Child process
if (start_new_process_group) {
// Instead of inheriting the process group ID of the parent, the child
// starts off a new process group with pgid equal to its process ID.
- if (setpgid(0, 0) < 0)
+ if (setpgid(0, 0) < 0) {
+ PLOG(ERROR) << "setpgid";
return false;
+ }
}
#if defined(OS_MACOSX)
RestoreDefaultExceptionHandler();
@@ -718,7 +722,79 @@ bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code,
return true;
}
+#if defined(OS_MACOSX)
+// Using kqueue on Mac so that we can wait on non-child processes.
+// We can't use kqueues on child processes because we need to reap
+// our own children using wait.
+static bool WaitForSingleNonChildProcess(ProcessHandle handle,
+ int64 wait_milliseconds) {
+ int kq = kqueue();
+ if (kq == -1) {
+ PLOG(ERROR) << "kqueue";
+ return false;
+ }
+
+ struct kevent change = { 0 };
+ EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+
+ struct timespec spec;
+ struct timespec *spec_ptr;
+ if (wait_milliseconds != base::kNoTimeout) {
+ time_t sec = static_cast<time_t>(wait_milliseconds / 1000);
+ wait_milliseconds = wait_milliseconds - (sec * 1000);
+ spec.tv_sec = sec;
+ spec.tv_nsec = wait_milliseconds * 1000000L;
+ spec_ptr = &spec;
+ } else {
+ spec_ptr = NULL;
+ }
+
+ while(true) {
+ struct kevent event = { 0 };
+ int event_count = HANDLE_EINTR(kevent(kq, &change, 1, &event, 1, spec_ptr));
+ if (close(kq) != 0) {
+ PLOG(ERROR) << "close";
+ }
+ if (event_count < 0) {
+ PLOG(ERROR) << "kevent";
+ return false;
+ } else if (event_count == 0) {
+ if (wait_milliseconds != base::kNoTimeout) {
+ // Timed out.
+ return false;
+ }
+ } else if ((event_count == 1) &&
+ (handle == static_cast<pid_t>(event.ident)) &&
+ (event.filter == EVFILT_PROC)) {
+ if (event.fflags == NOTE_EXIT) {
+ return true;
+ } else if (event.flags == EV_ERROR) {
+ LOG(ERROR) << "kevent error " << event.data;
+ return false;
+ } else {
+ NOTREACHED();
+ return false;
+ }
+ } else {
+ NOTREACHED();
+ return false;
+ }
+ }
+}
+#endif // OS_MACOSX
+
bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) {
+ ProcessHandle parent_pid = GetParentProcessId(handle);
+ ProcessHandle our_pid = Process::Current().handle();
+ if (parent_pid != our_pid) {
+#if defined(OS_MACOSX)
+ // On Mac we can wait on non child processes.
+ return WaitForSingleNonChildProcess(handle, wait_milliseconds);
+#else
+ // Currently on Linux we can't handle non child processes.
+ NOTIMPLEMENTED();
+#endif // OS_MACOSX
+ }
bool waitpid_success;
int status;
if (wait_milliseconds == base::kNoTimeout)
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index 1b7368a..31e1dec 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -658,12 +658,12 @@ TEST_F(ProcessUtilTest, GetAppOutputRestrictedNoZombies) {
}
}
-#if defined(OS_LINUX)
TEST_F(ProcessUtilTest, GetParentProcessId) {
base::ProcessId ppid = base::GetParentProcessId(base::GetCurrentProcId());
EXPECT_EQ(ppid, getppid());
}
+#if defined(OS_LINUX)
TEST_F(ProcessUtilTest, ParseProcStatCPU) {
// /proc/self/stat for a process running "top".
const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 "
@@ -683,7 +683,7 @@ TEST_F(ProcessUtilTest, ParseProcStatCPU) {
EXPECT_EQ(0, base::ParseProcStatCPU(kSelfStat));
}
-#endif
+#endif // defined(OS_LINUX)
#endif // defined(OS_POSIX)
diff --git a/base/ref_counted.cc b/base/ref_counted.cc
index 54c1071..2d459ae 100644
--- a/base/ref_counted.cc
+++ b/base/ref_counted.cc
@@ -12,7 +12,7 @@ namespace base {
namespace subtle {
RefCountedBase::RefCountedBase()
- : counter_holder_(new CounterHolder)
+ : ref_count_(0)
#ifndef NDEBUG
, in_dtor_(false)
#endif
@@ -20,7 +20,6 @@ RefCountedBase::RefCountedBase()
}
RefCountedBase::~RefCountedBase() {
- delete counter_holder_;
#ifndef NDEBUG
DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
#endif
@@ -33,7 +32,7 @@ void RefCountedBase::AddRef() const {
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
- ++(counter_holder_->ref_count);
+ ++ref_count_;
}
bool RefCountedBase::Release() const {
@@ -43,7 +42,7 @@ bool RefCountedBase::Release() const {
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
- if (--(counter_holder_->ref_count) == 0) {
+ if (--ref_count_ == 0) {
#ifndef NDEBUG
in_dtor_ = true;
#endif
@@ -54,19 +53,16 @@ bool RefCountedBase::Release() const {
bool RefCountedThreadSafeBase::HasOneRef() const {
return AtomicRefCountIsOne(
- &const_cast<RefCountedThreadSafeBase*>(this)->
- counter_holder_->ref_count);
+ &const_cast<RefCountedThreadSafeBase*>(this)->ref_count_);
}
-RefCountedThreadSafeBase::RefCountedThreadSafeBase()
- : counter_holder_(new CounterHolder) {
+RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {
#ifndef NDEBUG
in_dtor_ = false;
#endif
}
RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
- delete counter_holder_;
#ifndef NDEBUG
DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
"calling Release()";
@@ -77,15 +73,15 @@ void RefCountedThreadSafeBase::AddRef() const {
#ifndef NDEBUG
DCHECK(!in_dtor_);
#endif
- AtomicRefCountInc(&counter_holder_->ref_count);
+ AtomicRefCountInc(&ref_count_);
}
bool RefCountedThreadSafeBase::Release() const {
#ifndef NDEBUG
DCHECK(!in_dtor_);
- DCHECK(!AtomicRefCountIsZero(&counter_holder_->ref_count));
+ DCHECK(!AtomicRefCountIsZero(&ref_count_));
#endif
- if (!AtomicRefCountDec(&counter_holder_->ref_count)) {
+ if (!AtomicRefCountDec(&ref_count_)) {
#ifndef NDEBUG
in_dtor_ = true;
#endif
diff --git a/base/ref_counted.h b/base/ref_counted.h
index 6a2b996..4c3aeb8 100644
--- a/base/ref_counted.h
+++ b/base/ref_counted.h
@@ -17,25 +17,19 @@ class RefCountedBase {
public:
static bool ImplementsThreadSafeReferenceCounting() { return false; }
- bool HasOneRef() const { return counter_holder_->ref_count == 1; }
+ bool HasOneRef() const { return ref_count_ == 1; }
protected:
RefCountedBase();
~RefCountedBase();
- struct CounterHolder {
- CounterHolder() : ref_count(0), weak_count(0) {}
- int ref_count;
- int weak_count; // Simulates weak pointer.
- };
-
void AddRef() const;
// Returns true if the object should self-delete.
bool Release() const;
private:
- mutable CounterHolder* counter_holder_;
+ mutable int ref_count_;
#ifndef NDEBUG
mutable bool in_dtor_;
#endif
@@ -61,12 +55,7 @@ class RefCountedThreadSafeBase {
bool Release() const;
private:
- struct CounterHolder {
- CounterHolder() : ref_count(0), weak_count(0) {}
- AtomicRefCount ref_count;
- AtomicRefCount weak_count; // Simulates weak pointer.
- };
- mutable CounterHolder* counter_holder_;
+ mutable AtomicRefCount ref_count_;
#ifndef NDEBUG
mutable bool in_dtor_;
#endif
diff --git a/base/shared_memory_posix.cc b/base/shared_memory_posix.cc
index 4793627..bd2c6e5 100644
--- a/base/shared_memory_posix.cc
+++ b/base/shared_memory_posix.cc
@@ -79,7 +79,8 @@ SharedMemoryHandle SharedMemory::NULLHandle() {
// static
void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
DCHECK(handle.fd >= 0);
- close(handle.fd);
+ if (HANDLE_EINTR(close(handle.fd)) < 0)
+ PLOG(ERROR) << "close";
}
bool SharedMemory::CreateAndMapAnonymous(uint32 size) {
@@ -98,7 +99,7 @@ bool SharedMemory::CreateAnonymous(uint32 size) {
// of mem_filename after FilePathForMemoryName().
bool SharedMemory::CreateNamed(const std::string& name,
bool open_existing, uint32 size) {
- DCHECK(mapped_file_ == -1);
+ DCHECK_EQ(-1, mapped_file_);
if (size == 0) return false;
// This function theoretically can block on the disk, but realistically
@@ -229,7 +230,8 @@ void SharedMemory::Close() {
Unmap();
if (mapped_file_ > 0) {
- close(mapped_file_);
+ if (HANDLE_EINTR(close(mapped_file_)) < 0)
+ PLOG(ERROR) << "close";
mapped_file_ = -1;
}
}
@@ -247,7 +249,7 @@ void SharedMemory::Unlock() {
}
bool SharedMemory::PrepareMapFile(FILE *fp) {
- DCHECK(mapped_file_ == -1);
+ DCHECK_EQ(-1, mapped_file_);
if (fp == NULL) return false;
// This function theoretically can block on the disk, but realistically
@@ -282,8 +284,8 @@ bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
FilePath* path) {
// mem_name will be used for a filename; make sure it doesn't
// contain anything which will confuse us.
- DCHECK(mem_name.find('/') == std::string::npos);
- DCHECK(mem_name.find('\0') == std::string::npos);
+ DCHECK_EQ(std::string::npos, mem_name.find('/'));
+ DCHECK_EQ(std::string::npos, mem_name.find('\0'));
FilePath temp_dir;
if (!file_util::GetShmemTempDir(&temp_dir))
diff --git a/base/shared_memory_win.cc b/base/shared_memory_win.cc
index 15c61dd..526132c 100644
--- a/base/shared_memory_win.cc
+++ b/base/shared_memory_win.cc
@@ -80,7 +80,7 @@ bool SharedMemory::CreateAnonymous(uint32 size) {
bool SharedMemory::CreateNamed(const std::string& name,
bool open_existing, uint32 size) {
- DCHECK(mapped_file_ == NULL);
+ DCHECK(!mapped_file_);
if (size == 0)
return false;
@@ -119,7 +119,7 @@ bool SharedMemory::Delete(const std::string& name) {
}
bool SharedMemory::Open(const std::string& name, bool read_only) {
- DCHECK(mapped_file_ == NULL);
+ DCHECK(!mapped_file_);
name_ = ASCIIToWide(name);
read_only_ = read_only;
diff --git a/base/singleton.h b/base/singleton.h
index 5bd5c35..0fe5e27 100644
--- a/base/singleton.h
+++ b/base/singleton.h
@@ -254,7 +254,7 @@ class Singleton {
// Adapter function for use with AtExit(). This should be called single
// threaded, so don't use atomic operations.
// Calling OnExit while singleton is in use by other threads is a mistake.
- static void OnExit(void* unused) {
+ static void OnExit(void* /*unused*/) {
// AtExit should only ever be register after the singleton instance was
// created. We should only ever get here with a valid instance_ pointer.
Traits::Delete(
diff --git a/base/string_util.cc b/base/string_util.cc
index 0e0f17b..b2d9e6c 100644
--- a/base/string_util.cc
+++ b/base/string_util.cc
@@ -808,7 +808,8 @@ size_t Tokenize(const base::StringPiece& str,
template<typename STR>
static STR JoinStringT(const std::vector<STR>& parts,
typename STR::value_type sep) {
- if (parts.size() == 0) return STR();
+ if (parts.empty())
+ return STR();
STR result(parts[0]);
typename std::vector<STR>::const_iterator iter = parts.begin();
diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc
index c2020c2..91467b1 100644
--- a/base/sync_socket_posix.cc
+++ b/base/sync_socket_posix.cc
@@ -63,10 +63,14 @@ bool SyncSocket::CreatePair(SyncSocket* pair[2]) {
return true;
cleanup:
- if (handles[0] != kInvalidHandle)
- (void) close(handles[0]);
- if (handles[1] != kInvalidHandle)
- (void) close(handles[1]);
+ if (handles[0] != kInvalidHandle) {
+ if (HANDLE_EINTR(close(handles[0])) < 0)
+ PLOG(ERROR) << "close";
+ }
+ if (handles[1] != kInvalidHandle) {
+ if (HANDLE_EINTR(close(handles[1])) < 0)
+ PLOG(ERROR) << "close";
+ }
delete tmp_sockets[0];
delete tmp_sockets[1];
return false;
@@ -76,7 +80,9 @@ bool SyncSocket::Close() {
if (handle_ == kInvalidHandle) {
return false;
}
- int retval = close(handle_);
+ int retval = HANDLE_EINTR(close(handle_));
+ if (retval < 0)
+ PLOG(ERROR) << "close";
handle_ = kInvalidHandle;
return (retval == 0);
}
diff --git a/base/synchronization/condition_variable_posix.cc b/base/synchronization/condition_variable_posix.cc
index eff7053..fc68b64 100644
--- a/base/synchronization/condition_variable_posix.cc
+++ b/base/synchronization/condition_variable_posix.cc
@@ -20,12 +20,12 @@ ConditionVariable::ConditionVariable(Lock* user_lock)
#endif
{
int rv = pthread_cond_init(&condition_, NULL);
- DCHECK(rv == 0);
+ DCHECK_EQ(0, rv);
}
ConditionVariable::~ConditionVariable() {
int rv = pthread_cond_destroy(&condition_);
- DCHECK(rv == 0);
+ DCHECK_EQ(0, rv);
}
void ConditionVariable::Wait() {
@@ -33,7 +33,7 @@ void ConditionVariable::Wait() {
user_lock_->CheckHeldAndUnmark();
#endif
int rv = pthread_cond_wait(&condition_, user_mutex_);
- DCHECK(rv == 0);
+ DCHECK_EQ(0, rv);
#if !defined(NDEBUG)
user_lock_->CheckUnheldAndMark();
#endif
@@ -52,7 +52,7 @@ void ConditionVariable::TimedWait(const TimeDelta& max_time) {
Time::kNanosecondsPerMicrosecond;
abstime.tv_sec += abstime.tv_nsec / Time::kNanosecondsPerSecond;
abstime.tv_nsec %= Time::kNanosecondsPerSecond;
- DCHECK(abstime.tv_sec >= now.tv_sec); // Overflow paranoia
+ DCHECK_GE(abstime.tv_sec, now.tv_sec); // Overflow paranoia
#if !defined(NDEBUG)
user_lock_->CheckHeldAndUnmark();
@@ -66,12 +66,12 @@ void ConditionVariable::TimedWait(const TimeDelta& max_time) {
void ConditionVariable::Broadcast() {
int rv = pthread_cond_broadcast(&condition_);
- DCHECK(rv == 0);
+ DCHECK_EQ(0, rv);
}
void ConditionVariable::Signal() {
int rv = pthread_cond_signal(&condition_);
- DCHECK(rv == 0);
+ DCHECK_EQ(0, rv);
}
} // namespace base
diff --git a/base/synchronization/waitable_event_win.cc b/base/synchronization/waitable_event_win.cc
index 0fcf488..a0e39c1 100644
--- a/base/synchronization/waitable_event_win.cc
+++ b/base/synchronization/waitable_event_win.cc
@@ -50,7 +50,7 @@ bool WaitableEvent::Wait() {
DWORD result = WaitForSingleObject(handle_, INFINITE);
// It is most unexpected that this should ever fail. Help consumers learn
// about it if it should ever fail.
- DCHECK(result == WAIT_OBJECT_0) << "WaitForSingleObject failed";
+ DCHECK_EQ(WAIT_OBJECT_0, result) << "WaitForSingleObject failed";
return result == WAIT_OBJECT_0;
}
diff --git a/base/task.h b/base/task.h
index fc986b2..2deee56 100644
--- a/base/task.h
+++ b/base/task.h
@@ -423,6 +423,21 @@ inline CancelableTask* NewRunnableMethod(T* object, Method method,
e, f, g));
}
+template <class T, class Method, class A, class B, class C, class D, class E,
+ class F, class G, class H>
+inline CancelableTask* NewRunnableMethod(T* object, Method method,
+ 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 new RunnableMethod<T,
+ Method,
+ Tuple8<A, B, C, D, E, F, G, H> >(object,
+ method,
+ MakeTuple(a, b, c,
+ d, e, f,
+ g, h));
+}
+
// RunnableFunction and NewRunnableFunction implementation ---------------------
template <class Function, class Params>
diff --git a/base/template_util.h b/base/template_util.h
index 0408fc6..e48af91 100644
--- a/base/template_util.h
+++ b/base/template_util.h
@@ -47,8 +47,6 @@ struct NoType {
YesType dummy[2];
};
-#if !defined(OS_WIN)
-
// 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
@@ -58,15 +56,17 @@ struct NoType {
// had called it with an argument of type From. See Alexandrescu's
// _Modern C++ Design_ for more details on this sort of trick.
-template <typename From, typename To>
struct ConvertHelper {
+ template <typename To>
static YesType Test(To);
+
+ template <typename To>
static NoType Test(...);
+
+ template <typename From>
static From Create();
};
-#endif // !defined(OS_WIN)
-
// Used to determine if a type is a struct/union/class. Inspired by Boost's
// is_class type_trait implementation.
struct IsClassHelper {
@@ -79,19 +79,18 @@ struct IsClassHelper {
} // namespace internal
-#if !defined(OS_WIN)
-
// 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<From, To>::Test(
- internal::ConvertHelper<From, To>::Create()))
- == sizeof(internal::YesType)> {
+ sizeof(internal::ConvertHelper::Test<To>(
+ internal::ConvertHelper::Create<From>())) ==
+ sizeof(internal::YesType)> {
};
-#endif // !defined(OS_WIN)
-
template <typename T>
struct is_class
: integral_constant<bool,
diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc
index 51d4d33..ea5f0ff 100644
--- a/base/template_util_unittest.cc
+++ b/base/template_util_unittest.cc
@@ -37,10 +37,8 @@ TEST(TemplateUtilTest, IsNonConstReference) {
EXPECT_TRUE(is_non_const_reference<int&>::value);
}
-#if !defined(OS_WIN)
-// TODO(ajwong): Why is is_convertible disabled on windows?
TEST(TemplateUtilTest, IsConvertible) {
- // Extra parents needed to make EXPECT_*'s parsing happy. Otherwise,
+ // Extra parens needed to make EXPECT_*'s parsing happy. Otherwise,
// it sees the equivalent of
//
// EXPECT_TRUE( (is_convertible < Child), (Parent > ::value));
@@ -48,8 +46,12 @@ TEST(TemplateUtilTest, IsConvertible) {
// Silly C++.
EXPECT_TRUE( (is_convertible<Child, Parent>::value) );
EXPECT_FALSE( (is_convertible<Parent, Child>::value) );
+ EXPECT_FALSE( (is_convertible<Parent, AStruct>::value) );
+
+ EXPECT_TRUE( (is_convertible<int, double>::value) );
+ EXPECT_TRUE( (is_convertible<int*, void*>::value) );
+ EXPECT_FALSE( (is_convertible<void*, int*>::value) );
}
-#endif // !defined(OS_WIN)
TEST(TemplateUtilTest, IsClass) {
EXPECT_TRUE(is_class<AStruct>::value);
diff --git a/base/test/test_file_util.h b/base/test/test_file_util.h
index 2de74e7..e59456a 100644
--- a/base/test/test_file_util.h
+++ b/base/test/test_file_util.h
@@ -8,6 +8,8 @@
// File utility functions used only by tests.
+#include <string>
+
class FilePath;
namespace file_util {
@@ -35,9 +37,17 @@ bool CopyRecursiveDirNoCache(const FilePath& source_dir,
bool VolumeSupportsADS(const FilePath& path);
// Returns true if the ZoneIdentifier is correctly set to "Internet" (3).
+// Note that this function must be called from the same process as
+// the one that set the zone identifier. I.e. don't use it in UI/automation
+// based tests.
bool HasInternetZoneIdentifier(const FilePath& full_path);
#endif // defined(OS_WIN)
+// In general it's not reliable to convert a FilePath to a wstring and we use
+// string16 elsewhere for Unicode strings, but in tests it is frequently
+// convenient to be able to compare paths to literals like L"foobar".
+std::wstring FilePathAsWString(const FilePath& path);
+
} // namespace file_util
#endif // BASE_TEST_TEST_FILE_UTIL_H_
diff --git a/base/test/test_file_util_posix.cc b/base/test/test_file_util_posix.cc
index 876e882..430e52e 100644
--- a/base/test/test_file_util_posix.cc
+++ b/base/test/test_file_util_posix.cc
@@ -15,6 +15,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
namespace file_util {
@@ -109,4 +110,8 @@ bool EvictFileFromSystemCache(const FilePath& file) {
}
#endif
+std::wstring FilePathAsWString(const FilePath& path) {
+ return UTF8ToWide(path.value());
+}
+
} // namespace file_util
diff --git a/base/test/test_file_util_win.cc b/base/test/test_file_util_win.cc
index 7ca7e84..1f20740 100644
--- a/base/test/test_file_util_win.cc
+++ b/base/test/test_file_util_win.cc
@@ -194,41 +194,31 @@ bool VolumeSupportsADS(const FilePath& path) {
}
// Return whether the ZoneIdentifier is correctly set to "Internet" (3)
+// Only returns a valid result when called from same process as the
+// one that (was supposed to have) set the zone identifier.
bool HasInternetZoneIdentifier(const FilePath& full_path) {
- std::wstring path = full_path.value() + L":Zone.Identifier";
-
- // This polling and sleeping here is a very bad pattern. But due to how
- // Windows file semantics work it's really hard to do it other way. We are
- // reading a file written by a different process, using a different handle.
- // Windows does not guarantee that we will get the same contents even after
- // the other process closes the handle, flushes the buffers, etc.
- for (int i = 0; i < 20; i++) {
- base::PlatformThread::Sleep(1000);
-
- const DWORD kShare = FILE_SHARE_READ |
- FILE_SHARE_WRITE |
- FILE_SHARE_DELETE;
- HANDLE file = CreateFile(path.c_str(), GENERIC_READ, kShare, NULL,
- OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if (file == INVALID_HANDLE_VALUE)
- continue;
-
- char buffer[100] = {0};
- DWORD read = 0;
- BOOL read_result = ::ReadFile(file, buffer, 100, &read, NULL);
- CloseHandle(file);
-
- if (!read_result)
- continue;
-
- const char kIdentifier[] = "[ZoneTransfer]\nZoneId=3";
- if (read != arraysize(kIdentifier))
- continue;
-
- if (strcmp(kIdentifier, buffer) == 0)
- return true;
- }
- return false;
+ FilePath zone_path(full_path.value() + L":Zone.Identifier");
+ std::string zone_path_contents;
+ if (!file_util::ReadFileToString(zone_path, &zone_path_contents))
+ return false;
+
+ static const char kInternetIdentifier[] = "[ZoneTransfer]\nZoneId=3";
+ static const size_t kInternetIdentifierSize =
+ // Don't include null byte in size of identifier.
+ arraysize(kInternetIdentifier) - 1;
+
+ // Our test is that the initial characters match the above, and that
+ // the character after the end of the string is eof, null, or newline; any
+ // of those three will invoke the Window Finder cautionary dialog.
+ return ((zone_path_contents.compare(0, kInternetIdentifierSize,
+ kInternetIdentifier) == 0) &&
+ (kInternetIdentifierSize == zone_path_contents.length() ||
+ zone_path_contents[kInternetIdentifierSize] == '\0' ||
+ zone_path_contents[kInternetIdentifierSize] == '\n'));
+}
+
+std::wstring FilePathAsWString(const FilePath& path) {
+ return path.value();
}
} // namespace file_util
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index 447a138..42b5b90 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -49,6 +49,9 @@ class MaybeTestDisabler : public testing::EmptyTestEventListener {
const char TestSuite::kStrictFailureHandling[] = "strict_failure_handling";
TestSuite::TestSuite(int argc, char** argv) {
+#if defined(OS_WIN)
+ testing::GTEST_FLAG(catch_exceptions) = false;
+#endif
base::EnableTerminationOnHeapCorruption();
CommandLine::Init(argc, argv);
testing::InitGoogleTest(&argc, argv);
diff --git a/base/threading/non_thread_safe.cc b/base/threading/non_thread_safe.cc
deleted file mode 100644
index 8b41bc0..0000000
--- a/base/threading/non_thread_safe.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/threading/non_thread_safe.h"
-
-// These checks are only done in debug builds.
-#ifndef NDEBUG
-
-#include "base/logging.h"
-
-namespace base {
-
-NonThreadSafe::~NonThreadSafe() {
- DCHECK(CalledOnValidThread());
-}
-
-bool NonThreadSafe::CalledOnValidThread() const {
- return thread_checker_.CalledOnValidThread();
-}
-
-void NonThreadSafe::DetachFromThread() {
- thread_checker_.DetachFromThread();
-}
-
-} // namespace base
-
-#endif // NDEBUG
diff --git a/base/threading/non_thread_safe.h b/base/threading/non_thread_safe.h
index 868a031..bc3be3c 100644
--- a/base/threading/non_thread_safe.h
+++ b/base/threading/non_thread_safe.h
@@ -6,13 +6,29 @@
#define BASE_THREADING_NON_THREAD_SAFE_H_
#pragma once
-#include "base/threading/thread_checker.h"
+#ifndef NDEBUG
+#include "base/threading/non_thread_safe_impl.h"
+#endif
namespace base {
-// A helper class used to help verify that methods of a class are
-// called from the same thread. One can inherit from this class and use
-// CalledOnValidThread() to verify.
+// Do nothing implementation of NonThreadSafe, for release mode.
+//
+// Note: You should almost always use the NonThreadSafe class to get
+// the right version of the class for your build configuration.
+class NonThreadSafeDoNothing {
+ public:
+ bool CalledOnValidThread() const {
+ return true;
+ }
+
+ protected:
+ void DetachFromThread() {}
+};
+
+// NonThreadSafe is a helper class used to help verify that methods of a
+// class are called from the same thread. One can inherit from this class
+// and use CalledOnValidThread() to verify.
//
// This is intended to be used with classes that appear to be thread safe, but
// aren't. For example, a service or a singleton like the preferences system.
@@ -29,33 +45,10 @@ namespace base {
// In Release mode, CalledOnValidThread will always return true.
//
#ifndef NDEBUG
-class NonThreadSafe {
- public:
- ~NonThreadSafe();
-
- bool CalledOnValidThread() const;
-
- protected:
- // Changes the thread that is checked for in CalledOnValidThread. The next
- // call to CalledOnValidThread will attach this class to a new thread. It is
- // up to the NonThreadSafe derived class to decide to expose this or not.
- // This may be useful when an object may be created on one thread and then
- // used exclusively on another thread.
- void DetachFromThread();
-
- private:
- ThreadChecker thread_checker_;
+class NonThreadSafe : public NonThreadSafeImpl {
};
#else
-// Do nothing in release mode.
-class NonThreadSafe {
- public:
- bool CalledOnValidThread() const {
- return true;
- }
-
- protected:
- void DetachFromThread() {}
+class NonThreadSafe : public NonThreadSafeDoNothing {
};
#endif // NDEBUG
diff --git a/base/threading/non_thread_safe_impl.cc b/base/threading/non_thread_safe_impl.cc
new file mode 100644
index 0000000..f9c18c2
--- /dev/null
+++ b/base/threading/non_thread_safe_impl.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/non_thread_safe_impl.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+NonThreadSafeImpl::~NonThreadSafeImpl() {
+ DCHECK(CalledOnValidThread());
+}
+
+bool NonThreadSafeImpl::CalledOnValidThread() const {
+ return thread_checker_.CalledOnValidThread();
+}
+
+void NonThreadSafeImpl::DetachFromThread() {
+ thread_checker_.DetachFromThread();
+}
+
+} // namespace base
diff --git a/base/threading/non_thread_safe_impl.h b/base/threading/non_thread_safe_impl.h
new file mode 100644
index 0000000..12925f1
--- /dev/null
+++ b/base/threading/non_thread_safe_impl.h
@@ -0,0 +1,39 @@
+// 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_NON_THREAD_SAFE_IMPL_H_
+#define BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
+#pragma once
+
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+// Full implementation of NonThreadSafe, for debug mode or for occasional
+// temporary use in release mode e.g. when you need to CHECK on a thread
+// bug that only occurs in the wild.
+//
+// Note: You should almost always use the NonThreadSafe class to get
+// the right version of the class for your build configuration.
+class NonThreadSafeImpl {
+ public:
+ ~NonThreadSafeImpl();
+
+ bool CalledOnValidThread() const;
+
+ protected:
+ // Changes the thread that is checked for in CalledOnValidThread. The next
+ // call to CalledOnValidThread will attach this class to a new thread. It is
+ // up to the NonThreadSafe derived class to decide to expose this or not.
+ // This may be useful when an object may be created on one thread and then
+ // used exclusively on another thread.
+ void DetachFromThread();
+
+ private:
+ ThreadCheckerImpl thread_checker_;
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
diff --git a/base/threading/non_thread_safe_unittest.cc b/base/threading/non_thread_safe_unittest.cc
index 7d158cf..b79a4f4 100644
--- a/base/threading/non_thread_safe_unittest.cc
+++ b/base/threading/non_thread_safe_unittest.cc
@@ -9,8 +9,6 @@
#include "base/threading/simple_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
-#ifndef NDEBUG
-
namespace base {
// Simple class to exersice the basics of NonThreadSafe.
@@ -22,13 +20,16 @@ class NonThreadSafeClass : public NonThreadSafe {
// Verifies that it was called on the same thread as the constructor.
void DoStuff() {
- DCHECK(CalledOnValidThread());
+ CHECK(CalledOnValidThread());
}
void DetachFromThread() {
NonThreadSafe::DetachFromThread();
}
+ static void MethodOnDifferentThreadImpl();
+ static void DestructorOnDifferentThreadImpl();
+
private:
DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass);
};
@@ -94,37 +95,57 @@ TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) {
delete_on_thread.Join();
}
-#if GTEST_HAS_DEATH_TEST
+#if GTEST_HAS_DEATH_TEST || NDEBUG
-TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThread) {
- ASSERT_DEBUG_DEATH({
- scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
- new NonThreadSafeClass);
+void NonThreadSafeClass::MethodOnDifferentThreadImpl() {
+ scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+ new NonThreadSafeClass);
- // Verify that DoStuff asserts when called on a different thread.
- CallDoStuffOnThread call_on_thread(non_thread_safe_class.get());
+ // Verify that DoStuff asserts in debug builds only when called
+ // on a different thread.
+ CallDoStuffOnThread call_on_thread(non_thread_safe_class.get());
- call_on_thread.Start();
- call_on_thread.Join();
- }, "");
+ call_on_thread.Start();
+ call_on_thread.Join();
}
-TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThread) {
+#ifndef NDEBUG
+TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
ASSERT_DEBUG_DEATH({
- scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
- new NonThreadSafeClass);
+ NonThreadSafeClass::MethodOnDifferentThreadImpl();
+ }, "");
+}
+#else
+TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
+ NonThreadSafeClass::MethodOnDifferentThreadImpl();
+}
+#endif // NDEBUG
- // Verify that the destructor asserts when called on a different thread.
- DeleteNonThreadSafeClassOnThread delete_on_thread(
- non_thread_safe_class.release());
+void NonThreadSafeClass::DestructorOnDifferentThreadImpl() {
+ scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+ new NonThreadSafeClass);
- delete_on_thread.Start();
- delete_on_thread.Join();
+ // Verify that the destructor asserts in debug builds only
+ // when called on a different thread.
+ DeleteNonThreadSafeClassOnThread delete_on_thread(
+ non_thread_safe_class.release());
+
+ delete_on_thread.Start();
+ delete_on_thread.Join();
+}
+
+#ifndef NDEBUG
+TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
+ ASSERT_DEBUG_DEATH({
+ NonThreadSafeClass::DestructorOnDifferentThreadImpl();
}, "");
}
+#else
+TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
+ NonThreadSafeClass::DestructorOnDifferentThreadImpl();
+}
+#endif // NDEBUG
-#endif // GTEST_HAS_DEATH_TEST
+#endif // GTEST_HAS_DEATH_TEST || NDEBUG
} // namespace base
-
-#endif // NDEBUG
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 8452909..103145a 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -189,7 +189,7 @@ void PlatformThread::SetName(const char* name) {
// Mac is implemented in platform_thread_mac.mm.
#else
// static
-void PlatformThread::SetName(const char* name) {
+void PlatformThread::SetName(const char* /*name*/) {
// Leave it unimplemented.
// (This should be relatively simple to implement for the BSDs; I
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index c0fb537..7a100ca 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -173,7 +173,6 @@ void Thread::ThreadMain() {
message_loop_ = NULL;
message_loop_proxy_ = NULL;
}
- CleanUpAfterMessageLoopDestruction();
thread_id_ = kInvalidThreadId;
}
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 811dd80..379615d 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -25,7 +25,6 @@ namespace base {
// (1) Thread::CleanUp()
// (2) MessageLoop::~MessageLoop
// (3.b) MessageLoop::DestructionObserver::WillDestroyCurrentMessageLoop
-// (4) Thread::CleanUpAfterMessageLoopDestruction()
class Thread : PlatformThread::Delegate {
public:
struct Options {
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
index 712b5b5..33b6764 100644
--- a/base/threading/thread_checker.h
+++ b/base/threading/thread_checker.h
@@ -7,22 +7,34 @@
#pragma once
#ifndef NDEBUG
-#include "base/synchronization/lock.h"
-#include "base/threading/platform_thread.h"
-#endif // NDEBUG
+#include "base/threading/thread_checker_impl.h"
+#endif
namespace base {
+// Do nothing implementation, for use in release mode.
+//
+// Note: You should almost always use the ThreadChecker class to get the
+// right version for your build configuration.
+class ThreadCheckerDoNothing {
+ public:
+ bool CalledOnValidThread() const {
+ return true;
+ }
+
+ void DetachFromThread() {}
+};
+
// Before using this class, please consider using NonThreadSafe as it
// makes it much easier to determine the nature of your class.
//
-// A helper class used to help verify that some methods of a class are
-// called from the same thread. One can inherit from this class and use
-// CalledOnValidThread() to verify.
+// ThreadChecker is a helper class used to help verify that some methods of a
+// class are called from the same thread. One can inherit from this class and
+// use CalledOnValidThread() to verify.
//
-// Inheriting from class indicates that one must be careful when using the class
-// with multiple threads. However, it is up to the class document to indicate
-// how it can be used with threads.
+// Inheriting from class indicates that one must be careful when using the
+// class with multiple threads. However, it is up to the class document to
+// indicate how it can be used with threads.
//
// Example:
// class MyClass : public ThreadChecker {
@@ -34,37 +46,11 @@ namespace base {
// }
//
// In Release mode, CalledOnValidThread will always return true.
-//
#ifndef NDEBUG
-class ThreadChecker {
- public:
- ThreadChecker();
- ~ThreadChecker();
-
- bool CalledOnValidThread() const;
-
- // Changes the thread that is checked for in CalledOnValidThread. This may
- // be useful when an object may be created on one thread and then used
- // exclusively on another thread.
- void DetachFromThread();
-
- private:
- void EnsureThreadIdAssigned() const;
-
- mutable base::Lock lock_;
- // This is mutable so that CalledOnValidThread can set it.
- // It's guarded by |lock_|.
- mutable PlatformThreadId valid_thread_id_;
+class ThreadChecker : public ThreadCheckerImpl {
};
#else
-// Do nothing in release mode.
-class ThreadChecker {
- public:
- bool CalledOnValidThread() const {
- return true;
- }
-
- void DetachFromThread() {}
+class ThreadChecker : public ThreadCheckerDoNothing {
};
#endif // NDEBUG
diff --git a/base/threading/thread_checker.cc b/base/threading/thread_checker_impl.cc
index 28ba400..985433e 100644
--- a/base/threading/thread_checker.cc
+++ b/base/threading/thread_checker_impl.cc
@@ -1,32 +1,30 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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_checker.h"
-
-// This code is only done in debug builds.
-#ifndef NDEBUG
+#include "base/threading/thread_checker_impl.h"
namespace base {
-ThreadChecker::ThreadChecker() : valid_thread_id_(kInvalidThreadId) {
+ThreadCheckerImpl::ThreadCheckerImpl()
+ : valid_thread_id_(kInvalidThreadId) {
EnsureThreadIdAssigned();
}
-ThreadChecker::~ThreadChecker() {}
+ThreadCheckerImpl::~ThreadCheckerImpl() {}
-bool ThreadChecker::CalledOnValidThread() const {
+bool ThreadCheckerImpl::CalledOnValidThread() const {
EnsureThreadIdAssigned();
AutoLock auto_lock(lock_);
return valid_thread_id_ == PlatformThread::CurrentId();
}
-void ThreadChecker::DetachFromThread() {
+void ThreadCheckerImpl::DetachFromThread() {
AutoLock auto_lock(lock_);
valid_thread_id_ = kInvalidThreadId;
}
-void ThreadChecker::EnsureThreadIdAssigned() const {
+void ThreadCheckerImpl::EnsureThreadIdAssigned() const {
AutoLock auto_lock(lock_);
if (valid_thread_id_ != kInvalidThreadId)
return;
@@ -34,5 +32,3 @@ void ThreadChecker::EnsureThreadIdAssigned() const {
}
} // namespace base
-
-#endif // NDEBUG
diff --git a/base/threading/thread_checker_impl.h b/base/threading/thread_checker_impl.h
new file mode 100644
index 0000000..6d41fdc
--- /dev/null
+++ b/base/threading/thread_checker_impl.h
@@ -0,0 +1,43 @@
+// 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_CHECKER_IMPL_H_
+#define BASE_THREADING_THREAD_CHECKER_IMPL_H_
+#pragma once
+
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// Real implementation of ThreadChecker, for use in debug mode, or
+// for temporary use in release mode (e.g. to CHECK on a threading issue
+// seen only in the wild).
+//
+// Note: You should almost always use the ThreadChecker class to get the
+// right version for your build configuration.
+class ThreadCheckerImpl {
+ public:
+ ThreadCheckerImpl();
+ ~ThreadCheckerImpl();
+
+ bool CalledOnValidThread() const;
+
+ // Changes the thread that is checked for in CalledOnValidThread. This may
+ // be useful when an object may be created on one thread and then used
+ // exclusively on another thread.
+ void DetachFromThread();
+
+ private:
+ void EnsureThreadIdAssigned() const;
+
+ mutable base::Lock lock_;
+ // This is mutable so that CalledOnValidThread can set it.
+ // It's guarded by |lock_|.
+ mutable PlatformThreadId valid_thread_id_;
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_THREAD_CHECKER_IMPL_H_
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc
index 6ce5bf1..9a22a8e 100644
--- a/base/threading/thread_checker_unittest.cc
+++ b/base/threading/thread_checker_unittest.cc
@@ -9,11 +9,9 @@
#include "base/threading/simple_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
-#ifndef NDEBUG
-
namespace base {
-// Simple class to exersice the basics of ThreadChecker.
+// Simple class to exercise the basics of ThreadChecker.
// Both the destructor and DoStuff should verify that they were
// called on the same thread as the constructor.
class ThreadCheckerClass : public ThreadChecker {
@@ -22,13 +20,16 @@ class ThreadCheckerClass : public ThreadChecker {
// Verifies that it was called on the same thread as the constructor.
void DoStuff() {
- DCHECK(CalledOnValidThread());
+ CHECK(CalledOnValidThread());
}
void DetachFromThread() {
ThreadChecker::DetachFromThread();
}
+ static void MethodOnDifferentThreadImpl();
+ static void DetachThenCallFromDifferentThreadImpl();
+
private:
DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
};
@@ -106,41 +107,61 @@ TEST(ThreadCheckerTest, DetachFromThread) {
call_on_thread.Join();
}
-#if GTEST_HAS_DEATH_TEST
+#if GTEST_HAS_DEATH_TEST || NDEBUG
-TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThread) {
- ASSERT_DEBUG_DEATH({
- scoped_ptr<ThreadCheckerClass> thread_checker_class(
- new ThreadCheckerClass);
+void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
- // Verify that DoStuff asserts when called on a different thread.
- CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+ // DoStuff should assert in debug builds only when called on a
+ // different thread.
+ CallDoStuffOnThread call_on_thread(thread_checker_class.get());
- call_on_thread.Start();
- call_on_thread.Join();
- }, "");
+ call_on_thread.Start();
+ call_on_thread.Join();
}
-TEST(ThreadCheckerDeathTest, DetachFromThread) {
+#ifndef NDEBUG
+TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
ASSERT_DEBUG_DEATH({
- scoped_ptr<ThreadCheckerClass> thread_checker_class(
- new ThreadCheckerClass);
+ ThreadCheckerClass::MethodOnDifferentThreadImpl();
+ }, "");
+}
+#else
+TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
+ ThreadCheckerClass::MethodOnDifferentThreadImpl();
+}
+#endif // NDEBUG
- // Verify that DoStuff doesn't assert when called on a different thread
- // after a call to DetachFromThread.
- thread_checker_class->DetachFromThread();
- CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
+ scoped_ptr<ThreadCheckerClass> thread_checker_class(
+ new ThreadCheckerClass);
+
+ // DoStuff doesn't assert when called on a different thread
+ // after a call to DetachFromThread.
+ thread_checker_class->DetachFromThread();
+ CallDoStuffOnThread call_on_thread(thread_checker_class.get());
- call_on_thread.Start();
- call_on_thread.Join();
+ call_on_thread.Start();
+ call_on_thread.Join();
- // Verify that DoStuff asserts after moving to another thread.
- thread_checker_class->DoStuff();
+ // DoStuff should assert in debug builds only after moving to
+ // another thread.
+ thread_checker_class->DoStuff();
+}
+
+#ifndef NDEBUG
+TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
+ ASSERT_DEBUG_DEATH({
+ ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
}, "");
}
+#else
+TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
+ ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
+}
+#endif // NDEBUG
-#endif // GTEST_HAS_DEATH_TEST
+#endif // GTEST_HAS_DEATH_TEST || NDEBUG
} // namespace base
-
-#endif // NDEBUG
diff --git a/base/threading/thread_local_storage_win.cc b/base/threading/thread_local_storage_win.cc
index 667d1b9..c8128f1 100644
--- a/base/threading/thread_local_storage_win.cc
+++ b/base/threading/thread_local_storage_win.cc
@@ -47,7 +47,7 @@ void** ThreadLocalStorage::Initialize() {
TlsFree(value);
}
}
- DCHECK(TlsGetValue(tls_key_) == NULL);
+ DCHECK(!TlsGetValue(tls_key_));
// Create an array to store our data.
void** tls_data = new void*[kThreadLocalStorageSize];
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index 3748fc3..c7cb76a 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -57,7 +57,7 @@ class SleepInsideInitThread : public Thread {
enum ThreadEvent {
// Thread::Init() was called.
- THREAD_EVENT_INIT,
+ THREAD_EVENT_INIT = 0,
// The MessageLoop for the thread was deleted.
THREAD_EVENT_MESSAGE_LOOP_DESTROYED,
@@ -65,8 +65,8 @@ enum ThreadEvent {
// Thread::CleanUp() was called.
THREAD_EVENT_CLEANUP,
- // Thread::CleanUpAfterMessageLoopDestruction() was called.
- THREAD_EVENT_CLEANUP_AFTER_LOOP,
+ // Keep at end of list.
+ THREAD_NUM_EVENTS
};
typedef std::vector<ThreadEvent> EventList;
@@ -93,10 +93,6 @@ class CaptureToEventList : public Thread {
event_list_->push_back(THREAD_EVENT_CLEANUP);
}
- virtual void CleanUpAfterMessageLoopDestruction() {
- event_list_->push_back(THREAD_EVENT_CLEANUP_AFTER_LOOP);
- }
-
private:
EventList* event_list_;
};
@@ -230,7 +226,6 @@ TEST_F(ThreadTest, SleepInsideInit) {
// (1) Thread::CleanUp()
// (2) MessageLoop::~MessageLoop()
// MessageLoop::DestructionObservers called.
-// (3) Thread::CleanUpAfterMessageLoopDestruction
TEST_F(ThreadTest, CleanUp) {
EventList captured_events;
CapturingDestructionObserver loop_destruction_observer(&captured_events);
@@ -252,9 +247,8 @@ TEST_F(ThreadTest, CleanUp) {
}
// Check the order of events during shutdown.
- ASSERT_EQ(4u, captured_events.size());
+ ASSERT_EQ(static_cast<size_t>(THREAD_NUM_EVENTS), captured_events.size());
EXPECT_EQ(THREAD_EVENT_INIT, captured_events[0]);
EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
- EXPECT_EQ(THREAD_EVENT_CLEANUP_AFTER_LOOP, captured_events[3]);
}
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc
index 779c236..e1e41a6 100644
--- a/base/tools_sanity_unittest.cc
+++ b/base/tools_sanity_unittest.cc
@@ -61,16 +61,8 @@ void MakeSomeErrors(char *ptr, size_t size) {
ReadUninitializedValue(ptr);
ReadValueOutOfArrayBoundsLeft(ptr);
ReadValueOutOfArrayBoundsRight(ptr, size);
-
- // We execute this function only under memory checking tools -
- // Valgrind on Linux and Mac, Dr. Memory on Windows.
- // Currently writing values out-of-bounds makes Dr. Memory a bit crazy when
- // this code is linked with /MTd, so skip these writes on Windows.
- // See http://code.google.com/p/drmemory/issues/detail?id=51
-#if !defined(OS_WIN)
WriteValueOutOfArrayBoundsLeft(ptr);
WriteValueOutOfArrayBoundsRight(ptr, size);
-#endif
}
} // namespace
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index a9f81b1..d10603d 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -467,7 +467,7 @@ bool ThreadData::StartTracking(bool status) {
return true;
}
base::AutoLock lock(list_lock_);
- DCHECK(status_ == UNINITIALIZED);
+ DCHECK_EQ(UNINITIALIZED, status_);
CHECK(tls_index_.Initialize(NULL));
status_ = ACTIVE;
return true;
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index ed629c3..ac49225 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -643,13 +643,10 @@ class AutoTracking {
#ifndef NDEBUG
if (state_ != kRunning)
return;
- // Don't call these in a Release build: they just waste time.
- // The following should ONLY be called when in single threaded mode. It is
- // unsafe to do this cleanup if other threads are still active.
- // It is also very unnecessary, so I'm only doing this in debug to satisfy
- // purify (if we need to!).
- ThreadData::ShutdownSingleThreadedCleanup();
- state_ = kTornDownAndStopped;
+ // We don't do cleanup of any sort in Release build because it is a
+ // complete waste of time. Since Chromium doesn't join all its thread and
+ // guarantee we're in a single threaded mode, we don't even do cleanup in
+ // debug mode, as it will generate race-checker warnings.
#endif
}
diff --git a/base/tuple.h b/base/tuple.h
index 13d8722..65d0908 100644
--- a/base/tuple.h
+++ b/base/tuple.h
@@ -590,6 +590,13 @@ inline void DispatchToMethod(ObjT* obj, Method method,
(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>
diff --git a/base/values.cc b/base/values.cc
index 9c96f26..3340f9b 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -4,8 +4,10 @@
#include "base/values.h"
+#include "base/file_path.h"
#include "base/logging.h"
#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
namespace {
@@ -95,6 +97,19 @@ StringValue* Value::CreateStringValue(const string16& in_value) {
}
// static
+StringValue* Value::CreateFilePathValue(const FilePath& in_value) {
+#if defined(OS_POSIX)
+ // Value::SetString only knows about UTF8 strings, so convert the path from
+ // the system native value to UTF8.
+ std::string path_utf8 = WideToUTF8(base::SysNativeMBToWide(in_value.value()));
+ return new StringValue(path_utf8);
+#else
+ return new StringValue(in_value.value());
+#endif
+
+}
+
+// static
BinaryValue* Value::CreateBinaryValue(char* buffer, size_t size) {
return BinaryValue::Create(buffer, size);
}
@@ -119,6 +134,10 @@ bool Value::GetAsString(string16* out_value) const {
return false;
}
+bool Value::GetAsFilePath(FilePath* out_value) const {
+ return false;
+}
+
bool Value::GetAsList(ListValue** out_value) {
return false;
}
@@ -250,6 +269,20 @@ bool StringValue::GetAsString(string16* out_value) const {
return true;
}
+bool StringValue::GetAsFilePath(FilePath* out_value) const {
+ if (out_value) {
+ FilePath::StringType result;
+#if defined(OS_POSIX)
+ // We store filepaths as UTF8, so convert it back to the system type.
+ result = base::SysWideToNativeMB(UTF8ToWide(value_));
+#elif defined(OS_WIN)
+ result = UTF8ToUTF16(value_);
+#endif
+ *out_value = FilePath(result);
+ }
+ return true;
+}
+
StringValue* StringValue::DeepCopy() const {
return CreateStringValue(value_);
}
diff --git a/base/values.h b/base/values.h
index 408ca8b..5814a9f 100644
--- a/base/values.h
+++ b/base/values.h
@@ -31,12 +31,13 @@
#include "base/string16.h"
#include "build/build_config.h"
-class Value;
-class FundamentalValue;
-class StringValue;
class BinaryValue;
class DictionaryValue;
+class FilePath;
+class FundamentalValue;
class ListValue;
+class StringValue;
+class Value;
typedef std::vector<Value*> ValueVector;
typedef std::map<std::string, Value*> ValueMap;
@@ -68,6 +69,7 @@ class Value {
static FundamentalValue* CreateDoubleValue(double in_value);
static StringValue* CreateStringValue(const std::string& in_value);
static StringValue* CreateStringValue(const string16& in_value);
+ static StringValue* CreateFilePathValue(const FilePath& in_value);
// This one can return NULL if the input isn't valid. If the return value
// is non-null, the new object has taken ownership of the buffer pointer.
@@ -92,6 +94,7 @@ class Value {
virtual bool GetAsDouble(double* out_value) const;
virtual bool GetAsString(std::string* out_value) const;
virtual bool GetAsString(string16* out_value) const;
+ virtual bool GetAsFilePath(FilePath* out_value) const;
virtual bool GetAsList(ListValue** out_value);
// This creates a deep copy of the entire Value tree, and returns a pointer
@@ -159,6 +162,7 @@ class StringValue : public Value {
// Subclassed methods
virtual bool GetAsString(std::string* out_value) const;
virtual bool GetAsString(string16* out_value) const;
+ virtual bool GetAsFilePath(FilePath* out_value) const;
virtual StringValue* DeepCopy() const;
virtual bool Equals(const Value* other) const;
diff --git a/base/win/scoped_bstr.cc b/base/win/scoped_bstr.cc
index 18ffe6a..63ade0c 100644
--- a/base/win/scoped_bstr.cc
+++ b/base/win/scoped_bstr.cc
@@ -39,7 +39,7 @@ void ScopedBstr::Swap(ScopedBstr& bstr2) {
}
BSTR* ScopedBstr::Receive() {
- DCHECK(bstr_ == NULL) << "BSTR leak.";
+ DCHECK(!bstr_) << "BSTR leak.";
return &bstr_;
}
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
index 6375218..e508ef2 100644
--- a/base/win/scoped_comptr.h
+++ b/base/win/scoped_comptr.h
@@ -69,7 +69,7 @@ class ScopedComPtr : public scoped_refptr<Interface> {
// Accepts an interface pointer that has already been addref-ed.
void Attach(Interface* p) {
- DCHECK(ptr_ == NULL);
+ DCHECK(!ptr_);
ptr_ = p;
}
@@ -78,7 +78,7 @@ class ScopedComPtr : public scoped_refptr<Interface> {
// The function DCHECKs on the current value being NULL.
// Usage: Foo(p.Receive());
Interface** Receive() {
- DCHECK(ptr_ == NULL) << "Object leak. Pointer must be NULL";
+ DCHECK(!ptr_) << "Object leak. Pointer must be NULL";
return &ptr_;
}
@@ -114,7 +114,7 @@ class ScopedComPtr : public scoped_refptr<Interface> {
// Convenience wrapper around CoCreateInstance
HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
DWORD context = CLSCTX_ALL) {
- DCHECK(ptr_ == NULL);
+ DCHECK(!ptr_);
HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
reinterpret_cast<void**>(&ptr_));
return hr;
diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc
index 40ccdf2..f57ab93 100644
--- a/base/win/scoped_variant.cc
+++ b/base/win/scoped_variant.cc
@@ -211,7 +211,7 @@ void ScopedVariant::Set(SAFEARRAY* array) {
var_.vt |= VT_ARRAY;
var_.parray = array;
} else {
- DCHECK(array == NULL) << "Unable to determine safearray vartype";
+ DCHECK(!array) << "Unable to determine safearray vartype";
var_.vt = VT_EMPTY;
}
}
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index d3d74a2..76d8c5d 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -137,6 +137,13 @@ bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS);
}
+bool ReadCommandFromAutoRun(HKEY root_key,
+ const string16& name,
+ string16* command) {
+ base::win::RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
+ return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS);
+}
+
} // namespace win
} // namespace base
diff --git a/base/win/win_util.h b/base/win/win_util.h
index 187e42d..c9bdce8 100644
--- a/base/win/win_util.h
+++ b/base/win/win_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -55,7 +55,7 @@ bool IsAltPressed();
// NOTE: The EnableLUA registry flag, which is ignored on Windows XP
// machines, might still exist and be set to 0 (UAC disabled), in which case
// this function will return false. You should therefore check this flag only
-// if the OS is Vista.
+// if the OS is Vista or later.
bool UserAccountControlIsEnabled();
// Sets the application id in given IPropertyStore. The function is intended
@@ -72,6 +72,11 @@ bool AddCommandToAutoRun(HKEY root_key, const string16& name,
// could be HKCU or HKLM or the root of any user hive.
bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name);
+// Reads the command specified by |name| from the AutoRun key. |root_key|
+// could be HKCU or HKLM or the root of any user hive. Used for unit-tests.
+bool ReadCommandFromAutoRun(HKEY root_key,
+ const string16& name,
+ string16* command);
} // namespace win
} // namespace base
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc
index a80688c..d53148d 100644
--- a/base/win/windows_version.cc
+++ b/base/win/windows_version.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -68,5 +68,34 @@ void GetServicePackLevel(int* major, int* minor) {
*minor = service_pack_minor;
}
+WindowsArchitecture GetWindowsArchitecture() {
+ SYSTEM_INFO system_info;
+ GetNativeSystemInfo(&system_info);
+ switch (system_info.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_INTEL: return X86_ARCHITECTURE;
+ case PROCESSOR_ARCHITECTURE_AMD64: return X64_ARCHITECTURE;
+ case PROCESSOR_ARCHITECTURE_IA64: return IA64_ARCHITECTURE;
+ default: return OTHER_ARCHITECTURE;
+ }
+}
+
+WOW64Status GetWOW64Status() {
+ static WOW64Status wow64_status =
+ GetWOW64StatusForProcess(GetCurrentProcess());
+ return wow64_status;
+}
+
+WOW64Status GetWOW64StatusForProcess(HANDLE process_handle) {
+ typedef BOOL (WINAPI* IsWow64ProcessFunc)(HANDLE, PBOOL);
+ IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
+ GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
+ if (!is_wow64_process)
+ return WOW64_DISABLED;
+ BOOL is_wow64 = FALSE;
+ if (!(*is_wow64_process)(process_handle, &is_wow64))
+ return WOW64_UNKNOWN;
+ return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
+}
+
} // namespace win
} // namespace base
diff --git a/base/win/windows_version.h b/base/win/windows_version.h
index 7e281a6..df3cc35 100644
--- a/base/win/windows_version.h
+++ b/base/win/windows_version.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -6,6 +6,8 @@
#define BASE_WIN_WINDOWS_VERSION_H_
#pragma once
+typedef void* HANDLE;
+
namespace base {
namespace win {
@@ -13,10 +15,10 @@ namespace win {
// "if (GetWinVersion() > WINVERSION_2000) ...". It's OK to change the values,
// though.
enum Version {
- VERSION_PRE_2000 = 0, // Not supported
- VERSION_2000 = 1, // Not supported
+ VERSION_PRE_2000 = 0, // Not supported
+ VERSION_2000 = 1, // Not supported
VERSION_XP = 2,
- VERSION_SERVER_2003 = 3,
+ VERSION_SERVER_2003 = 3, // Also includes Windows XP Professional x64 edition
VERSION_VISTA = 4,
VERSION_2008 = 5,
VERSION_WIN7 = 6,
@@ -28,6 +30,37 @@ Version GetVersion();
// Returns the major and minor version of the service pack installed.
void GetServicePackLevel(int* major, int* minor);
+enum WindowsArchitecture {
+ X86_ARCHITECTURE,
+ X64_ARCHITECTURE,
+ IA64_ARCHITECTURE,
+ OTHER_ARCHITECTURE,
+};
+
+// Returns the processor architecture this copy of Windows natively uses.
+// For example, given an x64-capable processor, we have three possibilities:
+// 32-bit Chrome running on 32-bit Windows: X86_ARCHITECTURE
+// 32-bit Chrome running on 64-bit Windows via WOW64: X64_ARCHITECTURE
+// 64-bit Chrome running on 64-bit Windows: X64_ARCHITECTURE
+WindowsArchitecture GetWindowsArchitecture();
+
+enum WOW64Status {
+ WOW64_DISABLED,
+ WOW64_ENABLED,
+ WOW64_UNKNOWN,
+};
+
+// Returns whether this process is running under WOW64 (the wrapper that allows
+// 32-bit processes to run on 64-bit versions of Windows). This will return
+// WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit Chrome
+// on 64-bit Windows". WOW64_UNKNOWN means "an error occurred", e.g. the
+// process does not have sufficient access rights to determine this.
+WOW64Status GetWOW64Status();
+
+// Like GetWOW64Status(), but for the supplied handle instead of the current
+// process.
+WOW64Status GetWOW64StatusForProcess(HANDLE process_handle);
+
} // namespace win
} // namespace base