diff options
author | Paul Westbrook <pwestbro@google.com> | 2015-11-01 15:29:33 -0800 |
---|---|---|
committer | Paul Westbrook <pwestbro@google.com> | 2015-11-02 18:55:30 +0000 |
commit | 5a1f600e9d7d26c36b3e22ff0dc0ae9e3b2425fc (patch) | |
tree | 9a3a96971d8c687c1a1976dc9abf49dd8d3c62f2 /third_party | |
parent | 1bc421c9ef13ad855a3f749143fa8c4bc568ef16 (diff) | |
download | libweave-5a1f600e9d7d26c36b3e22ff0dc0ae9e3b2425fc.tar.gz |
Remove the unneeded libweave directory
Change-Id: I30fd8c5626cf83da6415ffa14a2019ef43be9916
Reviewed-on: https://weave-review.googlesource.com/1450
Reviewed-by: Paul Westbrook <pwestbro@google.com>
Diffstat (limited to 'third_party')
122 files changed, 32539 insertions, 0 deletions
diff --git a/third_party/chromium/LICENSE b/third_party/chromium/LICENSE new file mode 100644 index 0000000..a32e00c --- /dev/null +++ b/third_party/chromium/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/chromium/LICENSE.chromium_os b/third_party/chromium/LICENSE.chromium_os new file mode 100644 index 0000000..0aa7fc9 --- /dev/null +++ b/third_party/chromium/LICENSE.chromium_os @@ -0,0 +1,27 @@ +// Copyright (c) 2006-2009 The Chromium OS Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/chromium/base/base_export.h b/third_party/chromium/base/base_export.h new file mode 100644 index 0000000..dc01442 --- /dev/null +++ b/third_party/chromium/base/base_export.h @@ -0,0 +1,11 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_BASE_EXPORT_H_ +#define BASE_BASE_EXPORT_H_ + +#define BASE_EXPORT __attribute__((__visibility__("default"))) +#define BASE_EXPORT_PRIVATE __attribute__((__visibility__("hidden"))) + +#endif // BASE_BASE_EXPORT_H_ diff --git a/third_party/chromium/base/basictypes.h b/third_party/chromium/base/basictypes.h new file mode 100644 index 0000000..154688d --- /dev/null +++ b/third_party/chromium/base/basictypes.h @@ -0,0 +1,45 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains definitions of our old basic integral types +// ((u)int{8,16,32,64}) and further includes. I recommend that you use the C99 +// standard types instead, and include <stdint.h>/<stddef.h>/etc. as needed. +// Note that the macros and macro-like constructs that were formerly defined in +// this file are now available separately in base/macros.h. + +#ifndef BASE_BASICTYPES_H_ +#define BASE_BASICTYPES_H_ + +#include <limits.h> // So we can set the bounds of our types. +#include <stddef.h> // For size_t. +#include <stdint.h> // For intptr_t. + +#include "base/macros.h" +#include "base/build/build_config.h" + +// DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>). +typedef int8_t int8; +typedef uint8_t uint8; +typedef int16_t int16; +typedef uint16_t uint16; +typedef int32_t int32; +typedef uint32_t uint32; +typedef int64_t int64; +typedef uint64_t uint64; + +// DEPRECATED: Please use std::numeric_limits (from <limits>) instead. +const uint8 kuint8max = 0xFF; +const uint16 kuint16max = 0xFFFF; +const uint32 kuint32max = 0xFFFFFFFF; +const uint64 kuint64max = 0xFFFFFFFFFFFFFFFFULL; +const int8 kint8min = -0x7F - 1; +const int8 kint8max = 0x7F; +const int16 kint16min = -0x7FFF - 1; +const int16 kint16max = 0x7FFF; +const int32 kint32min = -0x7FFFFFFF - 1; +const int32 kint32max = 0x7FFFFFFF; +const int64 kint64min = -0x7FFFFFFFFFFFFFFFLL - 1; +const int64 kint64max = 0x7FFFFFFFFFFFFFFFLL; + +#endif // BASE_BASICTYPES_H_ diff --git a/third_party/chromium/base/bind.h b/third_party/chromium/base/bind.h new file mode 100644 index 0000000..51be10d --- /dev/null +++ b/third_party/chromium/base/bind.h @@ -0,0 +1,118 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_BIND_H_ +#define BASE_BIND_H_ + +#include "base/bind_internal.h" +#include "base/callback_internal.h" + +// ----------------------------------------------------------------------------- +// Usage documentation +// ----------------------------------------------------------------------------- +// +// See base/callback.h for documentation. +// +// +// ----------------------------------------------------------------------------- +// Implementation notes +// ----------------------------------------------------------------------------- +// +// If you're reading the implementation, before proceeding further, you should +// read the top comment of base/bind_internal.h for a definition of common +// terms and concepts. +// +// RETURN TYPES +// +// Though Bind()'s result is meant to be stored in a Callback<> type, it +// cannot actually return the exact type without requiring a large amount +// of extra template specializations. The problem is that in order to +// discern the correct specialization of Callback<>, Bind would need to +// unwrap the function signature to determine the signature's arity, and +// whether or not it is a method. +// +// Each unique combination of (arity, function_type, num_prebound) where +// function_type is one of {function, method, const_method} would require +// one specialization. We eventually have to do a similar number of +// specializations anyways in the implementation (see the Invoker<>, +// classes). However, it is avoidable in Bind if we return the result +// via an indirection like we do below. +// +// TODO(ajwong): We might be able to avoid this now, but need to test. +// +// It is possible to move most of the static_assert into BindState<>, but it +// feels a little nicer to have the asserts here so people do not need to crack +// open bind_internal.h. On the other hand, it makes Bind() harder to read. + +namespace base { + +template <typename Functor> +base::Callback< + typename internal::BindState< + typename internal::FunctorTraits<Functor>::RunnableType, + typename internal::FunctorTraits<Functor>::RunType, + internal::TypeList<>>::UnboundRunType> +Bind(Functor functor) { + // Typedefs for how to store and run the functor. + typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType; + typedef typename internal::FunctorTraits<Functor>::RunType RunType; + + typedef internal::BindState<RunnableType, RunType, + internal::TypeList<>> BindState; + + return Callback<typename BindState::UnboundRunType>( + new BindState(internal::MakeRunnable(functor))); +} + +template <typename Functor, typename... Args> +base::Callback< + typename internal::BindState< + typename internal::FunctorTraits<Functor>::RunnableType, + typename internal::FunctorTraits<Functor>::RunType, + internal::TypeList< + typename internal::CallbackParamTraits<Args>::StorageType...>> + ::UnboundRunType> +Bind(Functor functor, const Args&... args) { + // Typedefs for how to store and run the functor. + typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType; + typedef typename internal::FunctorTraits<Functor>::RunType RunType; + + // Use RunnableType::RunType instead of RunType above because our + // checks should below for bound references need to know what the actual + // functor is going to interpret the argument as. + typedef typename RunnableType::RunType BoundRunType; + + // Do not allow binding a non-const reference parameter. Non-const reference + // parameters are disallowed by the Google style guide. Also, binding a + // non-const reference parameter can make for subtle bugs because the + // invoked function will receive a reference to the stored copy of the + // argument and not the original. + static_assert(!internal::HasNonConstReferenceParam<BoundRunType>::value, + "do_not_bind_functions_with_nonconst_ref"); + + const bool is_method = internal::HasIsMethodTag<RunnableType>::value; + + // For methods, we need to be careful for parameter 1. We do not require + // a scoped_refptr because BindState<> itself takes care of AddRef() for + // methods. We also disallow binding of an array as the method's target + // object. + static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value, + "first_bound_argument_to_method_cannot_be_array"); + static_assert( + !internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value, + "a_parameter_is_refcounted_type_and_needs_scoped_refptr"); + + typedef internal::BindState< + RunnableType, RunType, + internal::TypeList< + typename internal::CallbackParamTraits<Args>::StorageType...>> + BindState; + + return Callback<typename BindState::UnboundRunType>( + new BindState(internal::MakeRunnable(functor), args...)); +} + +} // namespace base + +#endif // BASE_BIND_H_ diff --git a/third_party/chromium/base/bind_helpers.cc b/third_party/chromium/base/bind_helpers.cc new file mode 100644 index 0000000..f1fe46d --- /dev/null +++ b/third_party/chromium/base/bind_helpers.cc @@ -0,0 +1,14 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind_helpers.h" + +#include "base/callback.h" + +namespace base { + +void DoNothing() { +} + +} // namespace base diff --git a/third_party/chromium/base/bind_helpers.h b/third_party/chromium/base/bind_helpers.h new file mode 100644 index 0000000..5044a1c --- /dev/null +++ b/third_party/chromium/base/bind_helpers.h @@ -0,0 +1,710 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This defines a set of argument wrappers and related factory methods that +// can be used specify the refcounting and reference semantics of arguments +// that are bound by the Bind() function in base/bind.h. +// +// It also defines a set of simple functions and utilities that people want +// when using Callback<> and Bind(). +// +// +// ARGUMENT BINDING WRAPPERS +// +// The wrapper functions are base::Unretained(), base::Owned(), base::Passed(), +// base::ConstRef(), and base::IgnoreResult(). +// +// Unretained() allows Bind() to bind a non-refcounted class, and to disable +// refcounting on arguments that are refcounted objects. +// +// Owned() transfers ownership of an object to the Callback resulting from +// bind; the object will be deleted when the Callback is deleted. +// +// Passed() is for transferring movable-but-not-copyable types (eg. scoped_ptr) +// through a Callback. Logically, this signifies a destructive transfer of +// the state of the argument into the target function. Invoking +// Callback::Run() twice on a Callback that was created with a Passed() +// argument will CHECK() because the first invocation would have already +// transferred ownership to the target function. +// +// ConstRef() allows binding a constant reference to an argument rather +// than a copy. +// +// IgnoreResult() is used to adapt a function or Callback with a return type to +// one with a void return. This is most useful if you have a function with, +// say, a pesky ignorable bool return that you want to use with PostTask or +// something else that expect a Callback with a void return. +// +// EXAMPLE OF Unretained(): +// +// class Foo { +// public: +// void func() { cout << "Foo:f" << endl; } +// }; +// +// // In some function somewhere. +// Foo foo; +// Closure foo_callback = +// Bind(&Foo::func, Unretained(&foo)); +// foo_callback.Run(); // Prints "Foo:f". +// +// Without the Unretained() wrapper on |&foo|, the above call would fail +// to compile because Foo does not support the AddRef() and Release() methods. +// +// +// EXAMPLE OF Owned(): +// +// void foo(int* arg) { cout << *arg << endl } +// +// int* pn = new int(1); +// Closure foo_callback = Bind(&foo, Owned(pn)); +// +// foo_callback.Run(); // Prints "1" +// foo_callback.Run(); // Prints "1" +// *n = 2; +// foo_callback.Run(); // Prints "2" +// +// foo_callback.Reset(); // |pn| is deleted. Also will happen when +// // |foo_callback| goes out of scope. +// +// Without Owned(), someone would have to know to delete |pn| when the last +// reference to the Callback is deleted. +// +// +// EXAMPLE OF ConstRef(): +// +// void foo(int arg) { cout << arg << endl } +// +// int n = 1; +// Closure no_ref = Bind(&foo, n); +// Closure has_ref = Bind(&foo, ConstRef(n)); +// +// no_ref.Run(); // Prints "1" +// has_ref.Run(); // Prints "1" +// +// n = 2; +// no_ref.Run(); // Prints "1" +// has_ref.Run(); // Prints "2" +// +// Note that because ConstRef() takes a reference on |n|, |n| must outlive all +// its bound callbacks. +// +// +// EXAMPLE OF IgnoreResult(): +// +// int DoSomething(int arg) { cout << arg << endl; } +// +// // Assign to a Callback with a void return type. +// Callback<void(int)> cb = Bind(IgnoreResult(&DoSomething)); +// cb->Run(1); // Prints "1". +// +// // Prints "1" on |ml|. +// ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1); +// +// +// EXAMPLE OF Passed(): +// +// void TakesOwnership(scoped_ptr<Foo> arg) { } +// scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); } +// +// scoped_ptr<Foo> f(new Foo()); +// +// // |cb| is given ownership of Foo(). |f| is now NULL. +// // You can use f.Pass() in place of &f, but it's more verbose. +// Closure cb = Bind(&TakesOwnership, Passed(&f)); +// +// // Run was never called so |cb| still owns Foo() and deletes +// // it on Reset(). +// cb.Reset(); +// +// // |cb| is given a new Foo created by CreateFoo(). +// cb = Bind(&TakesOwnership, Passed(CreateFoo())); +// +// // |arg| in TakesOwnership() is given ownership of Foo(). |cb| +// // no longer owns Foo() and, if reset, would not delete Foo(). +// cb.Run(); // Foo() is now transferred to |arg| and deleted. +// cb.Run(); // This CHECK()s since Foo() already been used once. +// +// Passed() is particularly useful with PostTask() when you are transferring +// ownership of an argument into a task, but don't necessarily know if the +// task will always be executed. This can happen if the task is cancellable +// or if it is posted to a TaskRunner. +// +// +// SIMPLE FUNCTIONS AND UTILITIES. +// +// DoNothing() - Useful for creating a Closure that does nothing when called. +// DeletePointer<T>() - Useful for creating a Closure that will delete a +// pointer when invoked. Only use this when necessary. +// In most cases MessageLoop::DeleteSoon() is a better +// fit. + +#ifndef BASE_BIND_HELPERS_H_ +#define BASE_BIND_HELPERS_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "base/template_util.h" + +namespace base { +namespace internal { + +// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T +// for the existence of AddRef() and Release() functions of the correct +// signature. +// +// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error +// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence +// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison +// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions +// +// The last link in particular show the method used below. +// +// For SFINAE to work with inherited methods, we need to pull some extra tricks +// with multiple inheritance. In the more standard formulation, the overloads +// of Check would be: +// +// template <typename C> +// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*); +// +// template <typename C> +// No NotTheCheckWeWant(...); +// +// static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes); +// +// The problem here is that template resolution will not match +// C::TargetFunc if TargetFunc does not exist directly in C. That is, if +// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match, +// |value| will be false. This formulation only checks for whether or +// not TargetFunc exist directly in the class being introspected. +// +// To get around this, we play a dirty trick with multiple inheritance. +// First, We create a class BaseMixin that declares each function that we +// want to probe for. Then we create a class Base that inherits from both T +// (the class we wish to probe) and BaseMixin. Note that the function +// signature in BaseMixin does not need to match the signature of the function +// we are probing for; thus it's easiest to just use void(void). +// +// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an +// ambiguous resolution between BaseMixin and T. This lets us write the +// following: +// +// template <typename C> +// No GoodCheck(Helper<&C::TargetFunc>*); +// +// template <typename C> +// Yes GoodCheck(...); +// +// static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes); +// +// Notice here that the variadic version of GoodCheck() returns Yes here +// instead of No like the previous one. Also notice that we calculate |value| +// by specializing GoodCheck() on Base instead of T. +// +// We've reversed the roles of the variadic, and Helper overloads. +// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid +// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve +// to the variadic version if T has TargetFunc. If T::TargetFunc does not +// exist, then &C::TargetFunc is not ambiguous, and the overload resolution +// will prefer GoodCheck(Helper<&C::TargetFunc>*). +// +// This method of SFINAE will correctly probe for inherited names, but it cannot +// typecheck those names. It's still a good enough sanity check though. +// +// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008. +// +// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted +// this works well. +// +// TODO(ajwong): Make this check for Release() as well. +// See http://crbug.com/82038. +template <typename T> +class SupportsAddRefAndRelease { + typedef char Yes[1]; + typedef char No[2]; + + struct BaseMixin { + void AddRef(); + }; + +// MSVC warns when you try to use Base if T has a private destructor, the +// common pattern for refcounted types. It does this even though no attempt to +// instantiate Base is made. We disable the warning for this definition. +#if defined(OS_WIN) +#pragma warning(push) +#pragma warning(disable:4624) +#endif + struct Base : public T, public BaseMixin { + }; +#if defined(OS_WIN) +#pragma warning(pop) +#endif + + template <void(BaseMixin::*)(void)> struct Helper {}; + + template <typename C> + static No& Check(Helper<&C::AddRef>*); + + template <typename > + static Yes& Check(...); + + public: + enum { value = sizeof(Check<Base>(0)) == sizeof(Yes) }; +}; + +// Helpers to assert that arguments of a recounted type are bound with a +// scoped_refptr. +template <bool IsClasstype, typename T> +struct UnsafeBindtoRefCountedArgHelper : std::false_type { +}; + +template <typename T> +struct UnsafeBindtoRefCountedArgHelper<true, T> + : std::integral_constant<bool, SupportsAddRefAndRelease<T>::value> { +}; + +template <typename T> +struct UnsafeBindtoRefCountedArg : std::false_type { +}; + +template <typename T> +struct UnsafeBindtoRefCountedArg<T*> + : UnsafeBindtoRefCountedArgHelper<std::is_class<T>::value, T> { +}; + +template <typename T> +class HasIsMethodTag { + typedef char Yes[1]; + typedef char No[2]; + + template <typename U> + static Yes& Check(typename U::IsMethod*); + + template <typename U> + static No& Check(...); + + public: + enum { value = sizeof(Check<T>(0)) == sizeof(Yes) }; +}; + +template <typename T> +class UnretainedWrapper { + public: + explicit UnretainedWrapper(T* o) : ptr_(o) {} + T* get() const { return ptr_; } + private: + T* ptr_; +}; + +template <typename T> +class ConstRefWrapper { + public: + explicit ConstRefWrapper(const T& o) : ptr_(&o) {} + const T& get() const { return *ptr_; } + private: + const T* ptr_; +}; + +template <typename T> +struct IgnoreResultHelper { + explicit IgnoreResultHelper(T functor) : functor_(functor) {} + + T functor_; +}; + +template <typename T> +struct IgnoreResultHelper<Callback<T> > { + explicit IgnoreResultHelper(const Callback<T>& functor) : functor_(functor) {} + + const Callback<T>& functor_; +}; + +// An alternate implementation is to avoid the destructive copy, and instead +// specialize ParamTraits<> for OwnedWrapper<> to change the StorageType to +// a class that is essentially a scoped_ptr<>. +// +// The current implementation has the benefit though of leaving ParamTraits<> +// fully in callback_internal.h as well as avoiding type conversions during +// storage. +template <typename T> +class OwnedWrapper { + public: + explicit OwnedWrapper(T* o) : ptr_(o) {} + ~OwnedWrapper() { delete ptr_; } + T* get() const { return ptr_; } + OwnedWrapper(const OwnedWrapper& other) { + ptr_ = other.ptr_; + other.ptr_ = NULL; + } + + private: + mutable T* ptr_; +}; + +// PassedWrapper is a copyable adapter for a scoper that ignores const. +// +// It is needed to get around the fact that Bind() takes a const reference to +// all its arguments. Because Bind() takes a const reference to avoid +// unnecessary copies, it is incompatible with movable-but-not-copyable +// types; doing a destructive "move" of the type into Bind() would violate +// the const correctness. +// +// This conundrum cannot be solved without either C++11 rvalue references or +// a O(2^n) blowup of Bind() templates to handle each combination of regular +// types and movable-but-not-copyable types. Thus we introduce a wrapper type +// that is copyable to transmit the correct type information down into +// BindState<>. Ignoring const in this type makes sense because it is only +// created when we are explicitly trying to do a destructive move. +// +// Two notes: +// 1) PassedWrapper supports any type that has a "Pass()" function. +// This is intentional. The whitelisting of which specific types we +// support is maintained by CallbackParamTraits<>. +// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL" +// scoper to a Callback and allow the Callback to execute once. +template <typename T> +class PassedWrapper { + public: + explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {} + PassedWrapper(const PassedWrapper& other) + : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) { + } + T Pass() const { + CHECK(is_valid_); + is_valid_ = false; + return scoper_.Pass(); + } + + private: + mutable bool is_valid_; + mutable T scoper_; +}; + +// Specialize PassedWrapper for std::unique_ptr used by base::Passed(). +// Use std::move() to transfer the data from one storage to another. +template <typename T, typename D> +class PassedWrapper<std::unique_ptr<T, D>> { + public: + explicit PassedWrapper(std::unique_ptr<T, D> scoper) + : is_valid_(true), scoper_(std::move(scoper)) {} + PassedWrapper(const PassedWrapper& other) + : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {} + + std::unique_ptr<T, D> Pass() const { + CHECK(is_valid_); + is_valid_ = false; + return std::move(scoper_); + } + + private: + mutable bool is_valid_; + mutable std::unique_ptr<T, D> scoper_; +}; + +// Specialize PassedWrapper for std::vector<std::unique_ptr<T>>. +template <typename T, typename D, typename A> +class PassedWrapper<std::vector<std::unique_ptr<T, D>, A>> { + public: + explicit PassedWrapper(std::vector<std::unique_ptr<T, D>, A> scoper) + : is_valid_(true), scoper_(std::move(scoper)) {} + PassedWrapper(const PassedWrapper& other) + : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {} + + std::vector<std::unique_ptr<T, D>, A> Pass() const { + CHECK(is_valid_); + is_valid_ = false; + return std::move(scoper_); + } + + private: + mutable bool is_valid_; + mutable std::vector<std::unique_ptr<T, D>, A> scoper_; +}; + +// Specialize PassedWrapper for std::map<K, std::unique_ptr<T>>. +template <typename K, typename T, typename D, typename C, typename A> +class PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>> { + public: + explicit PassedWrapper(std::map<K, std::unique_ptr<T, D>, C, A> scoper) + : is_valid_(true), scoper_(std::move(scoper)) {} + PassedWrapper(const PassedWrapper& other) + : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {} + + std::map<K, std::unique_ptr<T, D>, C, A> Pass() const { + CHECK(is_valid_); + is_valid_ = false; + return std::move(scoper_); + } + + private: + mutable bool is_valid_; + mutable std::map<K, std::unique_ptr<T, D>, C, A> scoper_; +}; + +// Unwrap the stored parameters for the wrappers above. +template <typename T> +struct UnwrapTraits { + typedef const T& ForwardType; + static ForwardType Unwrap(const T& o) { return o; } +}; + +template <typename T> +struct UnwrapTraits<UnretainedWrapper<T> > { + typedef T* ForwardType; + static ForwardType Unwrap(UnretainedWrapper<T> unretained) { + return unretained.get(); + } +}; + +template <typename T> +struct UnwrapTraits<ConstRefWrapper<T> > { + typedef const T& ForwardType; + static ForwardType Unwrap(ConstRefWrapper<T> const_ref) { + return const_ref.get(); + } +}; + +template <typename T> +struct UnwrapTraits<scoped_refptr<T> > { + typedef T* ForwardType; + static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); } +}; + +template <typename T> +struct UnwrapTraits<WeakPtr<T> > { + typedef const WeakPtr<T>& ForwardType; + static ForwardType Unwrap(const WeakPtr<T>& o) { return o; } +}; + +template <typename T> +struct UnwrapTraits<OwnedWrapper<T> > { + typedef T* ForwardType; + static ForwardType Unwrap(const OwnedWrapper<T>& o) { + return o.get(); + } +}; + +template <typename T> +struct UnwrapTraits<PassedWrapper<T> > { + typedef T ForwardType; + static T Unwrap(PassedWrapper<T>& o) { + return o.Pass(); + } +}; + +// Utility for handling different refcounting semantics in the Bind() +// function. +template <bool is_method, typename... T> +struct MaybeScopedRefPtr; + +template <bool is_method> +struct MaybeScopedRefPtr<is_method> { + MaybeScopedRefPtr() {} +}; + +template <typename T, typename... Rest> +struct MaybeScopedRefPtr<false, T, Rest...> { + MaybeScopedRefPtr(const T&, const Rest&...) {} +}; + +template <typename T, size_t n, typename... Rest> +struct MaybeScopedRefPtr<false, T[n], Rest...> { + MaybeScopedRefPtr(const T*, const Rest&...) {} +}; + +template <typename T, typename... Rest> +struct MaybeScopedRefPtr<true, T, Rest...> { + MaybeScopedRefPtr(const T& o, const Rest&...) {} +}; + +template <typename T, typename... Rest> +struct MaybeScopedRefPtr<true, T*, Rest...> { + MaybeScopedRefPtr(T* o, const Rest&...) : ref_(o) {} + scoped_refptr<T> ref_; +}; + +// No need to additionally AddRef() and Release() since we are storing a +// scoped_refptr<> inside the storage object already. +template <typename T, typename... Rest> +struct MaybeScopedRefPtr<true, scoped_refptr<T>, Rest...> { + MaybeScopedRefPtr(const scoped_refptr<T>&, const Rest&...) {} +}; + +template <typename T, typename... Rest> +struct MaybeScopedRefPtr<true, const T*, Rest...> { + MaybeScopedRefPtr(const T* o, const Rest&...) : ref_(o) {} + scoped_refptr<const T> ref_; +}; + +// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a +// method. It is used internally by Bind() to select the correct +// InvokeHelper that will no-op itself in the event the WeakPtr<> for +// the target object is invalidated. +// +// The first argument should be the type of the object that will be received by +// the method. +template <bool IsMethod, typename... Args> +struct IsWeakMethod : public std::false_type {}; + +template <typename T, typename... Args> +struct IsWeakMethod<true, WeakPtr<T>, Args...> : public std::true_type {}; + +template <typename T, typename... Args> +struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T>>, Args...> + : public std::true_type {}; + + +// Packs a list of types to hold them in a single type. +template <typename... Types> +struct TypeList {}; + +// Used for DropTypeListItem implementation. +template <size_t n, typename List> +struct DropTypeListItemImpl; + +// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure. +template <size_t n, typename T, typename... List> +struct DropTypeListItemImpl<n, TypeList<T, List...>> + : DropTypeListItemImpl<n - 1, TypeList<List...>> {}; + +template <typename T, typename... List> +struct DropTypeListItemImpl<0, TypeList<T, List...>> { + typedef TypeList<T, List...> Type; +}; + +template <> +struct DropTypeListItemImpl<0, TypeList<>> { + typedef TypeList<> Type; +}; + +// A type-level function that drops |n| list item from given TypeList. +template <size_t n, typename List> +using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type; + +// Used for ConcatTypeLists implementation. +template <typename List1, typename List2> +struct ConcatTypeListsImpl; + +template <typename... Types1, typename... Types2> +struct ConcatTypeListsImpl<TypeList<Types1...>, TypeList<Types2...>> { + typedef TypeList<Types1..., Types2...> Type; +}; + +// A type-level function that concats two TypeLists. +template <typename List1, typename List2> +using ConcatTypeLists = typename ConcatTypeListsImpl<List1, List2>::Type; + +// Used for MakeFunctionType implementation. +template <typename R, typename ArgList> +struct MakeFunctionTypeImpl; + +template <typename R, typename... Args> +struct MakeFunctionTypeImpl<R, TypeList<Args...>> { + typedef R(Type)(Args...); +}; + +// A type-level function that constructs a function type that has |R| as its +// return type and has TypeLists items as its arguments. +template <typename R, typename ArgList> +using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type; + +} // namespace internal + +template <typename T> +static inline internal::UnretainedWrapper<T> Unretained(T* o) { + return internal::UnretainedWrapper<T>(o); +} + +template <typename T> +static inline internal::ConstRefWrapper<T> ConstRef(const T& o) { + return internal::ConstRefWrapper<T>(o); +} + +template <typename T> +static inline internal::OwnedWrapper<T> Owned(T* o) { + return internal::OwnedWrapper<T>(o); +} + +// We offer 2 syntaxes for calling Passed(). The first takes a temporary and +// is best suited for use with the return value of a function. The second +// takes a pointer to the scoper and is just syntactic sugar to avoid having +// to write Passed(scoper.Pass()). +template <typename T> +static inline internal::PassedWrapper<T> Passed(T scoper) { + return internal::PassedWrapper<T>(scoper.Pass()); +} +template <typename T> +static inline internal::PassedWrapper<T> Passed(T* scoper) { + return internal::PassedWrapper<T>(scoper->Pass()); +} + +// Overload base::Passed() for std::unique_ptr<T>. +template <typename T> +static inline internal::PassedWrapper<std::unique_ptr<T>> +Passed(std::unique_ptr<T>* scoper) { + return internal::PassedWrapper<std::unique_ptr<T>>(std::move(*scoper)); +} + +template <typename T> +static inline internal::PassedWrapper<std::unique_ptr<T>> +Passed(std::unique_ptr<T> scoper) { + return internal::PassedWrapper<std::unique_ptr<T>>(std::move(scoper)); +} + +// Overload base::Passed() for std::vector<std::unique_ptr<T>>. +template <typename T, typename D, typename A> +static inline internal::PassedWrapper<std::vector<std::unique_ptr<T, D>, A>> +Passed(std::vector<std::unique_ptr<T, D>, A>* scoper) { + return internal::PassedWrapper<std::vector<std::unique_ptr<T, D>, A>>( + std::move(*scoper)); +} + +template <typename T, typename D, typename A> +static inline internal::PassedWrapper<std::vector<std::unique_ptr<T, D>, A>> +Passed(std::vector<std::unique_ptr<T, D>, A> scoper) { + return internal::PassedWrapper<std::vector<std::unique_ptr<T, D>, A>>( + std::move(scoper)); +} + +// Overload base::Passed() for std::map<K, std::unique_ptr<T>>. +template <typename K, typename T, typename D, typename C, typename A> +static inline internal::PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>> +Passed(std::map<K, std::unique_ptr<T, D>, C, A>* scoper) { + return internal::PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>>( + std::move(*scoper)); +} + +template <typename K, typename T, typename D, typename C, typename A> +static inline internal::PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>> +Passed(std::map<K, std::unique_ptr<T, D>, C, A> scoper) { + return internal::PassedWrapper<std::map<K, std::unique_ptr<T, D>, C, A>>( + std::move(scoper)); +} + +template <typename T> +static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) { + return internal::IgnoreResultHelper<T>(data); +} + +template <typename T> +static inline internal::IgnoreResultHelper<Callback<T> > +IgnoreResult(const Callback<T>& data) { + return internal::IgnoreResultHelper<Callback<T> >(data); +} + +void DoNothing(); + +template<typename T> +void DeletePointer(T* obj) { + delete obj; +} + +} // namespace base + +#endif // BASE_BIND_HELPERS_H_ diff --git a/third_party/chromium/base/bind_internal.h b/third_party/chromium/base/bind_internal.h new file mode 100644 index 0000000..6d500a5 --- /dev/null +++ b/third_party/chromium/base/bind_internal.h @@ -0,0 +1,412 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_BIND_INTERNAL_H_ +#define BASE_BIND_INTERNAL_H_ + +#include "base/bind_helpers.h" +#include "base/build/build_config.h" +#include "base/callback_internal.h" +#include "base/memory/weak_ptr.h" +#include "base/template_util.h" +#include "base/tuple.h" + +#if defined(OS_WIN) +#include "base/bind_internal_win.h" +#endif + +namespace base { +namespace internal { + +// See base/callback.h for user documentation. +// +// +// CONCEPTS: +// Runnable -- A type (really a type class) that has a single Run() method +// and a RunType typedef that corresponds to the type of Run(). +// A Runnable can declare that it should treated like a method +// call by including a typedef named IsMethod. The value of +// this typedef is NOT inspected, only the existence. When a +// Runnable declares itself a method, Bind() will enforce special +// refcounting + WeakPtr handling semantics for the first +// parameter which is expected to be an object. +// Functor -- A copyable type representing something that should be called. +// All function pointers, Callback<>, and Runnables are functors +// even if the invocation syntax differs. +// RunType -- A function type (as opposed to function _pointer_ type) for +// a Run() function. Usually just a convenience typedef. +// (Bound)ArgsType -- A function type that is being (ab)used to store the +// types of set of arguments. The "return" type is always +// void here. We use this hack so that we do not need +// a new type name for each arity of type. (eg., +// BindState1, BindState2). This makes forward +// declarations and friending much much easier. +// +// Types: +// RunnableAdapter<> -- Wraps the various "function" pointer types into an +// object that adheres to the Runnable interface. +// ForceVoidReturn<> -- Helper class for translating function signatures to +// equivalent forms with a "void" return type. +// FunctorTraits<> -- Type traits used determine the correct RunType and +// RunnableType for a Functor. This is where function +// signature adapters are applied. +// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable +// type class that represents the underlying Functor. +// There are |O(1)| MakeRunnable types. +// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it. +// Handle the differing syntaxes needed for WeakPtr<> +// support, and for ignoring return values. This is separate +// from Invoker to avoid creating multiple version of +// Invoker<>. +// Invoker<> -- Unwraps the curried parameters and executes the Runnable. +// BindState<> -- Stores the curried parameters, and is the main entry point +// into the Bind() system, doing most of the type resolution. +// There are ARITY BindState types. + +// HasNonConstReferenceParam selects true_type when any of the parameters in +// |Sig| is a non-const reference. +// Implementation note: This non-specialized case handles zero-arity case only. +// Non-zero-arity cases should be handled by the specialization below. +template <typename Sig> +struct HasNonConstReferenceParam : std::false_type {}; + +// Implementation note: Select true_type if the first parameter is a non-const +// reference. Otherwise, skip the first parameter and check rest of parameters +// recursively. +template <typename R, typename T, typename... Args> +struct HasNonConstReferenceParam<R(T, Args...)> + : SelectType<is_non_const_reference<T>::value, + std::true_type, + HasNonConstReferenceParam<R(Args...)>>::Type {}; + +// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw +// pointer to a RefCounted type. +// Implementation note: This non-specialized case handles zero-arity case only. +// Non-zero-arity cases should be handled by the specialization below. +template <typename... Args> +struct HasRefCountedTypeAsRawPtr : std::false_type {}; + +// BindsArrayToFirstArg selects true_type when |is_method| is true and the first +// item of |Args| is an array type. +// Implementation note: This non-specialized case handles !is_method case and +// zero-arity case only. Other cases should be handled by the specialization +// below. +template <bool is_method, typename... Args> +struct BindsArrayToFirstArg : std::false_type {}; + +template <typename T, typename... Args> +struct BindsArrayToFirstArg<true, T, Args...> : std::is_array<T> {}; + +// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except +// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument. +// Implementation note: This non-specialized case handles !is_method case and +// zero-arity case only. Other cases should be handled by the specialization +// below. +template <bool is_method, typename... Args> +struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr<Args...> {}; + +template <typename T, typename... Args> +struct HasRefCountedParamAsRawPtr<true, T, Args...> + : HasRefCountedTypeAsRawPtr<Args...> {}; + +// RunnableAdapter<> +// +// The RunnableAdapter<> templates provide a uniform interface for invoking +// a function pointer, method pointer, or const method pointer. The adapter +// exposes a Run() method with an appropriate signature. Using this wrapper +// allows for writing code that supports all three pointer types without +// undue repetition. Without it, a lot of code would need to be repeated 3 +// times. +// +// For method pointers and const method pointers the first argument to Run() +// is considered to be the received of the method. This is similar to STL's +// mem_fun(). +// +// This class also exposes a RunType typedef that is the function type of the +// Run() function. +// +// If and only if the wrapper contains a method or const method pointer, an +// IsMethod typedef is exposed. The existence of this typedef (NOT the value) +// marks that the wrapper should be considered a method wrapper. + +template <typename Functor> +class RunnableAdapter; + +// Function. +template <typename R, typename... Args> +class RunnableAdapter<R(*)(Args...)> { + public: + typedef R (RunType)(Args...); + + explicit RunnableAdapter(R(*function)(Args...)) + : function_(function) { + } + + R Run(typename CallbackParamTraits<Args>::ForwardType... args) { + return function_(CallbackForward(args)...); + } + + private: + R (*function_)(Args...); +}; + +// Method. +template <typename R, typename T, typename... Args> +class RunnableAdapter<R(T::*)(Args...)> { + public: + typedef R (RunType)(T*, Args...); + typedef std::true_type IsMethod; + + explicit RunnableAdapter(R(T::*method)(Args...)) + : method_(method) { + } + + R Run(T* object, typename CallbackParamTraits<Args>::ForwardType... args) { + return (object->*method_)(CallbackForward(args)...); + } + + private: + R (T::*method_)(Args...); +}; + +// Const Method. +template <typename R, typename T, typename... Args> +class RunnableAdapter<R(T::*)(Args...) const> { + public: + typedef R (RunType)(const T*, Args...); + typedef std::true_type IsMethod; + + explicit RunnableAdapter(R(T::*method)(Args...) const) + : method_(method) { + } + + R Run(const T* object, + typename CallbackParamTraits<Args>::ForwardType... args) { + return (object->*method_)(CallbackForward(args)...); + } + + private: + R (T::*method_)(Args...) const; +}; + + +// ForceVoidReturn<> +// +// Set of templates that support forcing the function return type to void. +template <typename Sig> +struct ForceVoidReturn; + +template <typename R, typename... Args> +struct ForceVoidReturn<R(Args...)> { + typedef void(RunType)(Args...); +}; + + +// FunctorTraits<> +// +// See description at top of file. +template <typename T> +struct FunctorTraits { + typedef RunnableAdapter<T> RunnableType; + typedef typename RunnableType::RunType RunType; +}; + +template <typename T> +struct FunctorTraits<IgnoreResultHelper<T>> { + typedef typename FunctorTraits<T>::RunnableType RunnableType; + typedef typename ForceVoidReturn< + typename RunnableType::RunType>::RunType RunType; +}; + +template <typename T> +struct FunctorTraits<Callback<T>> { + typedef Callback<T> RunnableType; + typedef typename Callback<T>::RunType RunType; +}; + + +// MakeRunnable<> +// +// Converts a passed in functor to a RunnableType using type inference. + +template <typename T> +typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) { + return RunnableAdapter<T>(t); +} + +template <typename T> +typename FunctorTraits<T>::RunnableType +MakeRunnable(const IgnoreResultHelper<T>& t) { + return MakeRunnable(t.functor_); +} + +template <typename T> +const typename FunctorTraits<Callback<T>>::RunnableType& +MakeRunnable(const Callback<T>& t) { + DCHECK(!t.is_null()); + return t; +} + + +// InvokeHelper<> +// +// There are 3 logical InvokeHelper<> specializations: normal, void-return, +// WeakCalls. +// +// The normal type just calls the underlying runnable. +// +// We need a InvokeHelper to handle void return types in order to support +// IgnoreResult(). Normally, if the Runnable's RunType had a void return, +// the template system would just accept "return functor.Run()" ignoring +// the fact that a void function is being used with return. This piece of +// sugar breaks though when the Runnable's RunType is not void. Thus, we +// need a partial specialization to change the syntax to drop the "return" +// from the invocation call. +// +// WeakCalls similarly need special syntax that is applied to the first +// argument to check if they should no-op themselves. +template <bool IsWeakCall, typename ReturnType, typename Runnable, + typename ArgsType> +struct InvokeHelper; + +template <typename ReturnType, typename Runnable, typename... Args> +struct InvokeHelper<false, ReturnType, Runnable, TypeList<Args...>> { + static ReturnType MakeItSo(Runnable runnable, Args... args) { + return runnable.Run(CallbackForward(args)...); + } +}; + +template <typename Runnable, typename... Args> +struct InvokeHelper<false, void, Runnable, TypeList<Args...>> { + static void MakeItSo(Runnable runnable, Args... args) { + runnable.Run(CallbackForward(args)...); + } +}; + +template <typename Runnable, typename BoundWeakPtr, typename... Args> +struct InvokeHelper<true, void, Runnable, TypeList<BoundWeakPtr, Args...>> { + static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) { + if (!weak_ptr.get()) { + return; + } + runnable.Run(weak_ptr.get(), CallbackForward(args)...); + } +}; + +#if !defined(_MSC_VER) + +template <typename ReturnType, typename Runnable, typename ArgsType> +struct InvokeHelper<true, ReturnType, Runnable, ArgsType> { + // WeakCalls are only supported for functions with a void return type. + // Otherwise, the function result would be undefined if the the WeakPtr<> + // is invalidated. + COMPILE_ASSERT(std::is_void<ReturnType>::value, + weak_ptrs_can_only_bind_to_methods_without_return_values); +}; + +#endif + +// Invoker<> +// +// See description at the top of the file. +template <typename BoundIndices, + typename StorageType, typename Unwrappers, + typename InvokeHelperType, typename UnboundForwardRunType> +struct Invoker; + +template <size_t... bound_indices, + typename StorageType, + typename... Unwrappers, + typename InvokeHelperType, + typename R, + typename... UnboundForwardArgs> +struct Invoker<IndexSequence<bound_indices...>, + StorageType, TypeList<Unwrappers...>, + InvokeHelperType, R(UnboundForwardArgs...)> { + static R Run(BindStateBase* base, + UnboundForwardArgs... unbound_args) { + StorageType* storage = static_cast<StorageType*>(base); + // Local references to make debugger stepping easier. If in a debugger, + // you really want to warp ahead and step through the + // InvokeHelper<>::MakeItSo() call below. + return InvokeHelperType::MakeItSo( + storage->runnable_, + Unwrappers::Unwrap(get<bound_indices>(storage->bound_args_))..., + CallbackForward(unbound_args)...); + } +}; + + +// BindState<> +// +// This stores all the state passed into Bind() and is also where most +// of the template resolution magic occurs. +// +// Runnable is the functor we are binding arguments to. +// RunType is type of the Run() function that the Invoker<> should use. +// Normally, this is the same as the RunType of the Runnable, but it can +// be different if an adapter like IgnoreResult() has been used. +// +// BoundArgsType contains the storage type for all the bound arguments by +// (ab)using a function type. +template <typename Runnable, typename RunType, typename BoundArgList> +struct BindState; + +template <typename Runnable, + typename R, + typename... Args, + typename... BoundArgs> +struct BindState<Runnable, R(Args...), TypeList<BoundArgs...>> final + : public BindStateBase { + private: + using StorageType = BindState<Runnable, R(Args...), TypeList<BoundArgs...>>; + using RunnableType = Runnable; + + // true_type if Runnable is a method invocation and the first bound argument + // is a WeakPtr. + using IsWeakCall = + IsWeakMethod<HasIsMethodTag<Runnable>::value, BoundArgs...>; + + using BoundIndices = MakeIndexSequence<sizeof...(BoundArgs)>; + using Unwrappers = TypeList<UnwrapTraits<BoundArgs>...>; + using UnboundForwardArgs = DropTypeListItem< + sizeof...(BoundArgs), + TypeList<typename CallbackParamTraits<Args>::ForwardType...>>; + using UnboundForwardRunType = MakeFunctionType<R, UnboundForwardArgs>; + + using InvokeHelperArgs = ConcatTypeLists< + TypeList<typename UnwrapTraits<BoundArgs>::ForwardType...>, + UnboundForwardArgs>; + using InvokeHelperType = + InvokeHelper<IsWeakCall::value, R, Runnable, InvokeHelperArgs>; + + using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), TypeList<Args...>>; + + public: + using InvokerType = Invoker<BoundIndices, StorageType, Unwrappers, + InvokeHelperType, UnboundForwardRunType>; + using UnboundRunType = MakeFunctionType<R, UnboundArgs>; + + BindState(const Runnable& runnable, const BoundArgs&... bound_args) + : BindStateBase(&Destroy), + runnable_(runnable), + ref_(bound_args...), + bound_args_(bound_args...) {} + + RunnableType runnable_; + MaybeScopedRefPtr<HasIsMethodTag<Runnable>::value, BoundArgs...> ref_; + Tuple<BoundArgs...> bound_args_; + + private: + ~BindState() {} + + static void Destroy(BindStateBase* self) { + delete static_cast<BindState*>(self); + } +}; + +} // namespace internal +} // namespace base + +#endif // BASE_BIND_INTERNAL_H_ diff --git a/third_party/chromium/base/bind_unittest.cc b/third_party/chromium/base/bind_unittest.cc new file mode 100644 index 0000000..d3cc79a --- /dev/null +++ b/third_party/chromium/base/bind_unittest.cc @@ -0,0 +1,830 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" + +using ::testing::Mock; +using ::testing::Return; +using ::testing::StrictMock; + +namespace base { +namespace { + +class IncompleteType; + +class NoRef { + public: + NoRef() {} + + MOCK_METHOD0(VoidMethod0, void(void)); + MOCK_CONST_METHOD0(VoidConstMethod0, void(void)); + + MOCK_METHOD0(IntMethod0, int(void)); + MOCK_CONST_METHOD0(IntConstMethod0, int(void)); + + private: + // Particularly important in this test to ensure no copies are made. + DISALLOW_COPY_AND_ASSIGN(NoRef); +}; + +class HasRef : public NoRef { + public: + HasRef() {} + + MOCK_CONST_METHOD0(AddRef, void(void)); + MOCK_CONST_METHOD0(Release, bool(void)); + + private: + // Particularly important in this test to ensure no copies are made. + DISALLOW_COPY_AND_ASSIGN(HasRef); +}; + +class HasRefPrivateDtor : public HasRef { + private: + ~HasRefPrivateDtor() {} +}; + +static const int kParentValue = 1; +static const int kChildValue = 2; + +class Parent { + public: + void AddRef(void) const {} + void Release(void) const {} + virtual void VirtualSet() { value = kParentValue; } + void NonVirtualSet() { value = kParentValue; } + int value; +}; + +class Child : public Parent { + public: + void VirtualSet() override { value = kChildValue; } + void NonVirtualSet() { value = kChildValue; } +}; + +class NoRefParent { + public: + virtual void VirtualSet() { value = kParentValue; } + void NonVirtualSet() { value = kParentValue; } + int value; +}; + +class NoRefChild : public NoRefParent { + void VirtualSet() override { value = kChildValue; } + void NonVirtualSet() { value = kChildValue; } +}; + +// Used for probing the number of copies that occur if a type must be coerced +// during argument forwarding in the Run() methods. +struct DerivedCopyCounter { + DerivedCopyCounter(int* copies, int* assigns) + : copies_(copies), assigns_(assigns) { + } + int* copies_; + int* assigns_; +}; + +// Used for probing the number of copies in an argument. +class CopyCounter { + public: + CopyCounter(int* copies, int* assigns) + : copies_(copies), assigns_(assigns) { + } + + CopyCounter(const CopyCounter& other) + : copies_(other.copies_), + assigns_(other.assigns_) { + (*copies_)++; + } + + // Probing for copies from coercion. + explicit CopyCounter(const DerivedCopyCounter& other) + : copies_(other.copies_), + assigns_(other.assigns_) { + (*copies_)++; + } + + const CopyCounter& operator=(const CopyCounter& rhs) { + copies_ = rhs.copies_; + assigns_ = rhs.assigns_; + + if (assigns_) { + (*assigns_)++; + } + + return *this; + } + + int copies() const { + return *copies_; + } + + private: + int* copies_; + int* assigns_; +}; + +class DeleteCounter { + public: + explicit DeleteCounter(int* deletes) + : deletes_(deletes) { + } + + ~DeleteCounter() { + (*deletes_)++; + } + + void VoidMethod0() {} + + private: + int* deletes_; +}; + +template <typename T> +T PassThru(T scoper) { + return scoper.Pass(); +} + +// Some test functions that we can Bind to. +template <typename T> +T PolymorphicIdentity(T t) { + return t; +} + +template <typename T> +void VoidPolymorphic1(T t) { +} + +int Identity(int n) { + return n; +} + +int ArrayGet(const int array[], int n) { + return array[n]; +} + +int Sum(int a, int b, int c, int d, int e, int f) { + return a + b + c + d + e + f; +} + +const char* CStringIdentity(const char* s) { + return s; +} + +int GetCopies(const CopyCounter& counter) { + return counter.copies(); +} + +int UnwrapNoRefParent(NoRefParent p) { + return p.value; +} + +int UnwrapNoRefParentPtr(NoRefParent* p) { + return p->value; +} + +int UnwrapNoRefParentConstRef(const NoRefParent& p) { + return p.value; +} + +void RefArgSet(int &n) { + n = 2; +} + +void PtrArgSet(int *n) { + *n = 2; +} + +int FunctionWithWeakFirstParam(WeakPtr<NoRef> o, int n) { + return n; +} + +int FunctionWithScopedRefptrFirstParam(const scoped_refptr<HasRef>& o, int n) { + return n; +} + +void TakesACallback(const Closure& callback) { + callback.Run(); +} + +class BindTest : public ::testing::Test { + public: + BindTest() { + const_has_ref_ptr_ = &has_ref_; + const_no_ref_ptr_ = &no_ref_; + static_func_mock_ptr = &static_func_mock_; + } + + virtual ~BindTest() { + } + + static void VoidFunc0(void) { + static_func_mock_ptr->VoidMethod0(); + } + + static int IntFunc0(void) { return static_func_mock_ptr->IntMethod0(); } + + protected: + StrictMock<NoRef> no_ref_; + StrictMock<HasRef> has_ref_; + const HasRef* const_has_ref_ptr_; + const NoRef* const_no_ref_ptr_; + StrictMock<NoRef> static_func_mock_; + + // Used by the static functions to perform expectations. + static StrictMock<NoRef>* static_func_mock_ptr; + + private: + DISALLOW_COPY_AND_ASSIGN(BindTest); +}; + +StrictMock<NoRef>* BindTest::static_func_mock_ptr; + +// 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); + EXPECT_EQ(63, c0.Run()); + + Callback<int(int)> c1 = Bind(&Sum, 32, 16, 8, 4, 2); + EXPECT_EQ(75, c1.Run(13)); + + Callback<int(int,int)> c2 = Bind(&Sum, 32, 16, 8, 4); + EXPECT_EQ(85, c2.Run(13, 12)); + + Callback<int(int,int,int)> c3 = Bind(&Sum, 32, 16, 8); + EXPECT_EQ(92, c3.Run(13, 12, 11)); + + Callback<int(int,int,int,int)> c4 = Bind(&Sum, 32, 16); + EXPECT_EQ(94, c4.Run(13, 12, 11, 10)); + + Callback<int(int,int,int,int,int)> c5 = Bind(&Sum, 32); + EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9)); + + Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum); + EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14)); +} + +// Test the Currying ability of the Callback system. +TEST_F(BindTest, CurryingTest) { + Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum); + EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14)); + + Callback<int(int,int,int,int,int)> c5 = Bind(c6, 32); + EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9)); + + Callback<int(int,int,int,int)> c4 = Bind(c5, 16); + EXPECT_EQ(94, c4.Run(13, 12, 11, 10)); + + Callback<int(int,int,int)> c3 = Bind(c4, 8); + EXPECT_EQ(92, c3.Run(13, 12, 11)); + + Callback<int(int,int)> c2 = Bind(c3, 4); + EXPECT_EQ(85, c2.Run(13, 12)); + + Callback<int(int)> c1 = Bind(c2, 2); + EXPECT_EQ(75, c1.Run(13)); + + Callback<int(void)> c0 = Bind(c1, 1); + EXPECT_EQ(63, c0.Run()); +} + +// Test that currying the rvalue result of another Bind() works correctly. +// - rvalue should be usable as argument to Bind(). +// - multiple runs of resulting Callback remain valid. +TEST_F(BindTest, CurryingRvalueResultOfBind) { + int n = 0; + Closure cb = base::Bind(&TakesACallback, base::Bind(&PtrArgSet, &n)); + + // If we implement Bind() such that the return value has auto_ptr-like + // semantics, the second call here will fail because ownership of + // the internal BindState<> would have been transfered to a *temporary* + // constructon of a Callback object on the first call. + cb.Run(); + EXPECT_EQ(2, n); + + n = 0; + cb.Run(); + EXPECT_EQ(2, n); +} + +// Function type support. +// - Normal function. +// - Normal function bound with non-refcounted first argument. +// - Method bound to non-const object. +// - Method bound to scoped_refptr. +// - Const method bound to non-const object. +// - Const method bound to const object. +// - Derived classes can be used with pointers to non-virtual base functions. +// - Derived classes can be used with pointers to virtual base functions (and +// preserve virtual dispatch). +TEST_F(BindTest, FunctionTypeSupport) { + EXPECT_CALL(static_func_mock_, VoidMethod0()); + EXPECT_CALL(has_ref_, AddRef()).Times(5); + EXPECT_CALL(has_ref_, Release()).Times(5); + EXPECT_CALL(has_ref_, VoidMethod0()).Times(2); + EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2); + + Closure normal_cb = Bind(&VoidFunc0); + Callback<NoRef*(void)> normal_non_refcounted_cb = + Bind(&PolymorphicIdentity<NoRef*>, &no_ref_); + normal_cb.Run(); + EXPECT_EQ(&no_ref_, normal_non_refcounted_cb.Run()); + + Closure method_cb = Bind(&HasRef::VoidMethod0, &has_ref_); + Closure method_refptr_cb = Bind(&HasRef::VoidMethod0, + make_scoped_refptr(&has_ref_)); + Closure const_method_nonconst_obj_cb = Bind(&HasRef::VoidConstMethod0, + &has_ref_); + Closure const_method_const_obj_cb = Bind(&HasRef::VoidConstMethod0, + const_has_ref_ptr_); + method_cb.Run(); + method_refptr_cb.Run(); + const_method_nonconst_obj_cb.Run(); + const_method_const_obj_cb.Run(); + + Child child; + child.value = 0; + Closure virtual_set_cb = Bind(&Parent::VirtualSet, &child); + virtual_set_cb.Run(); + EXPECT_EQ(kChildValue, child.value); + + child.value = 0; + Closure non_virtual_set_cb = Bind(&Parent::NonVirtualSet, &child); + non_virtual_set_cb.Run(); + EXPECT_EQ(kParentValue, child.value); +} + +// Return value support. +// - Function with return value. +// - Method with return value. +// - Const method with return value. +TEST_F(BindTest, ReturnValues) { + EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337)); + EXPECT_CALL(has_ref_, AddRef()).Times(3); + EXPECT_CALL(has_ref_, Release()).Times(3); + EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(31337)); + EXPECT_CALL(has_ref_, IntConstMethod0()) + .WillOnce(Return(41337)) + .WillOnce(Return(51337)); + + Callback<int(void)> normal_cb = Bind(&IntFunc0); + Callback<int(void)> method_cb = Bind(&HasRef::IntMethod0, &has_ref_); + Callback<int(void)> const_method_nonconst_obj_cb = + Bind(&HasRef::IntConstMethod0, &has_ref_); + Callback<int(void)> const_method_const_obj_cb = + Bind(&HasRef::IntConstMethod0, const_has_ref_ptr_); + EXPECT_EQ(1337, normal_cb.Run()); + EXPECT_EQ(31337, method_cb.Run()); + EXPECT_EQ(41337, const_method_nonconst_obj_cb.Run()); + EXPECT_EQ(51337, const_method_const_obj_cb.Run()); +} + +// IgnoreResult adapter test. +// - Function with return value. +// - Method with return value. +// - Const Method with return. +// - Method with return value bound to WeakPtr<>. +// - Const Method with return bound to WeakPtr<>. +TEST_F(BindTest, IgnoreResult) { + EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337)); + EXPECT_CALL(has_ref_, AddRef()).Times(2); + EXPECT_CALL(has_ref_, Release()).Times(2); + EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(10)); + EXPECT_CALL(has_ref_, IntConstMethod0()).WillOnce(Return(11)); + EXPECT_CALL(no_ref_, IntMethod0()).WillOnce(Return(12)); + EXPECT_CALL(no_ref_, IntConstMethod0()).WillOnce(Return(13)); + + Closure normal_func_cb = Bind(IgnoreResult(&IntFunc0)); + normal_func_cb.Run(); + + Closure non_void_method_cb = + Bind(IgnoreResult(&HasRef::IntMethod0), &has_ref_); + non_void_method_cb.Run(); + + Closure non_void_const_method_cb = + Bind(IgnoreResult(&HasRef::IntConstMethod0), &has_ref_); + non_void_const_method_cb.Run(); + + WeakPtrFactory<NoRef> weak_factory(&no_ref_); + WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_); + + Closure non_void_weak_method_cb = + Bind(IgnoreResult(&NoRef::IntMethod0), weak_factory.GetWeakPtr()); + non_void_weak_method_cb.Run(); + + Closure non_void_weak_const_method_cb = + Bind(IgnoreResult(&NoRef::IntConstMethod0), weak_factory.GetWeakPtr()); + non_void_weak_const_method_cb.Run(); + + weak_factory.InvalidateWeakPtrs(); + non_void_weak_const_method_cb.Run(); + non_void_weak_method_cb.Run(); +} + +// Argument binding tests. +// - Argument binding to primitive. +// - Argument binding to primitive pointer. +// - Argument binding to a literal integer. +// - Argument binding to a literal string. +// - Argument binding with template function. +// - Argument binding to an object. +// - Argument binding to pointer to incomplete type. +// - Argument gets type converted. +// - Pointer argument gets converted. +// - Const Reference forces conversion. +TEST_F(BindTest, ArgumentBinding) { + int n = 2; + + Callback<int(void)> bind_primitive_cb = Bind(&Identity, n); + EXPECT_EQ(n, bind_primitive_cb.Run()); + + Callback<int*(void)> bind_primitive_pointer_cb = + Bind(&PolymorphicIdentity<int*>, &n); + EXPECT_EQ(&n, bind_primitive_pointer_cb.Run()); + + Callback<int(void)> bind_int_literal_cb = Bind(&Identity, 3); + EXPECT_EQ(3, bind_int_literal_cb.Run()); + + Callback<const char*(void)> bind_string_literal_cb = + Bind(&CStringIdentity, "hi"); + EXPECT_STREQ("hi", bind_string_literal_cb.Run()); + + Callback<int(void)> bind_template_function_cb = + Bind(&PolymorphicIdentity<int>, 4); + EXPECT_EQ(4, bind_template_function_cb.Run()); + + NoRefParent p; + p.value = 5; + Callback<int(void)> bind_object_cb = Bind(&UnwrapNoRefParent, p); + EXPECT_EQ(5, bind_object_cb.Run()); + + IncompleteType* incomplete_ptr = reinterpret_cast<IncompleteType*>(123); + Callback<IncompleteType*(void)> bind_incomplete_ptr_cb = + Bind(&PolymorphicIdentity<IncompleteType*>, incomplete_ptr); + EXPECT_EQ(incomplete_ptr, bind_incomplete_ptr_cb.Run()); + + NoRefChild c; + c.value = 6; + Callback<int(void)> bind_promotes_cb = Bind(&UnwrapNoRefParent, c); + EXPECT_EQ(6, bind_promotes_cb.Run()); + + c.value = 7; + Callback<int(void)> bind_pointer_promotes_cb = + Bind(&UnwrapNoRefParentPtr, &c); + EXPECT_EQ(7, bind_pointer_promotes_cb.Run()); + + c.value = 8; + Callback<int(void)> bind_const_reference_promotes_cb = + Bind(&UnwrapNoRefParentConstRef, c); + EXPECT_EQ(8, bind_const_reference_promotes_cb.Run()); +} + +// Unbound argument type support tests. +// - Unbound value. +// - Unbound pointer. +// - Unbound reference. +// - Unbound const reference. +// - Unbound unsized array. +// - Unbound sized array. +// - Unbound array-of-arrays. +TEST_F(BindTest, UnboundArgumentTypeSupport) { + Callback<void(int)> unbound_value_cb = Bind(&VoidPolymorphic1<int>); + Callback<void(int*)> unbound_pointer_cb = Bind(&VoidPolymorphic1<int*>); + Callback<void(int&)> unbound_ref_cb = Bind(&VoidPolymorphic1<int&>); + Callback<void(const int&)> unbound_const_ref_cb = + Bind(&VoidPolymorphic1<const int&>); + Callback<void(int[])> unbound_unsized_array_cb = + Bind(&VoidPolymorphic1<int[]>); + Callback<void(int[2])> unbound_sized_array_cb = + Bind(&VoidPolymorphic1<int[2]>); + Callback<void(int[][2])> unbound_array_of_arrays_cb = + Bind(&VoidPolymorphic1<int[][2]>); +} + +// Function with unbound reference parameter. +// - Original parameter is modified by callback. +TEST_F(BindTest, UnboundReferenceSupport) { + int n = 0; + Callback<void(int&)> unbound_ref_cb = Bind(&RefArgSet); + unbound_ref_cb.Run(n); + EXPECT_EQ(2, n); +} + +// Functions that take reference parameters. +// - Forced reference parameter type still stores a copy. +// - Forced const reference parameter type still stores a copy. +TEST_F(BindTest, ReferenceArgumentBinding) { + int n = 1; + int& ref_n = n; + const int& const_ref_n = n; + + Callback<int(void)> ref_copies_cb = Bind(&Identity, ref_n); + EXPECT_EQ(n, ref_copies_cb.Run()); + n++; + EXPECT_EQ(n - 1, ref_copies_cb.Run()); + + Callback<int(void)> const_ref_copies_cb = Bind(&Identity, const_ref_n); + EXPECT_EQ(n, const_ref_copies_cb.Run()); + n++; + EXPECT_EQ(n - 1, const_ref_copies_cb.Run()); +} + +// Check that we can pass in arrays and have them be stored as a pointer. +// - Array of values stores a pointer. +// - Array of const values stores a pointer. +TEST_F(BindTest, ArrayArgumentBinding) { + int array[4] = {1, 1, 1, 1}; + const int (*const_array_ptr)[4] = &array; + + Callback<int(void)> array_cb = Bind(&ArrayGet, array, 1); + EXPECT_EQ(1, array_cb.Run()); + + Callback<int(void)> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1); + EXPECT_EQ(1, const_array_cb.Run()); + + array[1] = 3; + EXPECT_EQ(3, array_cb.Run()); + EXPECT_EQ(3, const_array_cb.Run()); +} + +// Verify SupportsAddRefAndRelease correctly introspects the class type for +// AddRef() and Release(). +// - Class with AddRef() and Release() +// - Class without AddRef() and Release() +// - Derived Class with AddRef() and Release() +// - Derived Class without AddRef() and Release() +// - Derived Class with AddRef() and Release() and a private destructor. +TEST_F(BindTest, SupportsAddRefAndRelease) { + EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRef>::value); + EXPECT_FALSE(internal::SupportsAddRefAndRelease<NoRef>::value); + + // StrictMock<T> is a derived class of T. So, we use StrictMock<HasRef> and + // StrictMock<NoRef> to test that SupportsAddRefAndRelease works over + // inheritance. + EXPECT_TRUE(internal::SupportsAddRefAndRelease<StrictMock<HasRef> >::value); + EXPECT_FALSE(internal::SupportsAddRefAndRelease<StrictMock<NoRef> >::value); + + // This matters because the implementation creates a dummy class that + // inherits from the template type. + EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRefPrivateDtor>::value); +} + +// Unretained() wrapper support. +// - Method bound to Unretained() non-const object. +// - Const method bound to Unretained() non-const object. +// - Const method bound to Unretained() const object. +TEST_F(BindTest, Unretained) { + EXPECT_CALL(no_ref_, VoidMethod0()); + EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2); + + Callback<void(void)> method_cb = + Bind(&NoRef::VoidMethod0, Unretained(&no_ref_)); + method_cb.Run(); + + Callback<void(void)> const_method_cb = + Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_)); + const_method_cb.Run(); + + Callback<void(void)> const_method_const_ptr_cb = + Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_)); + const_method_const_ptr_cb.Run(); +} + +// WeakPtr() support. +// - Method bound to WeakPtr<> to non-const object. +// - Const method bound to WeakPtr<> to non-const object. +// - Const method bound to WeakPtr<> to const object. +// - Normal Function with WeakPtr<> as P1 can have return type and is +// not canceled. +TEST_F(BindTest, WeakPtr) { + EXPECT_CALL(no_ref_, VoidMethod0()); + EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2); + + WeakPtrFactory<NoRef> weak_factory(&no_ref_); + WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_); + + Closure method_cb = + Bind(&NoRef::VoidMethod0, weak_factory.GetWeakPtr()); + method_cb.Run(); + + Closure const_method_cb = + Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr()); + const_method_cb.Run(); + + Closure const_method_const_ptr_cb = + Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr()); + const_method_const_ptr_cb.Run(); + + Callback<int(int)> normal_func_cb = + Bind(&FunctionWithWeakFirstParam, weak_factory.GetWeakPtr()); + EXPECT_EQ(1, normal_func_cb.Run(1)); + + weak_factory.InvalidateWeakPtrs(); + const_weak_factory.InvalidateWeakPtrs(); + + method_cb.Run(); + const_method_cb.Run(); + const_method_const_ptr_cb.Run(); + + // Still runs even after the pointers are invalidated. + EXPECT_EQ(2, normal_func_cb.Run(2)); +} + +// ConstRef() wrapper support. +// - Binding w/o ConstRef takes a copy. +// - Binding a ConstRef takes a reference. +// - Binding ConstRef to a function ConstRef does not copy on invoke. +TEST_F(BindTest, ConstRef) { + int n = 1; + + Callback<int(void)> copy_cb = Bind(&Identity, n); + Callback<int(void)> const_ref_cb = Bind(&Identity, ConstRef(n)); + EXPECT_EQ(n, copy_cb.Run()); + EXPECT_EQ(n, const_ref_cb.Run()); + n++; + EXPECT_EQ(n - 1, copy_cb.Run()); + EXPECT_EQ(n, const_ref_cb.Run()); + + int copies = 0; + int assigns = 0; + CopyCounter counter(&copies, &assigns); + Callback<int(void)> all_const_ref_cb = + Bind(&GetCopies, ConstRef(counter)); + EXPECT_EQ(0, all_const_ref_cb.Run()); + EXPECT_EQ(0, copies); + EXPECT_EQ(0, assigns); +} + +TEST_F(BindTest, ScopedRefptr) { + // BUG: The scoped_refptr should cause the only AddRef()/Release() pair. But + // due to a bug in base::Bind(), there's an extra call when invoking the + // callback. + // https://code.google.com/p/chromium/issues/detail?id=251937 + EXPECT_CALL(has_ref_, AddRef()).Times(2); + EXPECT_CALL(has_ref_, Release()).Times(2); + + const scoped_refptr<StrictMock<HasRef> > refptr(&has_ref_); + + Callback<int(void)> scoped_refptr_const_ref_cb = + Bind(&FunctionWithScopedRefptrFirstParam, base::ConstRef(refptr), 1); + EXPECT_EQ(1, scoped_refptr_const_ref_cb.Run()); +} + +// Test Owned() support. +TEST_F(BindTest, Owned) { + int deletes = 0; + DeleteCounter* counter = new DeleteCounter(&deletes); + + // If we don't capture, delete happens on Callback destruction/reset. + // return the same value. + Callback<DeleteCounter*(void)> no_capture_cb = + Bind(&PolymorphicIdentity<DeleteCounter*>, Owned(counter)); + ASSERT_EQ(counter, no_capture_cb.Run()); + ASSERT_EQ(counter, no_capture_cb.Run()); + EXPECT_EQ(0, deletes); + no_capture_cb.Reset(); // This should trigger a delete. + EXPECT_EQ(1, deletes); + + deletes = 0; + counter = new DeleteCounter(&deletes); + base::Closure own_object_cb = + Bind(&DeleteCounter::VoidMethod0, Owned(counter)); + own_object_cb.Run(); + EXPECT_EQ(0, deletes); + own_object_cb.Reset(); + EXPECT_EQ(1, deletes); +} + +// Passed() wrapper support. +// - Passed() can be constructed from a pointer to scoper. +// - Passed() can be constructed from a scoper rvalue. +// - Using Passed() gives Callback Ownership. +// - Ownership is transferred from Callback to callee on the first Run(). +// - Callback supports unbound arguments. +TEST_F(BindTest, ScopedPtr) { + int deletes = 0; + + // Tests the Passed() function's support for pointers. + scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes)); + Callback<scoped_ptr<DeleteCounter>(void)> unused_callback = + Bind(&PassThru<scoped_ptr<DeleteCounter> >, Passed(&ptr)); + EXPECT_FALSE(ptr.get()); + EXPECT_EQ(0, deletes); + + // If we never invoke the Callback, it retains ownership and deletes. + unused_callback.Reset(); + EXPECT_EQ(1, deletes); + + // Tests the Passed() function's support for rvalues. + deletes = 0; + DeleteCounter* counter = new DeleteCounter(&deletes); + Callback<scoped_ptr<DeleteCounter>(void)> callback = + Bind(&PassThru<scoped_ptr<DeleteCounter> >, + Passed(scoped_ptr<DeleteCounter>(counter))); + EXPECT_FALSE(ptr.get()); + EXPECT_EQ(0, deletes); + + // Check that ownership can be transferred back out. + scoped_ptr<DeleteCounter> result = callback.Run(); + ASSERT_EQ(counter, result.get()); + EXPECT_EQ(0, deletes); + + // Resetting does not delete since ownership was transferred. + callback.Reset(); + EXPECT_EQ(0, deletes); + + // Ensure that we actually did get ownership. + result.reset(); + EXPECT_EQ(1, deletes); + + // Test unbound argument forwarding. + Callback<scoped_ptr<DeleteCounter>(scoped_ptr<DeleteCounter>)> cb_unbound = + Bind(&PassThru<scoped_ptr<DeleteCounter> >); + ptr.reset(new DeleteCounter(&deletes)); + cb_unbound.Run(ptr.Pass()); +} + +// Argument Copy-constructor usage for non-reference parameters. +// - Bound arguments are only copied once. +// - Forwarded arguments are only copied once. +// - Forwarded arguments with coercions are only copied twice (once for the +// coercion, and one for the final dispatch). +TEST_F(BindTest, ArgumentCopies) { + int copies = 0; + int assigns = 0; + + CopyCounter counter(&copies, &assigns); + + Callback<void(void)> copy_cb = + Bind(&VoidPolymorphic1<CopyCounter>, counter); + EXPECT_GE(1, copies); + EXPECT_EQ(0, assigns); + + copies = 0; + assigns = 0; + Callback<void(CopyCounter)> forward_cb = + Bind(&VoidPolymorphic1<CopyCounter>); + forward_cb.Run(counter); + EXPECT_GE(1, copies); + EXPECT_EQ(0, assigns); + + copies = 0; + assigns = 0; + DerivedCopyCounter derived(&copies, &assigns); + Callback<void(CopyCounter)> coerce_cb = + Bind(&VoidPolymorphic1<CopyCounter>); + coerce_cb.Run(CopyCounter(derived)); + EXPECT_GE(2, copies); + EXPECT_EQ(0, assigns); +} + +// Callback construction and assignment tests. +// - Construction from an InvokerStorageHolder should not cause ref/deref. +// - Assignment from other callback should only cause one ref +// +// TODO(ajwong): Is there actually a way to test this? + +#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 + +#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST + +// Test null callbacks cause a DCHECK. +TEST(BindDeathTest, NullCallback) { + base::Callback<void(int)> null_cb; + ASSERT_TRUE(null_cb.is_null()); + EXPECT_DEATH(base::Bind(null_cb, 42), ""); +} + +#endif // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && + // GTEST_HAS_DEATH_TEST + +} // namespace +} // namespace base diff --git a/third_party/chromium/base/build/build_config.h b/third_party/chromium/base/build/build_config.h new file mode 100644 index 0000000..904965a --- /dev/null +++ b/third_party/chromium/base/build/build_config.h @@ -0,0 +1,163 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file adds defines about the platform we're currently building on. +// Operating System: +// OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) / +// OS_NACL (NACL_SFI or NACL_NONSFI) / OS_NACL_SFI / OS_NACL_NONSFI +// Compiler: +// COMPILER_MSVC / COMPILER_GCC +// Processor: +// ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64) +// ARCH_CPU_32_BITS / ARCH_CPU_64_BITS + +#ifndef BASE_BUILD_BUILD_CONFIG_H_ +#define BASE_BUILD_BUILD_CONFIG_H_ + +// Add Brillo-specific defines. +#if defined(__BRILLO__) +#define __linux__ 1 +#define NO_TCMALLOC +// Unset ANDROID, which is just used for building Chrome on Android. +#undef ANDROID + +#if defined(__BIONIC__) +#define __UCLIBC__ 1 +#define OS_CHROMEOS 1 +#endif // __BIONIC__ + +#endif + +// A set of macros to use for platform detection. +#if defined(__native_client__) +// __native_client__ must be first, so that other OS_ defines are not set. +#define OS_NACL 1 +// OS_NACL comes in two sandboxing technology flavors, SFI or Non-SFI. +// PNaCl toolchain defines __native_client_nonsfi__ macro in Non-SFI build +// mode, while it does not in SFI build mode. +#if defined(__native_client_nonsfi__) +#define OS_NACL_NONSFI +#else +#define OS_NACL_SFI +#endif +#elif defined(ANDROID) +#define OS_ANDROID 1 +#elif defined(__APPLE__) +// only include TargetConditions after testing ANDROID as some android builds +// on mac don't have this header available and it's not needed unless the target +// is really mac/ios. +#include <TargetConditionals.h> +#define OS_MACOSX 1 +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#define OS_IOS 1 +#endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +#elif defined(__linux__) +#define OS_LINUX 1 +// include a system header to pull in features.h for glibc/uclibc macros. +#include <unistd.h> +#if defined(__GLIBC__) && !defined(__UCLIBC__) +// we really are using glibc, not uClibc pretending to be glibc +#define LIBC_GLIBC 1 +#endif +#elif defined(_WIN32) +#define OS_WIN 1 +#define TOOLKIT_VIEWS 1 +#elif defined(__FreeBSD__) +#define OS_FREEBSD 1 +#elif defined(__OpenBSD__) +#define OS_OPENBSD 1 +#elif defined(__sun) +#define OS_SOLARIS 1 +#elif defined(__QNXNTO__) +#define OS_QNX 1 +#else +#error Please add support for your platform in build/build_config.h +#endif + +#if defined(USE_OPENSSL) && defined(USE_NSS) +#error Cannot use both OpenSSL and NSS +#endif + +// For access to standard BSD features, use OS_BSD instead of a +// more specific macro. +#if defined(OS_FREEBSD) || defined(OS_OPENBSD) +#define OS_BSD 1 +#endif + +// For access to standard POSIXish features, use OS_POSIX instead of a +// more specific macro. +#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_FREEBSD) || \ + defined(OS_OPENBSD) || defined(OS_SOLARIS) || defined(OS_ANDROID) || \ + defined(OS_NACL) || defined(OS_QNX) +#define OS_POSIX 1 +#endif + +// Use tcmalloc +#if (defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)) && \ + !defined(NO_TCMALLOC) +#define USE_TCMALLOC 1 +#endif + +// Compiler detection. +#if defined(__GNUC__) +#define COMPILER_GCC 1 +#elif defined(_MSC_VER) +#define COMPILER_MSVC 1 +#else +#error Please add support for your compiler in build/build_config.h +#endif + +// Processor architecture detection. For more info on what's defined, see: +// http://msdn.microsoft.com/en-us/library/b0084kay.aspx +// http://www.agner.org/optimize/calling_conventions.pdf +// or with gcc, run: "echo | gcc -E -dM -" +#if defined(_M_X64) || defined(__x86_64__) +#define ARCH_CPU_X86_FAMILY 1 +#define ARCH_CPU_X86_64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(_M_IX86) || defined(__i386__) +#define ARCH_CPU_X86_FAMILY 1 +#define ARCH_CPU_X86 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__ARMEL__) +#define ARCH_CPU_ARM_FAMILY 1 +#define ARCH_CPU_ARMEL 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__aarch64__) +#define ARCH_CPU_ARM_FAMILY 1 +#define ARCH_CPU_ARM64 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__pnacl__) +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#elif defined(__MIPSEL__) +#if defined(__LP64__) +#define ARCH_CPU_MIPS64_FAMILY 1 +#define ARCH_CPU_MIPS64EL 1 +#define ARCH_CPU_64_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#else +#define ARCH_CPU_MIPS_FAMILY 1 +#define ARCH_CPU_MIPSEL 1 +#define ARCH_CPU_32_BITS 1 +#define ARCH_CPU_LITTLE_ENDIAN 1 +#endif +#else +#error Please add support for your architecture in build/build_config.h +#endif + +#if defined(OS_ANDROID) +// The compiler thinks std::string::const_iterator and "const char*" are +// equivalent types. +#define STD_STRING_ITERATOR_IS_CHAR_POINTER +// The compiler thinks base::string16::const_iterator and "char16*" are +// equivalent types. +#define BASE_STRING16_ITERATOR_IS_CHAR16_POINTER +#endif + +#endif // BASE_BUILD_BUILD_CONFIG_H_ diff --git a/third_party/chromium/base/callback.h b/third_party/chromium/base/callback.h new file mode 100644 index 0000000..00669dd --- /dev/null +++ b/third_party/chromium/base/callback.h @@ -0,0 +1,411 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_CALLBACK_H_ +#define BASE_CALLBACK_H_ + +#include "base/callback_forward.h" +#include "base/callback_internal.h" +#include "base/template_util.h" + +// NOTE: Header files that do not require the full definition of Callback or +// Closure should #include "base/callback_forward.h" instead of this file. + +// ----------------------------------------------------------------------------- +// Introduction +// ----------------------------------------------------------------------------- +// +// The templated Callback class is a generalized function object. Together +// with the Bind() function in bind.h, they provide a type-safe method for +// performing partial application of functions. +// +// Partial application (or "currying") is the process of binding a subset of +// a function's arguments to produce another function that takes fewer +// arguments. This can be used to pass around a unit of delayed execution, +// much like lexical closures are used in other languages. For example, it +// is used in Chromium code to schedule tasks on different MessageLoops. +// +// A callback with no unbound input parameters (base::Callback<void(void)>) +// is called a base::Closure. Note that this is NOT the same as what other +// languages refer to as a closure -- it does not retain a reference to its +// enclosing environment. +// +// MEMORY MANAGEMENT AND PASSING +// +// The Callback objects themselves should be passed by const-reference, and +// stored by copy. They internally store their state via a refcounted class +// and thus do not need to be deleted. +// +// The reason to pass via a const-reference is to avoid unnecessary +// AddRef/Release pairs to the internal state. +// +// +// ----------------------------------------------------------------------------- +// Quick reference for basic stuff +// ----------------------------------------------------------------------------- +// +// BINDING A BARE FUNCTION +// +// int Return5() { return 5; } +// base::Callback<int(void)> func_cb = base::Bind(&Return5); +// LOG(INFO) << func_cb.Run(); // Prints 5. +// +// BINDING A CLASS METHOD +// +// The first argument to bind is the member function to call, the second is +// the object on which to call it. +// +// class Ref : public base::RefCountedThreadSafe<Ref> { +// public: +// int Foo() { return 3; } +// void PrintBye() { LOG(INFO) << "bye."; } +// }; +// scoped_refptr<Ref> ref = new Ref(); +// base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref); +// LOG(INFO) << ref_cb.Run(); // Prints out 3. +// +// By default the object must support RefCounted or you will get a compiler +// error. If you're passing between threads, be sure it's +// RefCountedThreadSafe! See "Advanced binding of member functions" below if +// you don't want to use reference counting. +// +// RUNNING A CALLBACK +// +// Callbacks can be run with their "Run" method, which has the same +// signature as the template argument to the callback. +// +// void DoSomething(const base::Callback<void(int, std::string)>& callback) { +// callback.Run(5, "hello"); +// } +// +// Callbacks can be run more than once (they don't get deleted or marked when +// run). However, this precludes using base::Passed (see below). +// +// void DoSomething(const base::Callback<double(double)>& callback) { +// double myresult = callback.Run(3.14159); +// myresult += callback.Run(2.71828); +// } +// +// PASSING UNBOUND INPUT PARAMETERS +// +// Unbound parameters are specified at the time a callback is Run(). They are +// specified in the Callback template type: +// +// void MyFunc(int i, const std::string& str) {} +// base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc); +// cb.Run(23, "hello, world"); +// +// PASSING BOUND INPUT PARAMETERS +// +// Bound parameters are specified when you create thee callback as arguments +// to Bind(). They will be passed to the function and the Run()ner of the +// callback doesn't see those values or even know that the function it's +// calling. +// +// void MyFunc(int i, const std::string& str) {} +// base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world"); +// cb.Run(); +// +// A callback with no unbound input parameters (base::Callback<void(void)>) +// is called a base::Closure. So we could have also written: +// +// base::Closure cb = base::Bind(&MyFunc, 23, "hello world"); +// +// When calling member functions, bound parameters just go after the object +// pointer. +// +// base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world"); +// +// PARTIAL BINDING OF PARAMETERS +// +// You can specify some parameters when you create the callback, and specify +// the rest when you execute the callback. +// +// void MyFunc(int i, const std::string& str) {} +// base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23); +// cb.Run("hello world"); +// +// When calling a function bound parameters are first, followed by unbound +// parameters. +// +// +// ----------------------------------------------------------------------------- +// Quick reference for advanced binding +// ----------------------------------------------------------------------------- +// +// BINDING A CLASS METHOD WITH WEAK POINTERS +// +// base::Bind(&MyClass::Foo, GetWeakPtr()); +// +// The callback will not be run if the object has already been destroyed. +// DANGER: weak pointers are not threadsafe, so don't use this +// when passing between threads! +// +// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT +// +// base::Bind(&MyClass::Foo, base::Unretained(this)); +// +// This disables all lifetime management on the object. You're responsible +// for making sure the object is alive at the time of the call. You break it, +// you own it! +// +// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS +// +// MyClass* myclass = new MyClass; +// base::Bind(&MyClass::Foo, base::Owned(myclass)); +// +// The object will be deleted when the callback is destroyed, even if it's +// not run (like if you post a task during shutdown). Potentially useful for +// "fire and forget" cases. +// +// IGNORING RETURN VALUES +// +// Sometimes you want to call a function that returns a value in a callback +// that doesn't expect a return value. +// +// int DoSomething(int arg) { cout << arg << endl; } +// base::Callback<void<int>) cb = +// base::Bind(base::IgnoreResult(&DoSomething)); +// +// +// ----------------------------------------------------------------------------- +// Quick reference for binding parameters to Bind() +// ----------------------------------------------------------------------------- +// +// Bound parameters are specified as arguments to Bind() and are passed to the +// function. A callback with no parameters or no unbound parameters is called a +// Closure (base::Callback<void(void)> and base::Closure are the same thing). +// +// PASSING PARAMETERS OWNED BY THE CALLBACK +// +// void Foo(int* arg) { cout << *arg << endl; } +// int* pn = new int(1); +// base::Closure foo_callback = base::Bind(&foo, base::Owned(pn)); +// +// The parameter will be deleted when the callback is destroyed, even if it's +// not run (like if you post a task during shutdown). +// +// PASSING PARAMETERS AS A scoped_ptr +// +// void TakesOwnership(scoped_ptr<Foo> arg) {} +// scoped_ptr<Foo> f(new Foo); +// // f becomes null during the following call. +// base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f)); +// +// Ownership of the parameter will be with the callback until the it is run, +// when ownership is passed to the callback function. This means the callback +// can only be run once. If the callback is never run, it will delete the +// object when it's destroyed. +// +// PASSING PARAMETERS AS A scoped_refptr +// +// void TakesOneRef(scoped_refptr<Foo> arg) {} +// scoped_refptr<Foo> f(new Foo) +// base::Closure cb = base::Bind(&TakesOneRef, f); +// +// This should "just work." The closure will take a reference as long as it +// is alive, and another reference will be taken for the called function. +// +// PASSING PARAMETERS BY REFERENCE +// +// Const references are *copied* unless ConstRef is used. Example: +// +// void foo(const int& arg) { printf("%d %p\n", arg, &arg); } +// int n = 1; +// base::Closure has_copy = base::Bind(&foo, n); +// base::Closure has_ref = base::Bind(&foo, base::ConstRef(n)); +// n = 2; +// foo(n); // Prints "2 0xaaaaaaaaaaaa" +// has_copy.Run(); // Prints "1 0xbbbbbbbbbbbb" +// has_ref.Run(); // Prints "2 0xaaaaaaaaaaaa" +// +// Normally parameters are copied in the closure. DANGER: ConstRef stores a +// const reference instead, referencing the original parameter. This means +// that you must ensure the object outlives the callback! +// +// +// ----------------------------------------------------------------------------- +// Implementation notes +// ----------------------------------------------------------------------------- +// +// WHERE IS THIS DESIGN FROM: +// +// The design Callback and Bind is heavily influenced by C++'s +// tr1::function/tr1::bind, and by the "Google Callback" system used inside +// Google. +// +// +// HOW THE IMPLEMENTATION WORKS: +// +// There are three main components to the system: +// 1) The Callback classes. +// 2) The Bind() functions. +// 3) The arguments wrappers (e.g., Unretained() and ConstRef()). +// +// The Callback classes represent a generic function pointer. Internally, +// it stores a refcounted piece of state that represents the target function +// and all its bound parameters. Each Callback specialization has a templated +// constructor that takes an BindState<>*. In the context of the constructor, +// the static type of this BindState<> pointer uniquely identifies the +// function it is representing, all its bound parameters, and a Run() method +// that is capable of invoking the target. +// +// Callback's constructor takes the BindState<>* that has the full static type +// and erases the target function type as well as the types of the bound +// parameters. It does this by storing a pointer to the specific Run() +// function, and upcasting the state of BindState<>* to a +// BindStateBase*. This is safe as long as this BindStateBase pointer +// is only used with the stored Run() pointer. +// +// To BindState<> objects are created inside the Bind() functions. +// These functions, along with a set of internal templates, are responsible for +// +// - Unwrapping the function signature into return type, and parameters +// - Determining the number of parameters that are bound +// - Creating the BindState storing the bound parameters +// - Performing compile-time asserts to avoid error-prone behavior +// - Returning an Callback<> with an arity matching the number of unbound +// parameters and that knows the correct refcounting semantics for the +// target object if we are binding a method. +// +// The Bind functions do the above using type-inference, and template +// specializations. +// +// By default Bind() will store copies of all bound parameters, and attempt +// to refcount a target object if the function being bound is a class method. +// These copies are created even if the function takes parameters as const +// references. (Binding to non-const references is forbidden, see bind.h.) +// +// To change this behavior, we introduce a set of argument wrappers +// (e.g., Unretained(), and ConstRef()). These are simple container templates +// that are passed by value, and wrap a pointer to argument. See the +// file-level comment in base/bind_helpers.h for more info. +// +// These types are passed to the Unwrap() functions, and the MaybeRefcount() +// functions respectively to modify the behavior of Bind(). The Unwrap() +// and MaybeRefcount() functions change behavior by doing partial +// specialization based on whether or not a parameter is a wrapper type. +// +// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium. +// +// +// WHY NOT TR1 FUNCTION/BIND? +// +// Direct use of tr1::function and tr1::bind was considered, but ultimately +// rejected because of the number of copy constructors invocations involved +// in the binding of arguments during construction, and the forwarding of +// arguments during invocation. These copies will no longer be an issue in +// C++0x because C++0x will support rvalue reference allowing for the compiler +// to avoid these copies. However, waiting for C++0x is not an option. +// +// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the +// tr1::bind call itself will invoke a non-trivial copy constructor three times +// for each bound parameter. Also, each when passing a tr1::function, each +// bound argument will be copied again. +// +// In addition to the copies taken at binding and invocation, copying a +// tr1::function causes a copy to be made of all the bound parameters and +// state. +// +// Furthermore, in Chromium, it is desirable for the Callback to take a +// reference on a target object when representing a class method call. This +// is not supported by tr1. +// +// Lastly, tr1::function and tr1::bind has a more general and flexible API. +// This includes things like argument reordering by use of +// tr1::bind::placeholder, support for non-const reference parameters, and some +// limited amount of subtyping of the tr1::function object (e.g., +// tr1::function<int(int)> is convertible to tr1::function<void(int)>). +// +// These are not features that are required in Chromium. Some of them, such as +// allowing for reference parameters, and subtyping of functions, may actually +// become a source of errors. Removing support for these features actually +// allows for a simpler implementation, and a terser Currying API. +// +// +// WHY NOT GOOGLE CALLBACKS? +// +// The Google callback system also does not support refcounting. Furthermore, +// its implementation has a number of strange edge cases with respect to type +// conversion of its arguments. In particular, the argument's constness must +// at times match exactly the function signature, or the type-inference might +// break. Given the above, writing a custom solution was easier. +// +// +// MISSING FUNCTIONALITY +// - Invoking the return of Bind. Bind(&foo).Run() does not work; +// - Binding arrays to functions that take a non-const pointer. +// Example: +// void Foo(const char* ptr); +// void Bar(char* ptr); +// Bind(&Foo, "test"); +// Bind(&Bar, "test"); // This fails because ptr is not const. + +namespace base { + +// First, we forward declare the Callback class template. This informs the +// compiler that the template only has 1 type parameter which is the function +// signature that the Callback is representing. +// +// After this, create template specializations for 0-7 parameters. Note that +// even though the template typelist grows, the specialization still +// only has one type: the function signature. +// +// If you are thinking of forward declaring Callback in your own header file, +// please include "base/callback_forward.h" instead. +template <typename Sig> +class Callback; + +namespace internal { +template <typename Runnable, typename RunType, typename BoundArgsType> +struct BindState; +} // namespace internal + +template <typename R, typename... Args> +class Callback<R(Args...)> : public internal::CallbackBase { + public: + typedef R(RunType)(Args...); + + Callback() : CallbackBase(NULL) { } + + // Note that this constructor CANNOT be explicit, and that Bind() CANNOT + // return the exact Callback<> type. See base/bind.h for details. + template <typename Runnable, typename BindRunType, typename BoundArgsType> + Callback(internal::BindState<Runnable, BindRunType, + BoundArgsType>* bind_state) + : CallbackBase(bind_state) { + // Force the assignment to a local variable of PolymorphicInvoke + // so the compiler will typecheck that the passed in Run() method has + // the correct type. + PolymorphicInvoke invoke_func = + &internal::BindState<Runnable, BindRunType, BoundArgsType> + ::InvokerType::Run; + polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func); + } + + bool Equals(const Callback& other) const { + return CallbackBase::Equals(other); + } + + R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args) + const { + PolymorphicInvoke f = + reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_); + + return f(bind_state_.get(), internal::CallbackForward(args)...); + } + + private: + typedef R(*PolymorphicInvoke)( + internal::BindStateBase*, + typename internal::CallbackParamTraits<Args>::ForwardType...); +}; + +// Syntactic sugar to make Callback<void(void)> easier to declare since it +// will be used in a lot of APIs with delayed execution. +typedef Callback<void(void)> Closure; + +} // namespace base + +#endif // BASE_CALLBACK_H_ diff --git a/third_party/chromium/base/callback_forward.h b/third_party/chromium/base/callback_forward.h new file mode 100644 index 0000000..262c306 --- /dev/null +++ b/third_party/chromium/base/callback_forward.h @@ -0,0 +1,17 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_CALLBACK_FORWARD_H_ +#define BASE_CALLBACK_FORWARD_H_ + +namespace base { + +template <typename Sig> +class Callback; + +typedef Callback<void(void)> Closure; + +} // namespace base + +#endif // BASE_CALLBACK_FORWARD_H_ diff --git a/third_party/chromium/base/callback_internal.cc b/third_party/chromium/base/callback_internal.cc new file mode 100644 index 0000000..f0d16bb --- /dev/null +++ b/third_party/chromium/base/callback_internal.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/callback_internal.h" + +#include "base/logging.h" + +namespace base { +namespace internal { + +void BindStateBase::AddRef() { + ++ref_count_; +} + +void BindStateBase::Release() { + if (--ref_count_ == 0) + destructor_(this); +} + +CallbackBase::CallbackBase(const CallbackBase& c) = default; +CallbackBase& CallbackBase::operator=(const CallbackBase& c) = default; + +void CallbackBase::Reset() { + polymorphic_invoke_ = NULL; + // NULL the bind_state_ last, since it may be holding the last ref to whatever + // object owns us, and we may be deleted after that. + bind_state_ = NULL; +} + +bool CallbackBase::Equals(const CallbackBase& other) const { + return bind_state_.get() == other.bind_state_.get() && + polymorphic_invoke_ == other.polymorphic_invoke_; +} + +CallbackBase::CallbackBase(BindStateBase* bind_state) + : bind_state_(bind_state), + polymorphic_invoke_(NULL) { + DCHECK(!bind_state_.get() || bind_state_->ref_count_ == 1); +} + +CallbackBase::~CallbackBase() { +} + +} // namespace internal +} // namespace base diff --git a/third_party/chromium/base/callback_internal.h b/third_party/chromium/base/callback_internal.h new file mode 100644 index 0000000..94e4f79 --- /dev/null +++ b/third_party/chromium/base/callback_internal.h @@ -0,0 +1,272 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains utility functions and classes that help the +// implementation, and management of the Callback objects. + +#ifndef BASE_CALLBACK_INTERNAL_H_ +#define BASE_CALLBACK_INTERNAL_H_ + +#include <stddef.h> +#include <map> +#include <memory> +#include <vector> + +#include "base/base_export.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/template_util.h" + +template <typename T> +class ScopedVector; + +namespace base { +namespace internal { +class CallbackBase; + +// BindStateBase is used to provide an opaque handle that the Callback +// class can use to represent a function object with bound arguments. It +// behaves as an existential type that is used by a corresponding +// DoInvoke function to perform the function execution. This allows +// us to shield the Callback class from the types of the bound argument via +// "type erasure." +// At the base level, the only task is to add reference counting data. Don't use +// RefCountedThreadSafe since it requires the destructor to be a virtual method. +// Creating a vtable for every BindState template instantiation results in a lot +// of bloat. Its only task is to call the destructor which can be done with a +// function pointer. +class BindStateBase { + protected: + explicit BindStateBase(void (*destructor)(BindStateBase*)) + : ref_count_(0), destructor_(destructor) {} + ~BindStateBase() = default; + + private: + friend class scoped_refptr<BindStateBase>; + friend class CallbackBase; + + void AddRef(); + void Release(); + + std::atomic<int32_t> ref_count_; + + // Pointer to a function that will properly destroy |this|. + void (*destructor_)(BindStateBase*); + + DISALLOW_COPY_AND_ASSIGN(BindStateBase); +}; + +// Holds the Callback methods that don't require specialization to reduce +// template bloat. +class BASE_EXPORT CallbackBase { + public: + CallbackBase(const CallbackBase& c); + CallbackBase& operator=(const CallbackBase& c); + + // Returns true if Callback is null (doesn't refer to anything). + bool is_null() const { return bind_state_.get() == NULL; } + + // Returns the Callback into an uninitialized state. + void Reset(); + + protected: + // In C++, it is safe to cast function pointers to function pointers of + // another type. It is not okay to use void*. We create a InvokeFuncStorage + // that that can store our function pointer, and then cast it back to + // the original type on usage. + typedef void(*InvokeFuncStorage)(void); + + // Returns true if this callback equals |other|. |other| may be null. + bool Equals(const CallbackBase& other) const; + + // Allow initializing of |bind_state_| via the constructor to avoid default + // initialization of the scoped_refptr. We do not also initialize + // |polymorphic_invoke_| here because doing a normal assignment in the + // derived Callback templates makes for much nicer compiler errors. + explicit CallbackBase(BindStateBase* bind_state); + + // Force the destructor to be instantiated inside this translation unit so + // that our subclasses will not get inlined versions. Avoids more template + // bloat. + ~CallbackBase(); + + scoped_refptr<BindStateBase> bind_state_; + InvokeFuncStorage polymorphic_invoke_; +}; + +// A helper template to determine if given type is non-const move-only-type, +// i.e. if a value of the given type should be passed via .Pass() in a +// destructive way. +template <typename T> struct IsMoveOnlyType { + template <typename U> + static YesType Test(const typename U::MoveOnlyTypeForCPP03*); + + template <typename U> + static NoType Test(...); + + static const bool value = sizeof((Test<T>(0))) == sizeof(YesType) && + !std::is_const<T>::value; +}; + +// Mark std::unique_ptr<T> and common containers using unique_ptr as MoveOnly +// type for base::Callback, so it is stored by value and not a const reference +// inside Callback. +template<typename T, typename D> +struct IsMoveOnlyType<std::unique_ptr<T, D>> : public std::true_type {}; + +template<typename T, typename D, typename A> +struct IsMoveOnlyType<std::vector<std::unique_ptr<T, D>, A>> + : public std::true_type {}; + +template<typename K, typename T, typename D, typename C, typename A> +struct IsMoveOnlyType<std::map<K, std::unique_ptr<T, D>, C, A>> + : public std::true_type {}; + +// Returns |Then| as SelectType::Type if |condition| is true. Otherwise returns +// |Else|. +template <bool condition, typename Then, typename Else> +struct SelectType { + typedef Then Type; +}; + +template <typename Then, typename Else> +struct SelectType<false, Then, Else> { + typedef Else Type; +}; + +template <typename> +struct CallbackParamTraitsForMoveOnlyType; + +template <typename> +struct CallbackParamTraitsForNonMoveOnlyType; + +// TODO(tzik): Use a default parameter once MSVS supports variadic templates +// with default values. +// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates +// +// This is a typetraits object that's used to take an argument type, and +// extract a suitable type for storing and forwarding arguments. +// +// In particular, it strips off references, and converts arrays to +// pointers for storage; and it avoids accidentally trying to create a +// "reference of a reference" if the argument is a reference type. +// +// This array type becomes an issue for storage because we are passing bound +// parameters by const reference. In this case, we end up passing an actual +// array type in the initializer list which C++ does not allow. This will +// break passing of C-string literals. +template <typename T> +struct CallbackParamTraits + : SelectType<IsMoveOnlyType<T>::value, + CallbackParamTraitsForMoveOnlyType<T>, + CallbackParamTraitsForNonMoveOnlyType<T> >::Type { +}; + +template <typename T> +struct CallbackParamTraitsForNonMoveOnlyType { + typedef const T& ForwardType; + typedef T StorageType; +}; + +// The Storage should almost be impossible to trigger unless someone manually +// specifies type of the bind parameters. However, in case they do, +// this will guard against us accidentally storing a reference parameter. +// +// The ForwardType should only be used for unbound arguments. +template <typename T> +struct CallbackParamTraitsForNonMoveOnlyType<T&> { + typedef T& ForwardType; + typedef T StorageType; +}; + +// Note that for array types, we implicitly add a const in the conversion. This +// means that it is not possible to bind array arguments to functions that take +// a non-const pointer. Trying to specialize the template based on a "const +// T[n]" does not seem to match correctly, so we are stuck with this +// restriction. +template <typename T, size_t n> +struct CallbackParamTraitsForNonMoveOnlyType<T[n]> { + typedef const T* ForwardType; + typedef const T* StorageType; +}; + +// See comment for CallbackParamTraits<T[n]>. +template <typename T> +struct CallbackParamTraitsForNonMoveOnlyType<T[]> { + typedef const T* ForwardType; + typedef const T* StorageType; +}; + +// Parameter traits for movable-but-not-copyable scopers. +// +// Callback<>/Bind() understands movable-but-not-copyable semantics where +// the type cannot be copied but can still have its state destructively +// transferred (aka. moved) to another instance of the same type by calling a +// helper function. When used with Bind(), this signifies transferal of the +// object's state to the target function. +// +// For these types, the ForwardType must not be a const reference, or a +// reference. A const reference is inappropriate, and would break const +// correctness, because we are implementing a destructive move. A non-const +// reference cannot be used with temporaries which means the result of a +// function or a cast would not be usable with Callback<> or Bind(). +template <typename T> +struct CallbackParamTraitsForMoveOnlyType { + typedef T ForwardType; + typedef T StorageType; +}; + +// CallbackForward() is a very limited simulation of C++11's std::forward() +// used by the Callback/Bind system for a set of movable-but-not-copyable +// types. It is needed because forwarding a movable-but-not-copyable +// argument to another function requires us to invoke the proper move +// operator to create a rvalue version of the type. The supported types are +// whitelisted below as overloads of the CallbackForward() function. The +// default template compiles out to be a no-op. +// +// In C++11, std::forward would replace all uses of this function. However, it +// is impossible to implement a general std::forward with C++11 due to a lack +// of rvalue references. +// +// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to +// simulate std::forward() and forward the result of one Callback as a +// parameter to another callback. This is to support Callbacks that return +// the movable-but-not-copyable types whitelisted above. +template <typename T> +typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward( + T& t) { + return t; +} + +template <typename T> +typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward( + T& t) { + return t.Pass(); +} + +// Overload base::internal::CallbackForward() to forward unique_ptr and common +// containers with unique_ptr by using std::move instead of default T::Pass() +// used with scoped_ptr<U>. +template <typename T, typename D> +std::unique_ptr<T, D> CallbackForward(std::unique_ptr<T, D>& t) { + return std::move(t); +} + +template <typename T, typename D, typename A> +std::vector<std::unique_ptr<T, D>, A> +CallbackForward(std::vector<std::unique_ptr<T, D>, A>& t) { + return std::move(t); +} + +template <typename K, typename T, typename D, typename C, typename A> +std::map<K, std::unique_ptr<T, D>, C, A> +CallbackForward(std::map<K, std::unique_ptr<T, D>, C, A>& t) { + return std::move(t); +} + +} // namespace internal +} // namespace base + +#endif // BASE_CALLBACK_INTERNAL_H_ diff --git a/third_party/chromium/base/callback_list.h b/third_party/chromium/base/callback_list.h new file mode 100644 index 0000000..aeed5f1 --- /dev/null +++ b/third_party/chromium/base/callback_list.h @@ -0,0 +1,230 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_CALLBACK_LIST_H_ +#define BASE_CALLBACK_LIST_H_ + +#include <list> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/callback_internal.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" + +// OVERVIEW: +// +// A container for a list of callbacks. Unlike a normal STL vector or list, +// this container can be modified during iteration without invalidating the +// iterator. It safely handles the case of a callback removing itself +// or another callback from the list while callbacks are being run. +// +// TYPICAL USAGE: +// +// class MyWidget { +// public: +// ... +// +// typedef base::Callback<void(const Foo&)> OnFooCallback; +// +// scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription> +// RegisterCallback(const OnFooCallback& cb) { +// return callback_list_.Add(cb); +// } +// +// private: +// void NotifyFoo(const Foo& foo) { +// callback_list_.Notify(foo); +// } +// +// base::CallbackList<void(const Foo&)> callback_list_; +// +// DISALLOW_COPY_AND_ASSIGN(MyWidget); +// }; +// +// +// class MyWidgetListener { +// public: +// MyWidgetListener::MyWidgetListener() { +// foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback( +// base::Bind(&MyWidgetListener::OnFoo, this))); +// } +// +// MyWidgetListener::~MyWidgetListener() { +// // Subscription gets deleted automatically and will deregister +// // the callback in the process. +// } +// +// private: +// void OnFoo(const Foo& foo) { +// // Do something. +// } +// +// scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription> +// foo_subscription_; +// +// DISALLOW_COPY_AND_ASSIGN(MyWidgetListener); +// }; + +namespace base { + +namespace internal { + +template <typename CallbackType> +class CallbackListBase { + public: + class Subscription { + public: + Subscription(CallbackListBase<CallbackType>* list, + typename std::list<CallbackType>::iterator iter) + : list_(list), + iter_(iter) { + } + + ~Subscription() { + if (list_->active_iterator_count_) { + iter_->Reset(); + } else { + list_->callbacks_.erase(iter_); + if (!list_->removal_callback_.is_null()) + list_->removal_callback_.Run(); + } + } + + private: + CallbackListBase<CallbackType>* list_; + typename std::list<CallbackType>::iterator iter_; + + DISALLOW_COPY_AND_ASSIGN(Subscription); + }; + + // Add a callback to the list. The callback will remain registered until the + // returned Subscription is destroyed, which must occur before the + // CallbackList is destroyed. + scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT { + DCHECK(!cb.is_null()); + return scoped_ptr<Subscription>( + new Subscription(this, callbacks_.insert(callbacks_.end(), cb))); + } + + // Sets a callback which will be run when a subscription list is changed. + void set_removal_callback(const Closure& callback) { + removal_callback_ = callback; + } + + // Returns true if there are no subscriptions. This is only valid to call when + // not looping through the list. + bool empty() { + DCHECK_EQ(0, active_iterator_count_); + return callbacks_.empty(); + } + + protected: + // An iterator class that can be used to access the list of callbacks. + class Iterator { + public: + explicit Iterator(CallbackListBase<CallbackType>* list) + : list_(list), + list_iter_(list_->callbacks_.begin()) { + ++list_->active_iterator_count_; + } + + Iterator(const Iterator& iter) + : list_(iter.list_), + list_iter_(iter.list_iter_) { + ++list_->active_iterator_count_; + } + + ~Iterator() { + if (list_ && --list_->active_iterator_count_ == 0) { + list_->Compact(); + } + } + + CallbackType* GetNext() { + while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null()) + ++list_iter_; + + CallbackType* cb = NULL; + if (list_iter_ != list_->callbacks_.end()) { + cb = &(*list_iter_); + ++list_iter_; + } + return cb; + } + + private: + CallbackListBase<CallbackType>* list_; + typename std::list<CallbackType>::iterator list_iter_; + }; + + CallbackListBase() : active_iterator_count_(0) {} + + ~CallbackListBase() { + DCHECK_EQ(0, active_iterator_count_); + DCHECK_EQ(0U, callbacks_.size()); + } + + // Returns an instance of a CallbackListBase::Iterator which can be used + // to run callbacks. + Iterator GetIterator() { + return Iterator(this); + } + + // Compact the list: remove any entries which were NULLed out during + // iteration. + void Compact() { + typename std::list<CallbackType>::iterator it = callbacks_.begin(); + bool updated = false; + while (it != callbacks_.end()) { + if ((*it).is_null()) { + updated = true; + it = callbacks_.erase(it); + } else { + ++it; + } + + if (updated && !removal_callback_.is_null()) + removal_callback_.Run(); + } + } + + private: + std::list<CallbackType> callbacks_; + int active_iterator_count_; + Closure removal_callback_; + + DISALLOW_COPY_AND_ASSIGN(CallbackListBase); +}; + +} // namespace internal + +template <typename Sig> class CallbackList; + +template <typename... Args> +class CallbackList<void(Args...)> + : public internal::CallbackListBase<Callback<void(Args...)> > { + public: + typedef Callback<void(Args...)> CallbackType; + + CallbackList() {} + + void Notify( + typename internal::CallbackParamTraits<Args>::ForwardType... args) { + typename internal::CallbackListBase<CallbackType>::Iterator it = + this->GetIterator(); + CallbackType* cb; + while ((cb = it.GetNext()) != NULL) { + cb->Run(args...); + } + } + + private: + DISALLOW_COPY_AND_ASSIGN(CallbackList); +}; + +} // namespace base + +#endif // BASE_CALLBACK_LIST_H_ diff --git a/third_party/chromium/base/callback_list_unittest.cc b/third_party/chromium/base/callback_list_unittest.cc new file mode 100644 index 0000000..3b50622 --- /dev/null +++ b/third_party/chromium/base/callback_list_unittest.cc @@ -0,0 +1,292 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/callback_list.h" + +#include <gtest/gtest.h> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/scoped_ptr.h" + +namespace base { +namespace { + +class Listener { + public: + Listener() : total_(0), scaler_(1) {} + explicit Listener(int scaler) : total_(0), scaler_(scaler) {} + void IncrementTotal() { total_++; } + void IncrementByMultipleOfScaler(int x) { total_ += x * scaler_; } + + int total() const { return total_; } + + private: + int total_; + int scaler_; + DISALLOW_COPY_AND_ASSIGN(Listener); +}; + +class Remover { + public: + Remover() : total_(0) {} + void IncrementTotalAndRemove() { + total_++; + removal_subscription_.reset(); + } + void SetSubscriptionToRemove( + scoped_ptr<CallbackList<void(void)>::Subscription> sub) { + removal_subscription_ = sub.Pass(); + } + + int total() const { return total_; } + + private: + int total_; + scoped_ptr<CallbackList<void(void)>::Subscription> removal_subscription_; + DISALLOW_COPY_AND_ASSIGN(Remover); +}; + +class Adder { + public: + explicit Adder(CallbackList<void(void)>* cb_reg) + : added_(false), + total_(0), + cb_reg_(cb_reg) { + } + void AddCallback() { + if (!added_) { + added_ = true; + subscription_ = + cb_reg_->Add(Bind(&Adder::IncrementTotal, Unretained(this))); + } + } + void IncrementTotal() { total_++; } + + bool added() const { return added_; } + + int total() const { return total_; } + + private: + bool added_; + int total_; + CallbackList<void(void)>* cb_reg_; + scoped_ptr<CallbackList<void(void)>::Subscription> subscription_; + DISALLOW_COPY_AND_ASSIGN(Adder); +}; + +class Summer { + public: + Summer() : value_(0) {} + + void AddOneParam(int a) { value_ = a; } + void AddTwoParam(int a, int b) { value_ = a + b; } + void AddThreeParam(int a, int b, int c) { value_ = a + b + c; } + void AddFourParam(int a, int b, int c, int d) { value_ = a + b + c + d; } + void AddFiveParam(int a, int b, int c, int d, int e) { + value_ = a + b + c + d + e; + } + void AddSixParam(int a, int b, int c, int d, int e , int f) { + value_ = a + b + c + d + e + f; + } + + int value() const { return value_; } + + private: + int value_; + DISALLOW_COPY_AND_ASSIGN(Summer); +}; + +// Sanity check that we can instantiate a CallbackList for each arity. +TEST(CallbackListTest, ArityTest) { + Summer s; + + CallbackList<void(int)> c1; + scoped_ptr<CallbackList<void(int)>::Subscription> subscription1 = + c1.Add(Bind(&Summer::AddOneParam, Unretained(&s))); + + c1.Notify(1); + EXPECT_EQ(1, s.value()); + + CallbackList<void(int, int)> c2; + scoped_ptr<CallbackList<void(int, int)>::Subscription> subscription2 = + c2.Add(Bind(&Summer::AddTwoParam, Unretained(&s))); + + c2.Notify(1, 2); + EXPECT_EQ(3, s.value()); + + CallbackList<void(int, int, int)> c3; + scoped_ptr<CallbackList<void(int, int, int)>::Subscription> + subscription3 = c3.Add(Bind(&Summer::AddThreeParam, Unretained(&s))); + + c3.Notify(1, 2, 3); + EXPECT_EQ(6, s.value()); + + CallbackList<void(int, int, int, int)> c4; + scoped_ptr<CallbackList<void(int, int, int, int)>::Subscription> + subscription4 = c4.Add(Bind(&Summer::AddFourParam, Unretained(&s))); + + c4.Notify(1, 2, 3, 4); + EXPECT_EQ(10, s.value()); + + CallbackList<void(int, int, int, int, int)> c5; + scoped_ptr<CallbackList<void(int, int, int, int, int)>::Subscription> + subscription5 = c5.Add(Bind(&Summer::AddFiveParam, Unretained(&s))); + + c5.Notify(1, 2, 3, 4, 5); + EXPECT_EQ(15, s.value()); + + CallbackList<void(int, int, int, int, int, int)> c6; + scoped_ptr<CallbackList<void(int, int, int, int, int, int)>::Subscription> + subscription6 = c6.Add(Bind(&Summer::AddSixParam, Unretained(&s))); + + c6.Notify(1, 2, 3, 4, 5, 6); + EXPECT_EQ(21, s.value()); +} + +// Sanity check that closures added to the list will be run, and those removed +// from the list will not be run. +TEST(CallbackListTest, BasicTest) { + CallbackList<void(void)> cb_reg; + Listener a, b, c; + + scoped_ptr<CallbackList<void(void)>::Subscription> a_subscription = + cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a))); + scoped_ptr<CallbackList<void(void)>::Subscription> b_subscription = + cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b))); + + EXPECT_TRUE(a_subscription.get()); + EXPECT_TRUE(b_subscription.get()); + + cb_reg.Notify(); + + EXPECT_EQ(1, a.total()); + EXPECT_EQ(1, b.total()); + + b_subscription.reset(); + + scoped_ptr<CallbackList<void(void)>::Subscription> c_subscription = + cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&c))); + + cb_reg.Notify(); + + EXPECT_EQ(2, a.total()); + EXPECT_EQ(1, b.total()); + EXPECT_EQ(1, c.total()); + + a_subscription.reset(); + b_subscription.reset(); + c_subscription.reset(); +} + +// Sanity check that callbacks with details added to the list will be run, with +// the correct details, and those removed from the list will not be run. +TEST(CallbackListTest, BasicTestWithParams) { + CallbackList<void(int)> cb_reg; + Listener a(1), b(-1), c(1); + + scoped_ptr<CallbackList<void(int)>::Subscription> a_subscription = + cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&a))); + scoped_ptr<CallbackList<void(int)>::Subscription> b_subscription = + cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&b))); + + EXPECT_TRUE(a_subscription.get()); + EXPECT_TRUE(b_subscription.get()); + + cb_reg.Notify(10); + + EXPECT_EQ(10, a.total()); + EXPECT_EQ(-10, b.total()); + + b_subscription.reset(); + + scoped_ptr<CallbackList<void(int)>::Subscription> c_subscription = + cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&c))); + + cb_reg.Notify(10); + + EXPECT_EQ(20, a.total()); + EXPECT_EQ(-10, b.total()); + EXPECT_EQ(10, c.total()); + + a_subscription.reset(); + b_subscription.reset(); + c_subscription.reset(); +} + +// Test the a callback can remove itself or a different callback from the list +// during iteration without invalidating the iterator. +TEST(CallbackListTest, RemoveCallbacksDuringIteration) { + CallbackList<void(void)> cb_reg; + Listener a, b; + Remover remover_1, remover_2; + + scoped_ptr<CallbackList<void(void)>::Subscription> remover_1_sub = + cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove, + Unretained(&remover_1))); + scoped_ptr<CallbackList<void(void)>::Subscription> remover_2_sub = + cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove, + Unretained(&remover_2))); + scoped_ptr<CallbackList<void(void)>::Subscription> a_subscription = + cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a))); + scoped_ptr<CallbackList<void(void)>::Subscription> b_subscription = + cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b))); + + // |remover_1| will remove itself. + remover_1.SetSubscriptionToRemove(remover_1_sub.Pass()); + // |remover_2| will remove a. + remover_2.SetSubscriptionToRemove(a_subscription.Pass()); + + cb_reg.Notify(); + + // |remover_1| runs once (and removes itself), |remover_2| runs once (and + // removes a), |a| never runs, and |b| runs once. + EXPECT_EQ(1, remover_1.total()); + EXPECT_EQ(1, remover_2.total()); + EXPECT_EQ(0, a.total()); + EXPECT_EQ(1, b.total()); + + cb_reg.Notify(); + + // Only |remover_2| and |b| run this time. + EXPECT_EQ(1, remover_1.total()); + EXPECT_EQ(2, remover_2.total()); + EXPECT_EQ(0, a.total()); + EXPECT_EQ(2, b.total()); +} + +// Test that a callback can add another callback to the list durning iteration +// without invalidating the iterator. The newly added callback should be run on +// the current iteration as will all other callbacks in the list. +TEST(CallbackListTest, AddCallbacksDuringIteration) { + CallbackList<void(void)> cb_reg; + Adder a(&cb_reg); + Listener b; + scoped_ptr<CallbackList<void(void)>::Subscription> a_subscription = + cb_reg.Add(Bind(&Adder::AddCallback, Unretained(&a))); + scoped_ptr<CallbackList<void(void)>::Subscription> b_subscription = + cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b))); + + cb_reg.Notify(); + + EXPECT_EQ(1, a.total()); + EXPECT_EQ(1, b.total()); + EXPECT_TRUE(a.added()); + + cb_reg.Notify(); + + EXPECT_EQ(2, a.total()); + EXPECT_EQ(2, b.total()); +} + +// Sanity check: notifying an empty list is a no-op. +TEST(CallbackListTest, EmptyList) { + CallbackList<void(void)> cb_reg; + + cb_reg.Notify(); +} + +} // namespace +} // namespace base diff --git a/third_party/chromium/base/callback_unittest.cc b/third_party/chromium/base/callback_unittest.cc new file mode 100644 index 0000000..3630176 --- /dev/null +++ b/third_party/chromium/base/callback_unittest.cc @@ -0,0 +1,184 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/callback.h" + +#include <gtest/gtest.h> + +#include "base/bind.h" +#include "base/callback_internal.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" + +namespace base { + +namespace { + +struct FakeInvoker { + typedef void(RunType)(internal::BindStateBase*); + static void Run(internal::BindStateBase*) { + } +}; + +} // namespace + +namespace internal { +template <typename Runnable, typename RunType, typename BoundArgsType> +struct BindState; + +// White-box testpoints to inject into a Callback<> object for checking +// comparators and emptiness APIs. Use a BindState that is specialized +// based on a type we declared in the anonymous namespace above to remove any +// chance of colliding with another instantiation and breaking the +// one-definition-rule. +template <> +struct BindState<void(void), void(void), void(FakeInvoker)> + : public BindStateBase { + public: + BindState() : BindStateBase(&Destroy) {} + typedef FakeInvoker InvokerType; + private: + ~BindState() {} + static void Destroy(BindStateBase* self) { + delete static_cast<BindState*>(self); + } +}; + +template <> +struct BindState<void(void), void(void), + void(FakeInvoker, FakeInvoker)> + : public BindStateBase { + public: + BindState() : BindStateBase(&Destroy) {} + typedef FakeInvoker InvokerType; + private: + ~BindState() {} + static void Destroy(BindStateBase* self) { + delete static_cast<BindState*>(self); + } +}; +} // namespace internal + +namespace { + +typedef internal::BindState<void(void), void(void), void(FakeInvoker)> + FakeBindState1; +typedef internal::BindState<void(void), void(void), + void(FakeInvoker, FakeInvoker)> + FakeBindState2; + +class CallbackTest : public ::testing::Test { + public: + CallbackTest() + : callback_a_(new FakeBindState1()), + callback_b_(new FakeBindState2()) { + } + + ~CallbackTest() override {} + + 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(new FakeBindState1()); + 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_)); +} + +struct TestForReentrancy { + TestForReentrancy() + : cb_already_run(false), + cb(Bind(&TestForReentrancy::AssertCBIsNull, Unretained(this))) { + } + void AssertCBIsNull() { + ASSERT_TRUE(cb.is_null()); + cb_already_run = true; + } + bool cb_already_run; + Closure cb; +}; + +class CallbackOwner : public base::RefCounted<CallbackOwner> { + public: + explicit CallbackOwner(bool* deleted) { + callback_ = Bind(&CallbackOwner::Unused, this); + deleted_ = deleted; + } + void Reset() { + callback_.Reset(); + // We are deleted here if no-one else had a ref to us. + } + + private: + friend class base::RefCounted<CallbackOwner>; + virtual ~CallbackOwner() { + *deleted_ = true; + } + void Unused() { + FAIL() << "Should never be called"; + } + + Closure callback_; + bool* deleted_; +}; + +TEST_F(CallbackTest, CallbackHasLastRefOnContainingObject) { + bool deleted = false; + CallbackOwner* owner = new CallbackOwner(&deleted); + owner->Reset(); + ASSERT_TRUE(deleted); +} + +} // namespace +} // namespace base diff --git a/third_party/chromium/base/command_line.h b/third_party/chromium/base/command_line.h new file mode 100644 index 0000000..686c978 --- /dev/null +++ b/third_party/chromium/base/command_line.h @@ -0,0 +1,31 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This class works with command lines: building and parsing. +// Arguments with prefixes ('--', '-', and on Windows, '/') are switches. +// Switches will precede all other arguments without switch prefixes. +// Switches can optionally have values, delimited by '=', e.g., "-switch=value". +// An argument of "--" will terminate switch parsing during initialization, +// interpreting subsequent tokens as non-switch arguments, regardless of prefix. + +// There is a singleton read-only CommandLine that represents the command line +// that the current process was started with. It must be initialized in main(). + +#ifndef BASE_COMMAND_LINE_H_ +#define BASE_COMMAND_LINE_H_ + +#include <stddef.h> + +#include "base/base_export.h" + +namespace base { + +class CommandLine { + public: + static bool Init(int argc, const char* const* argv) { return true; } +}; + +} // namespace base + +#endif // BASE_COMMAND_LINE_H_ diff --git a/third_party/chromium/base/compiler_specific.h b/third_party/chromium/base/compiler_specific.h new file mode 100644 index 0000000..8c2ba34 --- /dev/null +++ b/third_party/chromium/base/compiler_specific.h @@ -0,0 +1,207 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_COMPILER_SPECIFIC_H_ +#define BASE_COMPILER_SPECIFIC_H_ + +#include "base/build/build_config.h" + +#if defined(COMPILER_MSVC) + +// Macros for suppressing and disabling warnings on MSVC. +// +// Warning numbers are enumerated at: +// http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx +// +// The warning pragma: +// http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx +// +// Using __pragma instead of #pragma inside macros: +// http://msdn.microsoft.com/en-us/library/d9x1s805.aspx + +// MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and +// for the next line of the source file. +#define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n)) + +// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled. +// The warning remains disabled until popped by MSVC_POP_WARNING. +#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ + __pragma(warning(disable:n)) + +// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level. The level +// remains in effect until popped by MSVC_POP_WARNING(). Use 0 to disable all +// warnings. +#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n)) + +// Pop effects of innermost MSVC_PUSH_* macro. +#define MSVC_POP_WARNING() __pragma(warning(pop)) + +#define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off)) +#define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on)) + +// Allows exporting a class that inherits from a non-exported base class. +// This uses suppress instead of push/pop because the delimiter after the +// declaration (either "," or "{") has to be placed before the pop macro. +// +// Example usage: +// class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) { +// +// MSVC Compiler warning C4275: +// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'. +// Note that this is intended to be used only when no access to the base class' +// static data is done through derived classes or inline methods. For more info, +// see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx +#define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \ + code + +#else // Not MSVC + +#define MSVC_SUPPRESS_WARNING(n) +#define MSVC_PUSH_DISABLE_WARNING(n) +#define MSVC_PUSH_WARNING_LEVEL(n) +#define MSVC_POP_WARNING() +#define MSVC_DISABLE_OPTIMIZE() +#define MSVC_ENABLE_OPTIMIZE() +#define NON_EXPORTED_BASE(code) code + +#endif // COMPILER_MSVC + + +// The C++ standard requires that static const members have an out-of-class +// definition (in a single compilation unit), but MSVC chokes on this (when +// language extensions, which are required, are enabled). (You're only likely to +// notice the need for a definition if you take the address of the member or, +// more commonly, pass it to a function that takes it as a reference argument -- +// probably an STL function.) This macro makes MSVC do the right thing. See +// http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx for more +// information. Use like: +// +// In .h file: +// struct Foo { +// static const int kBar = 5; +// }; +// +// In .cc file: +// STATIC_CONST_MEMBER_DEFINITION const int Foo::kBar; +#if defined(COMPILER_MSVC) +#define STATIC_CONST_MEMBER_DEFINITION __declspec(selectany) +#else +#define STATIC_CONST_MEMBER_DEFINITION +#endif + +// Annotate a variable indicating it's ok if the variable is not used. +// (Typically used to silence a compiler warning when the assignment +// is important for some other reason.) +// Use like: +// int x = ...; +// ALLOW_UNUSED_LOCAL(x); +#define ALLOW_UNUSED_LOCAL(x) false ? (void)x : (void)0 + +// Annotate a typedef or function indicating it's ok if it's not used. +// Use like: +// typedef Foo Bar ALLOW_UNUSED_TYPE; +#if defined(COMPILER_GCC) +#define ALLOW_UNUSED_TYPE __attribute__((unused)) +#else +#define ALLOW_UNUSED_TYPE +#endif + +// Annotate a function indicating it should not be inlined. +// Use like: +// NOINLINE void DoStuff() { ... } +#if defined(COMPILER_GCC) +#define NOINLINE __attribute__((noinline)) +#elif defined(COMPILER_MSVC) +#define NOINLINE __declspec(noinline) +#else +#define NOINLINE +#endif + +// Specify memory alignment for structs, classes, etc. +// Use like: +// class ALIGNAS(16) MyClass { ... } +// ALIGNAS(16) int array[4]; +#if defined(COMPILER_MSVC) +#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment)) +#elif defined(COMPILER_GCC) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#endif + +// Return the byte alignment of the given type (available at compile time). +// Use like: +// ALIGNOF(int32) // this would be 4 +#if defined(COMPILER_MSVC) +#define ALIGNOF(type) __alignof(type) +#elif defined(COMPILER_GCC) +#define ALIGNOF(type) __alignof__(type) +#endif + +// Annotate a function indicating the caller must examine the return value. +// Use like: +// int foo() WARN_UNUSED_RESULT; +// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>. +#if defined(COMPILER_GCC) +#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define WARN_UNUSED_RESULT +#endif + +// Tell the compiler a function is using a printf-style format string. +// |format_param| is the one-based index of the format string parameter; +// |dots_param| is the one-based index of the "..." parameter. +// For v*printf functions (which take a va_list), pass 0 for dots_param. +// (This is undocumented but matches what the system C headers do.) +#if defined(COMPILER_GCC) +#define PRINTF_FORMAT(format_param, dots_param) \ + __attribute__((format(printf, format_param, dots_param))) +#else +#define PRINTF_FORMAT(format_param, dots_param) +#endif + +// WPRINTF_FORMAT is the same, but for wide format strings. +// This doesn't appear to yet be implemented in any compiler. +// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 . +#define WPRINTF_FORMAT(format_param, dots_param) +// If available, it would look like: +// __attribute__((format(wprintf, format_param, dots_param))) + +// MemorySanitizer annotations. +#if defined(MEMORY_SANITIZER) && !defined(OS_NACL) +#include <sanitizer/msan_interface.h> + +// Mark a memory region fully initialized. +// Use this to annotate code that deliberately reads uninitialized data, for +// example a GC scavenging root set pointers from the stack. +#define MSAN_UNPOISON(p, size) __msan_unpoison(p, size) + +// Check a memory region for initializedness, as if it was being used here. +// If any bits are uninitialized, crash with an MSan report. +// Use this to sanitize data which MSan won't be able to track, e.g. before +// passing data to another process via shared memory. +#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) \ + __msan_check_mem_is_initialized(p, size) +#else // MEMORY_SANITIZER +#define MSAN_UNPOISON(p, size) +#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) +#endif // MEMORY_SANITIZER + +// Macro useful for writing cross-platform function pointers. +#if !defined(CDECL) +#if defined(OS_WIN) +#define CDECL __cdecl +#else // defined(OS_WIN) +#define CDECL +#endif // defined(OS_WIN) +#endif // !defined(CDECL) + +// Macro for hinting that an expression is likely to be false. +#if !defined(UNLIKELY) +#if defined(COMPILER_GCC) +#define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define UNLIKELY(x) (x) +#endif // defined(COMPILER_GCC) +#endif // !defined(UNLIKELY) + +#endif // BASE_COMPILER_SPECIFIC_H_ diff --git a/third_party/chromium/base/gtest_prod_util.h b/third_party/chromium/base/gtest_prod_util.h new file mode 100644 index 0000000..b90cd4e --- /dev/null +++ b/third_party/chromium/base/gtest_prod_util.h @@ -0,0 +1,66 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_GTEST_PROD_UTIL_H_ +#define BASE_GTEST_PROD_UTIL_H_ + +#include <gtest/gtest_prod.h> + +// This is a wrapper for gtest's FRIEND_TEST macro that friends +// test with all possible prefixes. This is very helpful when changing the test +// prefix, because the friend declarations don't need to be updated. +// +// Example usage: +// +// class MyClass { +// private: +// void MyMethod(); +// FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod); +// }; +#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \ + FRIEND_TEST(test_case_name, test_name); \ + FRIEND_TEST(test_case_name, DISABLED_##test_name); \ + FRIEND_TEST(test_case_name, FLAKY_##test_name) + +// C++ compilers will refuse to compile the following code: +// +// namespace foo { +// class MyClass { +// private: +// FRIEND_TEST_ALL_PREFIXES(MyClassTest, TestMethod); +// bool private_var; +// }; +// } // namespace foo +// +// class MyClassTest::TestMethod() { +// foo::MyClass foo_class; +// foo_class.private_var = true; +// } +// +// Unless you forward declare MyClassTest::TestMethod outside of namespace foo. +// Use FORWARD_DECLARE_TEST to do so for all possible prefixes. +// +// Example usage: +// +// FORWARD_DECLARE_TEST(MyClassTest, TestMethod); +// +// namespace foo { +// class MyClass { +// private: +// FRIEND_TEST_ALL_PREFIXES(::MyClassTest, TestMethod); // NOTE use of :: +// bool private_var; +// }; +// } // namespace foo +// +// class MyClassTest::TestMethod() { +// foo::MyClass foo_class; +// foo_class.private_var = true; +// } + +#define FORWARD_DECLARE_TEST(test_case_name, test_name) \ + class test_case_name##_##test_name##_Test; \ + class test_case_name##_##DISABLED_##test_name##_Test; \ + class test_case_name##_##FLAKY_##test_name##_Test + +#endif // BASE_GTEST_PROD_UTIL_H_ diff --git a/third_party/chromium/base/guid.h b/third_party/chromium/base/guid.h new file mode 100644 index 0000000..a43a223 --- /dev/null +++ b/third_party/chromium/base/guid.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_GUID_H_ +#define BASE_GUID_H_ + +#include <string> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/build/build_config.h" + +namespace base { + +// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX". +// If GUID generation fails an empty string is returned. +// The POSIX implementation uses pseudo random number generation to create +// the GUID. The Windows implementation uses system services. +std::string GenerateGUID(); + +#if defined(OS_POSIX) +// For unit testing purposes only. Do not use outside of tests. +std::string RandomDataToGUIDString(const uint64 bytes[2]); +#endif + +} // namespace base + +#endif // BASE_GUID_H_ diff --git a/third_party/chromium/base/guid_posix.cc b/third_party/chromium/base/guid_posix.cc new file mode 100644 index 0000000..f0fedc2 --- /dev/null +++ b/third_party/chromium/base/guid_posix.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/guid.h" + +#include "base/rand_util.h" +#include "base/strings/stringprintf.h" + +namespace base { + +std::string GenerateGUID() { + uint64 sixteen_bytes[2] = { base::RandUint64(), base::RandUint64() }; + + // Set the GUID to version 4 as described in RFC 4122, section 4.4. + // The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, + // where y is one of [8, 9, A, B]. + + // Clear the version bits and set the version to 4: + sixteen_bytes[0] &= 0xffffffffffff0fffULL; + sixteen_bytes[0] |= 0x0000000000004000ULL; + + // Set the two most significant bits (bits 6 and 7) of the + // clock_seq_hi_and_reserved to zero and one, respectively: + sixteen_bytes[1] &= 0x3fffffffffffffffULL; + sixteen_bytes[1] |= 0x8000000000000000ULL; + + return RandomDataToGUIDString(sixteen_bytes); +} + +// TODO(cmasone): Once we're comfortable this works, migrate Windows code to +// use this as well. +std::string RandomDataToGUIDString(const uint64 bytes[2]) { + return StringPrintf("%08X-%04X-%04X-%04X-%012llX", + static_cast<unsigned int>(bytes[0] >> 32), + static_cast<unsigned int>((bytes[0] >> 16) & 0x0000ffff), + static_cast<unsigned int>(bytes[0] & 0x0000ffff), + static_cast<unsigned int>(bytes[1] >> 48), + bytes[1] & 0x0000ffffffffffffULL); +} + +} // namespace base diff --git a/third_party/chromium/base/guid_unittest.cc b/third_party/chromium/base/guid_unittest.cc new file mode 100644 index 0000000..37b4edc --- /dev/null +++ b/third_party/chromium/base/guid_unittest.cc @@ -0,0 +1,91 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/guid.h" + +#include <limits> + +#include <gtest/gtest.h> + +#include "base/strings/string_util.h" + +namespace base { + +#if defined(OS_POSIX) + +namespace { + +template <typename Char> +inline bool IsHexDigit(Char c) { + return (c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f'); +} + +bool IsValidGUID(const std::string& guid) { + const size_t kGUIDLength = 36U; + if (guid.length() != kGUIDLength) + return false; + + for (size_t i = 0; i < guid.length(); ++i) { + char current = guid[i]; + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (current != '-') + return false; + } else { + if (!IsHexDigit(current)) + return false; + } + } + + return true; +} + +bool IsGUIDv4(const std::string& guid) { + // The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, + // where y is one of [8, 9, A, B]. + return IsValidGUID(guid) && guid[14] == '4' && + (guid[19] == '8' || guid[19] == '9' || guid[19] == 'A' || + guid[19] == 'a' || guid[19] == 'B' || guid[19] == 'b'); +} + +} // namespace + +TEST(GUIDTest, GUIDGeneratesAllZeroes) { + uint64 bytes[] = { 0, 0 }; + std::string clientid = RandomDataToGUIDString(bytes); + EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid); +} + +TEST(GUIDTest, GUIDGeneratesCorrectly) { + uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL }; + std::string clientid = RandomDataToGUIDString(bytes); + EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid); +} +#endif + +TEST(GUIDTest, GUIDCorrectlyFormatted) { + const int kIterations = 10; + for (int it = 0; it < kIterations; ++it) { + std::string guid = GenerateGUID(); + EXPECT_TRUE(IsValidGUID(guid)); + } +} + +TEST(GUIDTest, GUIDBasicUniqueness) { + const int kIterations = 10; + for (int it = 0; it < kIterations; ++it) { + std::string guid1 = GenerateGUID(); + std::string guid2 = GenerateGUID(); + EXPECT_EQ(36U, guid1.length()); + EXPECT_EQ(36U, guid2.length()); + EXPECT_NE(guid1, guid2); +#if defined(OS_POSIX) + EXPECT_TRUE(IsGUIDv4(guid1)); + EXPECT_TRUE(IsGUIDv4(guid2)); +#endif + } +} + +} // namespace base diff --git a/third_party/chromium/base/json/json_parser.cc b/third_party/chromium/base/json/json_parser.cc new file mode 100644 index 0000000..964fcd4 --- /dev/null +++ b/third_party/chromium/base/json/json_parser.cc @@ -0,0 +1,961 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/json/json_parser.h" + +#include <cmath> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversion_utils.h" +#include "base/third_party/icu/icu_utf.h" +#include "base/values.h" + +namespace base { +namespace internal { + +namespace { + +const int kStackMaxDepth = 100; + +const int32 kExtendedASCIIStart = 0x80; + +// This and the class below are used to own the JSON input string for when +// string tokens are stored as StringPiece instead of std::string. This +// optimization avoids about 2/3rds of string memory copies. The constructor +// takes ownership of the input string. The real root value is Swap()ed into +// the new instance. +class DictionaryHiddenRootValue : public base::DictionaryValue { + public: + DictionaryHiddenRootValue(std::string* json, Value* root) : json_(json) { + DCHECK(root->IsType(Value::TYPE_DICTIONARY)); + DictionaryValue::Swap(static_cast<DictionaryValue*>(root)); + } + + void Swap(DictionaryValue* other) override { + DVLOG(1) << "Swap()ing a DictionaryValue inefficiently."; + + // First deep copy to convert JSONStringValue to std::string and swap that + // copy with |other|, which contains the new contents of |this|. + scoped_ptr<base::DictionaryValue> copy(DeepCopy()); + copy->Swap(other); + + // Then erase the contents of the current dictionary and swap in the + // new contents, originally from |other|. + Clear(); + json_.reset(); + DictionaryValue::Swap(copy.get()); + } + + // Not overriding DictionaryValue::Remove because it just calls through to + // the method below. + + bool RemoveWithoutPathExpansion(const std::string& key, + scoped_ptr<Value>* out) override { + // If the caller won't take ownership of the removed value, just call up. + if (!out) + return DictionaryValue::RemoveWithoutPathExpansion(key, out); + + DVLOG(1) << "Remove()ing from a DictionaryValue inefficiently."; + + // Otherwise, remove the value while its still "owned" by this and copy it + // to convert any JSONStringValues to std::string. + scoped_ptr<Value> out_owned; + if (!DictionaryValue::RemoveWithoutPathExpansion(key, &out_owned)) + return false; + + out->reset(out_owned->DeepCopy()); + + return true; + } + + private: + scoped_ptr<std::string> json_; + + DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue); +}; + +class ListHiddenRootValue : public base::ListValue { + public: + ListHiddenRootValue(std::string* json, Value* root) : json_(json) { + DCHECK(root->IsType(Value::TYPE_LIST)); + ListValue::Swap(static_cast<ListValue*>(root)); + } + + void Swap(ListValue* other) override { + DVLOG(1) << "Swap()ing a ListValue inefficiently."; + + // First deep copy to convert JSONStringValue to std::string and swap that + // copy with |other|, which contains the new contents of |this|. + scoped_ptr<base::ListValue> copy(DeepCopy()); + copy->Swap(other); + + // Then erase the contents of the current list and swap in the new contents, + // originally from |other|. + Clear(); + json_.reset(); + ListValue::Swap(copy.get()); + } + + bool Remove(size_t index, scoped_ptr<Value>* out) override { + // If the caller won't take ownership of the removed value, just call up. + if (!out) + return ListValue::Remove(index, out); + + DVLOG(1) << "Remove()ing from a ListValue inefficiently."; + + // Otherwise, remove the value while its still "owned" by this and copy it + // to convert any JSONStringValues to std::string. + scoped_ptr<Value> out_owned; + if (!ListValue::Remove(index, &out_owned)) + return false; + + out->reset(out_owned->DeepCopy()); + + return true; + } + + private: + scoped_ptr<std::string> json_; + + DISALLOW_COPY_AND_ASSIGN(ListHiddenRootValue); +}; + +// A variant on StringValue that uses StringPiece instead of copying the string +// into the Value. This can only be stored in a child of hidden root (above), +// otherwise the referenced string will not be guaranteed to outlive it. +class JSONStringValue : public base::Value { + public: + explicit JSONStringValue(const base::StringPiece& piece) + : Value(TYPE_STRING), + string_piece_(piece) { + } + + // Overridden from base::Value: + bool GetAsString(std::string* out_value) const override { + string_piece_.CopyToString(out_value); + return true; + } + Value* DeepCopy() const override { + return new StringValue(string_piece_.as_string()); + } + bool Equals(const Value* other) const override { + std::string other_string; + return other->IsType(TYPE_STRING) && other->GetAsString(&other_string) && + StringPiece(other_string) == string_piece_; + } + + private: + // The location in the original input stream. + base::StringPiece string_piece_; + + DISALLOW_COPY_AND_ASSIGN(JSONStringValue); +}; + +// Simple class that checks for maximum recursion/"stack overflow." +class StackMarker { + public: + explicit StackMarker(int* depth) : depth_(depth) { + ++(*depth_); + DCHECK_LE(*depth_, kStackMaxDepth); + } + ~StackMarker() { + --(*depth_); + } + + bool IsTooDeep() const { + return *depth_ >= kStackMaxDepth; + } + + private: + int* const depth_; + + DISALLOW_COPY_AND_ASSIGN(StackMarker); +}; + +} // namespace + +JSONParser::JSONParser(int options) + : options_(options), + start_pos_(NULL), + pos_(NULL), + end_pos_(NULL), + index_(0), + stack_depth_(0), + line_number_(0), + index_last_line_(0), + error_code_(JSONReader::JSON_NO_ERROR), + error_line_(0), + error_column_(0) { +} + +JSONParser::~JSONParser() { +} + +Value* JSONParser::Parse(const StringPiece& input) { + scoped_ptr<std::string> input_copy; + // If the children of a JSON root can be detached, then hidden roots cannot + // be used, so do not bother copying the input because StringPiece will not + // be used anywhere. + if (!(options_ & JSON_DETACHABLE_CHILDREN)) { + input_copy.reset(new std::string(input.as_string())); + start_pos_ = input_copy->data(); + } else { + start_pos_ = input.data(); + } + pos_ = start_pos_; + end_pos_ = start_pos_ + input.length(); + index_ = 0; + line_number_ = 1; + index_last_line_ = 0; + + error_code_ = JSONReader::JSON_NO_ERROR; + error_line_ = 0; + error_column_ = 0; + + // When the input JSON string starts with a UTF-8 Byte-Order-Mark + // <0xEF 0xBB 0xBF>, advance the start position to avoid the + // ParseNextToken function mis-treating a Unicode BOM as an invalid + // character and returning NULL. + if (CanConsume(3) && static_cast<uint8>(*pos_) == 0xEF && + static_cast<uint8>(*(pos_ + 1)) == 0xBB && + static_cast<uint8>(*(pos_ + 2)) == 0xBF) { + NextNChars(3); + } + + // Parse the first and any nested tokens. + scoped_ptr<Value> root(ParseNextToken()); + if (!root.get()) + return NULL; + + // Make sure the input stream is at an end. + if (GetNextToken() != T_END_OF_INPUT) { + if (!CanConsume(1) || (NextChar() && GetNextToken() != T_END_OF_INPUT)) { + ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1); + return NULL; + } + } + + // Dictionaries and lists can contain JSONStringValues, so wrap them in a + // hidden root. + if (!(options_ & JSON_DETACHABLE_CHILDREN)) { + if (root->IsType(Value::TYPE_DICTIONARY)) { + return new DictionaryHiddenRootValue(input_copy.release(), root.get()); + } else if (root->IsType(Value::TYPE_LIST)) { + return new ListHiddenRootValue(input_copy.release(), root.get()); + } else if (root->IsType(Value::TYPE_STRING)) { + // A string type could be a JSONStringValue, but because there's no + // corresponding HiddenRootValue, the memory will be lost. Deep copy to + // preserve it. + return root->DeepCopy(); + } + } + + // All other values can be returned directly. + return root.release(); +} + +JSONReader::JsonParseError JSONParser::error_code() const { + return error_code_; +} + +std::string JSONParser::GetErrorMessage() const { + return FormatErrorMessage(error_line_, error_column_, + JSONReader::ErrorCodeToString(error_code_)); +} + +// StringBuilder /////////////////////////////////////////////////////////////// + +JSONParser::StringBuilder::StringBuilder() + : pos_(NULL), + length_(0), + string_(NULL) { +} + +JSONParser::StringBuilder::StringBuilder(const char* pos) + : pos_(pos), + length_(0), + string_(NULL) { +} + +void JSONParser::StringBuilder::Swap(StringBuilder* other) { + std::swap(other->string_, string_); + std::swap(other->pos_, pos_); + std::swap(other->length_, length_); +} + +JSONParser::StringBuilder::~StringBuilder() { + delete string_; +} + +void JSONParser::StringBuilder::Append(const char& c) { + DCHECK_GE(c, 0); + DCHECK_LT(c, 128); + + if (string_) + string_->push_back(c); + else + ++length_; +} + +void JSONParser::StringBuilder::AppendString(const std::string& str) { + DCHECK(string_); + string_->append(str); +} + +void JSONParser::StringBuilder::Convert() { + if (string_) + return; + string_ = new std::string(pos_, length_); +} + +bool JSONParser::StringBuilder::CanBeStringPiece() const { + return !string_; +} + +StringPiece JSONParser::StringBuilder::AsStringPiece() { + if (string_) + return StringPiece(); + return StringPiece(pos_, length_); +} + +const std::string& JSONParser::StringBuilder::AsString() { + if (!string_) + Convert(); + return *string_; +} + +// JSONParser private ////////////////////////////////////////////////////////// + +inline bool JSONParser::CanConsume(int length) { + return pos_ + length <= end_pos_; +} + +const char* JSONParser::NextChar() { + DCHECK(CanConsume(1)); + ++index_; + ++pos_; + return pos_; +} + +void JSONParser::NextNChars(int n) { + DCHECK(CanConsume(n)); + index_ += n; + pos_ += n; +} + +JSONParser::Token JSONParser::GetNextToken() { + EatWhitespaceAndComments(); + if (!CanConsume(1)) + return T_END_OF_INPUT; + + switch (*pos_) { + case '{': + return T_OBJECT_BEGIN; + case '}': + return T_OBJECT_END; + case '[': + return T_ARRAY_BEGIN; + case ']': + return T_ARRAY_END; + case '"': + return T_STRING; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return T_NUMBER; + case 't': + return T_BOOL_TRUE; + case 'f': + return T_BOOL_FALSE; + case 'n': + return T_NULL; + case ',': + return T_LIST_SEPARATOR; + case ':': + return T_OBJECT_PAIR_SEPARATOR; + default: + return T_INVALID_TOKEN; + } +} + +void JSONParser::EatWhitespaceAndComments() { + while (pos_ < end_pos_) { + switch (*pos_) { + case '\r': + case '\n': + index_last_line_ = index_; + // Don't increment line_number_ twice for "\r\n". + if (!(*pos_ == '\n' && pos_ > start_pos_ && *(pos_ - 1) == '\r')) + ++line_number_; + // Fall through. + case ' ': + case '\t': + NextChar(); + break; + case '/': + if (!EatComment()) + return; + break; + default: + return; + } + } +} + +bool JSONParser::EatComment() { + if (*pos_ != '/' || !CanConsume(1)) + return false; + + char next_char = *NextChar(); + if (next_char == '/') { + // Single line comment, read to newline. + while (CanConsume(1)) { + next_char = *NextChar(); + if (next_char == '\n' || next_char == '\r') + return true; + } + } else if (next_char == '*') { + char previous_char = '\0'; + // Block comment, read until end marker. + while (CanConsume(1)) { + next_char = *NextChar(); + if (previous_char == '*' && next_char == '/') { + // EatWhitespaceAndComments will inspect pos_, which will still be on + // the last / of the comment, so advance once more (which may also be + // end of input). + NextChar(); + return true; + } + previous_char = next_char; + } + + // If the comment is unterminated, GetNextToken will report T_END_OF_INPUT. + } + + return false; +} + +Value* JSONParser::ParseNextToken() { + return ParseToken(GetNextToken()); +} + +Value* JSONParser::ParseToken(Token token) { + switch (token) { + case T_OBJECT_BEGIN: + return ConsumeDictionary(); + case T_ARRAY_BEGIN: + return ConsumeList(); + case T_STRING: + return ConsumeString(); + case T_NUMBER: + return ConsumeNumber(); + case T_BOOL_TRUE: + case T_BOOL_FALSE: + case T_NULL: + return ConsumeLiteral(); + default: + ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); + return NULL; + } +} + +Value* JSONParser::ConsumeDictionary() { + if (*pos_ != '{') { + ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); + return NULL; + } + + StackMarker depth_check(&stack_depth_); + if (depth_check.IsTooDeep()) { + ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1); + return NULL; + } + + scoped_ptr<DictionaryValue> dict(new DictionaryValue); + + NextChar(); + Token token = GetNextToken(); + while (token != T_OBJECT_END) { + if (token != T_STRING) { + ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 1); + return NULL; + } + + // First consume the key. + StringBuilder key; + if (!ConsumeStringRaw(&key)) { + return NULL; + } + + // Read the separator. + NextChar(); + token = GetNextToken(); + if (token != T_OBJECT_PAIR_SEPARATOR) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + + // The next token is the value. Ownership transfers to |dict|. + NextChar(); + Value* value = ParseNextToken(); + if (!value) { + // ReportError from deeper level. + return NULL; + } + + dict->SetWithoutPathExpansion(key.AsString(), value); + + NextChar(); + token = GetNextToken(); + if (token == T_LIST_SEPARATOR) { + NextChar(); + token = GetNextToken(); + if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { + ReportError(JSONReader::JSON_TRAILING_COMMA, 1); + return NULL; + } + } else if (token != T_OBJECT_END) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + return NULL; + } + } + + return dict.release(); +} + +Value* JSONParser::ConsumeList() { + if (*pos_ != '[') { + ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); + return NULL; + } + + StackMarker depth_check(&stack_depth_); + if (depth_check.IsTooDeep()) { + ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1); + return NULL; + } + + scoped_ptr<ListValue> list(new ListValue); + + NextChar(); + Token token = GetNextToken(); + while (token != T_ARRAY_END) { + Value* item = ParseToken(token); + if (!item) { + // ReportError from deeper level. + return NULL; + } + + list->Append(item); + + NextChar(); + token = GetNextToken(); + if (token == T_LIST_SEPARATOR) { + NextChar(); + token = GetNextToken(); + if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { + ReportError(JSONReader::JSON_TRAILING_COMMA, 1); + return NULL; + } + } else if (token != T_ARRAY_END) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + } + + return list.release(); +} + +Value* JSONParser::ConsumeString() { + StringBuilder string; + if (!ConsumeStringRaw(&string)) + return NULL; + + // Create the Value representation, using a hidden root, if configured + // to do so, and if the string can be represented by StringPiece. + if (string.CanBeStringPiece() && !(options_ & JSON_DETACHABLE_CHILDREN)) { + return new JSONStringValue(string.AsStringPiece()); + } else { + if (string.CanBeStringPiece()) + string.Convert(); + return new StringValue(string.AsString()); + } +} + +bool JSONParser::ConsumeStringRaw(StringBuilder* out) { + if (*pos_ != '"') { + ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); + return false; + } + + // StringBuilder will internally build a StringPiece unless a UTF-16 + // conversion occurs, at which point it will perform a copy into a + // std::string. + StringBuilder string(NextChar()); + + int length = end_pos_ - start_pos_; + int32 next_char = 0; + + while (CanConsume(1)) { + pos_ = start_pos_ + index_; // CBU8_NEXT is postcrement. + CBU8_NEXT(start_pos_, index_, length, next_char); + if (next_char < 0 || !IsValidCharacter(next_char)) { + ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 1); + return false; + } + + // If this character is an escape sequence... + if (next_char == '\\') { + // The input string will be adjusted (either by combining the two + // characters of an encoded escape sequence, or with a UTF conversion), + // so using StringPiece isn't possible -- force a conversion. + string.Convert(); + + if (!CanConsume(1)) { + ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); + return false; + } + + switch (*NextChar()) { + // Allowed esape sequences: + case 'x': { // UTF-8 sequence. + // UTF-8 \x escape sequences are not allowed in the spec, but they + // are supported here for backwards-compatiblity with the old parser. + if (!CanConsume(2)) { + ReportError(JSONReader::JSON_INVALID_ESCAPE, 1); + return false; + } + + int hex_digit = 0; + if (!HexStringToInt(StringPiece(NextChar(), 2), &hex_digit)) { + ReportError(JSONReader::JSON_INVALID_ESCAPE, -1); + return false; + } + NextChar(); + + if (hex_digit < kExtendedASCIIStart) + string.Append(static_cast<char>(hex_digit)); + else + DecodeUTF8(hex_digit, &string); + break; + } + case 'u': { // UTF-16 sequence. + // UTF units are of the form \uXXXX. + if (!CanConsume(5)) { // 5 being 'u' and four HEX digits. + ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); + return false; + } + + // Skip the 'u'. + NextChar(); + + std::string utf8_units; + if (!DecodeUTF16(&utf8_units)) { + ReportError(JSONReader::JSON_INVALID_ESCAPE, -1); + return false; + } + + string.AppendString(utf8_units); + break; + } + case '"': + string.Append('"'); + break; + case '\\': + string.Append('\\'); + break; + case '/': + string.Append('/'); + break; + case 'b': + string.Append('\b'); + break; + case 'f': + string.Append('\f'); + break; + case 'n': + string.Append('\n'); + break; + case 'r': + string.Append('\r'); + break; + case 't': + string.Append('\t'); + break; + case 'v': // Not listed as valid escape sequence in the RFC. + string.Append('\v'); + break; + // All other escape squences are illegal. + default: + ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); + return false; + } + } else if (next_char == '"') { + --index_; // Rewind by one because of CBU8_NEXT. + out->Swap(&string); + return true; + } else { + if (next_char < kExtendedASCIIStart) + string.Append(static_cast<char>(next_char)); + else + DecodeUTF8(next_char, &string); + } + } + + ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + return false; +} + +// Entry is at the first X in \uXXXX. +bool JSONParser::DecodeUTF16(std::string* dest_string) { + if (!CanConsume(4)) + return false; + + // This is a 32-bit field because the shift operations in the + // conversion process below cause MSVC to error about "data loss." + // This only stores UTF-16 code units, though. + // Consume the UTF-16 code unit, which may be a high surrogate. + int code_unit16_high = 0; + if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_high)) + return false; + + // Only add 3, not 4, because at the end of this iteration, the parser has + // finished working with the last digit of the UTF sequence, meaning that + // the next iteration will advance to the next byte. + NextNChars(3); + + // Used to convert the UTF-16 code units to a code point and then to a UTF-8 + // code unit sequence. + char code_unit8[8] = { 0 }; + size_t offset = 0; + + // If this is a high surrogate, consume the next code unit to get the + // low surrogate. + if (CBU16_IS_SURROGATE(code_unit16_high)) { + // Make sure this is the high surrogate. If not, it's an encoding + // error. + if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high)) + return false; + + // Make sure that the token has more characters to consume the + // lower surrogate. + if (!CanConsume(6)) // 6 being '\' 'u' and four HEX digits. + return false; + if (*NextChar() != '\\' || *NextChar() != 'u') + return false; + + NextChar(); // Read past 'u'. + int code_unit16_low = 0; + if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_low)) + return false; + + NextNChars(3); + + if (!CBU16_IS_TRAIL(code_unit16_low)) { + return false; + } + + uint32 code_point = CBU16_GET_SUPPLEMENTARY(code_unit16_high, + code_unit16_low); + offset = 0; + CBU8_APPEND_UNSAFE(code_unit8, offset, code_point); + } else { + // Not a surrogate. + DCHECK(CBU16_IS_SINGLE(code_unit16_high)); + CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high); + } + + dest_string->append(code_unit8); + return true; +} + +void JSONParser::DecodeUTF8(const int32& point, StringBuilder* dest) { + // Anything outside of the basic ASCII plane will need to be decoded from + // int32 to a multi-byte sequence. + if (point < kExtendedASCIIStart) { + dest->Append(static_cast<char>(point)); + } else { + char utf8_units[4] = { 0 }; + int offset = 0; + CBU8_APPEND_UNSAFE(utf8_units, offset, point); + dest->Convert(); + // CBU8_APPEND_UNSAFE can overwrite up to 4 bytes, so utf8_units may not be + // zero terminated at this point. |offset| contains the correct length. + dest->AppendString(std::string(utf8_units, offset)); + } +} + +Value* JSONParser::ConsumeNumber() { + const char* num_start = pos_; + const int start_index = index_; + int end_index = start_index; + + if (*pos_ == '-') + NextChar(); + + if (!ReadInt(false)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + end_index = index_; + + // The optional fraction part. + if (*pos_ == '.') { + if (!CanConsume(1)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + NextChar(); + if (!ReadInt(true)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + end_index = index_; + } + + // Optional exponent part. + if (*pos_ == 'e' || *pos_ == 'E') { + NextChar(); + if (*pos_ == '-' || *pos_ == '+') + NextChar(); + if (!ReadInt(true)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + end_index = index_; + } + + // ReadInt is greedy because numbers have no easily detectable sentinel, + // so save off where the parser should be on exit (see Consume invariant at + // the top of the header), then make sure the next token is one which is + // valid. + const char* exit_pos = pos_ - 1; + int exit_index = index_ - 1; + + switch (GetNextToken()) { + case T_OBJECT_END: + case T_ARRAY_END: + case T_LIST_SEPARATOR: + case T_END_OF_INPUT: + break; + default: + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + + pos_ = exit_pos; + index_ = exit_index; + + StringPiece num_string(num_start, end_index - start_index); + + int num_int; + if (StringToInt(num_string, &num_int)) + return new FundamentalValue(num_int); + + double num_double; + if (base::StringToDouble(num_string.as_string(), &num_double) && + std::isfinite(num_double)) { + return new FundamentalValue(num_double); + } + + return NULL; +} + +bool JSONParser::ReadInt(bool allow_leading_zeros) { + char first = *pos_; + int len = 0; + + char c = first; + while (CanConsume(1) && std::isdigit(c)) { + c = *NextChar(); + ++len; + } + + if (len == 0) + return false; + + if (!allow_leading_zeros && len > 1 && first == '0') + return false; + + return true; +} + +Value* JSONParser::ConsumeLiteral() { + switch (*pos_) { + case 't': { + const char kTrueLiteral[] = "true"; + const int kTrueLen = static_cast<int>(strlen(kTrueLiteral)); + if (!CanConsume(kTrueLen - 1) || + !StringsAreEqual(pos_, kTrueLiteral, kTrueLen)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + NextNChars(kTrueLen - 1); + return new FundamentalValue(true); + } + case 'f': { + const char kFalseLiteral[] = "false"; + const int kFalseLen = static_cast<int>(strlen(kFalseLiteral)); + if (!CanConsume(kFalseLen - 1) || + !StringsAreEqual(pos_, kFalseLiteral, kFalseLen)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + NextNChars(kFalseLen - 1); + return new FundamentalValue(false); + } + case 'n': { + const char kNullLiteral[] = "null"; + const int kNullLen = static_cast<int>(strlen(kNullLiteral)); + if (!CanConsume(kNullLen - 1) || + !StringsAreEqual(pos_, kNullLiteral, kNullLen)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return NULL; + } + NextNChars(kNullLen - 1); + return Value::CreateNullValue().release(); + } + default: + ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); + return NULL; + } +} + +// static +bool JSONParser::StringsAreEqual(const char* one, const char* two, size_t len) { + return strncmp(one, two, len) == 0; +} + +void JSONParser::ReportError(JSONReader::JsonParseError code, + int column_adjust) { + error_code_ = code; + error_line_ = line_number_; + error_column_ = index_ - index_last_line_ + column_adjust; +} + +// static +std::string JSONParser::FormatErrorMessage(int line, int column, + const std::string& description) { + if (line || column) { + return StringPrintf("Line: %i, column: %i, %s", + line, column, description.c_str()); + } + return description; +} + +} // namespace internal +} // namespace base diff --git a/third_party/chromium/base/json/json_parser.h b/third_party/chromium/base/json/json_parser.h new file mode 100644 index 0000000..c8ed0cd --- /dev/null +++ b/third_party/chromium/base/json/json_parser.h @@ -0,0 +1,255 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_JSON_JSON_PARSER_H_ +#define BASE_JSON_JSON_PARSER_H_ + +#include <string> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" +#include "base/json/json_reader.h" +#include "base/strings/string_piece.h" + +namespace base { +class Value; +} + +namespace base { +namespace internal { + +class JSONParserTest; + +// The implementation behind the JSONReader interface. This class is not meant +// to be used directly; it encapsulates logic that need not be exposed publicly. +// +// This parser guarantees O(n) time through the input string. It also optimizes +// base::StringValue by using StringPiece where possible when returning Value +// objects by using "hidden roots," discussed in the implementation. +// +// Iteration happens on the byte level, with the functions CanConsume and +// NextChar. The conversion from byte to JSON token happens without advancing +// the parser in GetNextToken/ParseToken, that is tokenization operates on +// the current parser position without advancing. +// +// Built on top of these are a family of Consume functions that iterate +// internally. Invariant: on entry of a Consume function, the parser is wound +// to the first byte of a valid JSON token. On exit, it is on the last byte +// of a token, such that the next iteration of the parser will be at the byte +// immediately following the token, which would likely be the first byte of the +// next token. +class BASE_EXPORT_PRIVATE JSONParser { + public: + explicit JSONParser(int options); + ~JSONParser(); + + // Parses the input string according to the set options and returns the + // result as a Value owned by the caller. + Value* Parse(const StringPiece& input); + + // Returns the error code. + JSONReader::JsonParseError error_code() const; + + // Returns the human-friendly error message. + std::string GetErrorMessage() const; + + private: + enum Token { + T_OBJECT_BEGIN, // { + T_OBJECT_END, // } + T_ARRAY_BEGIN, // [ + T_ARRAY_END, // ] + T_STRING, + T_NUMBER, + T_BOOL_TRUE, // true + T_BOOL_FALSE, // false + T_NULL, // null + T_LIST_SEPARATOR, // , + T_OBJECT_PAIR_SEPARATOR, // : + T_END_OF_INPUT, + T_INVALID_TOKEN, + }; + + // A helper class used for parsing strings. One optimization performed is to + // create base::Value with a StringPiece to avoid unnecessary std::string + // copies. This is not possible if the input string needs to be decoded from + // UTF-16 to UTF-8, or if an escape sequence causes characters to be skipped. + // This class centralizes that logic. + class StringBuilder { + public: + // Empty constructor. Used for creating a builder with which to Swap(). + StringBuilder(); + + // |pos| is the beginning of an input string, excluding the |"|. + explicit StringBuilder(const char* pos); + + ~StringBuilder(); + + // Swaps the contents of |other| with this. + void Swap(StringBuilder* other); + + // Either increases the |length_| of the string or copies the character if + // the StringBuilder has been converted. |c| must be in the basic ASCII + // plane; all other characters need to be in UTF-8 units, appended with + // AppendString below. + void Append(const char& c); + + // Appends a string to the std::string. Must be Convert()ed to use. + void AppendString(const std::string& str); + + // Converts the builder from its default StringPiece to a full std::string, + // performing a copy. Once a builder is converted, it cannot be made a + // StringPiece again. + void Convert(); + + // Returns whether the builder can be converted to a StringPiece. + bool CanBeStringPiece() const; + + // Returns the StringPiece representation. Returns an empty piece if it + // cannot be converted. + StringPiece AsStringPiece(); + + // Returns the builder as a std::string. + const std::string& AsString(); + + private: + // The beginning of the input string. + const char* pos_; + + // Number of bytes in |pos_| that make up the string being built. + size_t length_; + + // The copied string representation. NULL until Convert() is called. + // Strong. scoped_ptr<T> has too much of an overhead here. + std::string* string_; + }; + + // Quick check that the stream has capacity to consume |length| more bytes. + bool CanConsume(int length); + + // The basic way to consume a single character in the stream. Consumes one + // byte of the input stream and returns a pointer to the rest of it. + const char* NextChar(); + + // Performs the equivalent of NextChar N times. + void NextNChars(int n); + + // Skips over whitespace and comments to find the next token in the stream. + // This does not advance the parser for non-whitespace or comment chars. + Token GetNextToken(); + + // Consumes whitespace characters and comments until the next non-that is + // encountered. + void EatWhitespaceAndComments(); + // Helper function that consumes a comment, assuming that the parser is + // currently wound to a '/'. + bool EatComment(); + + // Calls GetNextToken() and then ParseToken(). Caller owns the result. + Value* ParseNextToken(); + + // Takes a token that represents the start of a Value ("a structural token" + // in RFC terms) and consumes it, returning the result as an object the + // caller owns. + Value* ParseToken(Token token); + + // Assuming that the parser is currently wound to '{', this parses a JSON + // object into a DictionaryValue. + Value* ConsumeDictionary(); + + // Assuming that the parser is wound to '[', this parses a JSON list into a + // ListValue. + Value* ConsumeList(); + + // Calls through ConsumeStringRaw and wraps it in a value. + Value* ConsumeString(); + + // Assuming that the parser is wound to a double quote, this parses a string, + // decoding any escape sequences and converts UTF-16 to UTF-8. Returns true on + // success and Swap()s the result into |out|. Returns false on failure with + // error information set. + bool ConsumeStringRaw(StringBuilder* out); + // Helper function for ConsumeStringRaw() that consumes the next four or 10 + // bytes (parser is wound to the first character of a HEX sequence, with the + // potential for consuming another \uXXXX for a surrogate). Returns true on + // success and places the UTF8 code units in |dest_string|, and false on + // failure. + bool DecodeUTF16(std::string* dest_string); + // Helper function for ConsumeStringRaw() that takes a single code point, + // decodes it into UTF-8 units, and appends it to the given builder. The + // point must be valid. + void DecodeUTF8(const int32& point, StringBuilder* dest); + + // Assuming that the parser is wound to the start of a valid JSON number, + // this parses and converts it to either an int or double value. + Value* ConsumeNumber(); + // Helper that reads characters that are ints. Returns true if a number was + // read and false on error. + bool ReadInt(bool allow_leading_zeros); + + // Consumes the literal values of |true|, |false|, and |null|, assuming the + // parser is wound to the first character of any of those. + Value* ConsumeLiteral(); + + // Compares two string buffers of a given length. + static bool StringsAreEqual(const char* left, const char* right, size_t len); + + // Sets the error information to |code| at the current column, based on + // |index_| and |index_last_line_|, with an optional positive/negative + // adjustment by |column_adjust|. + void ReportError(JSONReader::JsonParseError code, int column_adjust); + + // Given the line and column number of an error, formats one of the error + // message contants from json_reader.h for human display. + static std::string FormatErrorMessage(int line, int column, + const std::string& description); + + // base::JSONParserOptions that control parsing. + int options_; + + // Pointer to the start of the input data. + const char* start_pos_; + + // Pointer to the current position in the input data. Equivalent to + // |start_pos_ + index_|. + const char* pos_; + + // Pointer to the last character of the input data. + const char* end_pos_; + + // The index in the input stream to which the parser is wound. + int index_; + + // The number of times the parser has recursed (current stack depth). + int stack_depth_; + + // The line number that the parser is at currently. + int line_number_; + + // The last value of |index_| on the previous line. + int index_last_line_; + + // Error information. + JSONReader::JsonParseError error_code_; + int error_line_; + int error_column_; + + friend class JSONParserTest; + FRIEND_TEST_ALL_PREFIXES(JSONParserTest, NextChar); + FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeDictionary); + FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeList); + FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeString); + FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeLiterals); + FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeNumbers); + FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ErrorMessages); + + DISALLOW_COPY_AND_ASSIGN(JSONParser); +}; + +} // namespace internal +} // namespace base + +#endif // BASE_JSON_JSON_PARSER_H_ diff --git a/third_party/chromium/base/json/json_parser_unittest.cc b/third_party/chromium/base/json/json_parser_unittest.cc new file mode 100644 index 0000000..c432eee --- /dev/null +++ b/third_party/chromium/base/json/json_parser_unittest.cc @@ -0,0 +1,318 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/json/json_parser.h" + +#include <gtest/gtest.h> + +#include "base/json/json_reader.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" + +namespace base { +namespace internal { + +class JSONParserTest : public testing::Test { + public: + JSONParser* NewTestParser(const std::string& input) { + JSONParser* parser = new JSONParser(JSON_PARSE_RFC); + parser->start_pos_ = input.data(); + parser->pos_ = parser->start_pos_; + parser->end_pos_ = parser->start_pos_ + input.length(); + return parser; + } + + void TestLastThree(JSONParser* parser) { + EXPECT_EQ(',', *parser->NextChar()); + EXPECT_EQ('|', *parser->NextChar()); + EXPECT_EQ('\0', *parser->NextChar()); + EXPECT_EQ(parser->end_pos_, parser->pos_); + } +}; + +TEST_F(JSONParserTest, NextChar) { + std::string input("Hello world"); + scoped_ptr<JSONParser> parser(NewTestParser(input)); + + EXPECT_EQ('H', *parser->pos_); + for (size_t i = 1; i < input.length(); ++i) { + EXPECT_EQ(input[i], *parser->NextChar()); + } + EXPECT_EQ(parser->end_pos_, parser->NextChar()); +} + +TEST_F(JSONParserTest, ConsumeString) { + std::string input("\"test\",|"); + scoped_ptr<JSONParser> parser(NewTestParser(input)); + scoped_ptr<Value> value(parser->ConsumeString()); + EXPECT_EQ('"', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + std::string str; + EXPECT_TRUE(value->GetAsString(&str)); + EXPECT_EQ("test", str); +} + +TEST_F(JSONParserTest, ConsumeList) { + std::string input("[true, false],|"); + scoped_ptr<JSONParser> parser(NewTestParser(input)); + scoped_ptr<Value> value(parser->ConsumeList()); + EXPECT_EQ(']', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + base::ListValue* list; + EXPECT_TRUE(value->GetAsList(&list)); + EXPECT_EQ(2u, list->GetSize()); +} + +TEST_F(JSONParserTest, ConsumeDictionary) { + std::string input("{\"abc\":\"def\"},|"); + scoped_ptr<JSONParser> parser(NewTestParser(input)); + scoped_ptr<Value> value(parser->ConsumeDictionary()); + EXPECT_EQ('}', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + base::DictionaryValue* dict; + EXPECT_TRUE(value->GetAsDictionary(&dict)); + std::string str; + EXPECT_TRUE(dict->GetString("abc", &str)); + EXPECT_EQ("def", str); +} + +TEST_F(JSONParserTest, ConsumeLiterals) { + // Literal |true|. + std::string input("true,|"); + scoped_ptr<JSONParser> parser(NewTestParser(input)); + scoped_ptr<Value> value(parser->ConsumeLiteral()); + EXPECT_EQ('e', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + bool bool_value = false; + EXPECT_TRUE(value->GetAsBoolean(&bool_value)); + EXPECT_TRUE(bool_value); + + // Literal |false|. + input = "false,|"; + parser.reset(NewTestParser(input)); + value.reset(parser->ConsumeLiteral()); + EXPECT_EQ('e', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + EXPECT_TRUE(value->GetAsBoolean(&bool_value)); + EXPECT_FALSE(bool_value); + + // Literal |null|. + input = "null,|"; + parser.reset(NewTestParser(input)); + value.reset(parser->ConsumeLiteral()); + EXPECT_EQ('l', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + EXPECT_TRUE(value->IsType(Value::TYPE_NULL)); +} + +TEST_F(JSONParserTest, ConsumeNumbers) { + // Integer. + std::string input("1234,|"); + scoped_ptr<JSONParser> parser(NewTestParser(input)); + scoped_ptr<Value> value(parser->ConsumeNumber()); + EXPECT_EQ('4', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + int number_i; + EXPECT_TRUE(value->GetAsInteger(&number_i)); + EXPECT_EQ(1234, number_i); + + // Negative integer. + input = "-1234,|"; + parser.reset(NewTestParser(input)); + value.reset(parser->ConsumeNumber()); + EXPECT_EQ('4', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + EXPECT_TRUE(value->GetAsInteger(&number_i)); + EXPECT_EQ(-1234, number_i); + + // Double. + input = "12.34,|"; + parser.reset(NewTestParser(input)); + value.reset(parser->ConsumeNumber()); + EXPECT_EQ('4', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + double number_d; + EXPECT_TRUE(value->GetAsDouble(&number_d)); + EXPECT_EQ(12.34, number_d); + + // Scientific. + input = "42e3,|"; + parser.reset(NewTestParser(input)); + value.reset(parser->ConsumeNumber()); + EXPECT_EQ('3', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + EXPECT_TRUE(value->GetAsDouble(&number_d)); + EXPECT_EQ(42000, number_d); + + // Negative scientific. + input = "314159e-5,|"; + parser.reset(NewTestParser(input)); + value.reset(parser->ConsumeNumber()); + EXPECT_EQ('5', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + EXPECT_TRUE(value->GetAsDouble(&number_d)); + EXPECT_EQ(3.14159, number_d); + + // Positive scientific. + input = "0.42e+3,|"; + parser.reset(NewTestParser(input)); + value.reset(parser->ConsumeNumber()); + EXPECT_EQ('3', *parser->pos_); + + TestLastThree(parser.get()); + + ASSERT_TRUE(value.get()); + EXPECT_TRUE(value->GetAsDouble(&number_d)); + EXPECT_EQ(420, number_d); +} + +TEST_F(JSONParserTest, ErrorMessages) { + // Error strings should not be modified in case of success. + std::string error_message; + int error_code = 0; + scoped_ptr<Value> root; + root.reset(JSONReader::DeprecatedReadAndReturnError( + "[42]", JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_TRUE(error_message.empty()); + EXPECT_EQ(0, error_code); + + // Test line and column counting + const char big_json[] = "[\n0,\n1,\n2,\n3,4,5,6 7,\n8,\n9\n]"; + // error here ----------------------------------^ + root.reset(JSONReader::DeprecatedReadAndReturnError( + big_json, JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError), + error_message); + EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); + + error_code = 0; + error_message = ""; + // Test line and column counting with "\r\n" line ending + const char big_json_crlf[] = + "[\r\n0,\r\n1,\r\n2,\r\n3,4,5,6 7,\r\n8,\r\n9\r\n]"; + // error here ----------------------^ + root.reset(JSONReader::DeprecatedReadAndReturnError( + big_json_crlf, JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError), + error_message); + EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); + + // Test each of the error conditions + root.reset(JSONReader::DeprecatedReadAndReturnError( + "{},{}", JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3, + JSONReader::kUnexpectedDataAfterRoot), error_message); + EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, error_code); + + std::string nested_json; + for (int i = 0; i < 101; ++i) { + nested_json.insert(nested_json.begin(), '['); + nested_json.append(1, ']'); + } + root.reset(JSONReader::DeprecatedReadAndReturnError( + nested_json, JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 100, JSONReader::kTooMuchNesting), + error_message); + EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code); + + root.reset(JSONReader::DeprecatedReadAndReturnError( + "[1,]", JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma), + error_message); + EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); + + root.reset(JSONReader::DeprecatedReadAndReturnError( + "{foo:\"bar\"}", JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, + JSONReader::kUnquotedDictionaryKey), error_message); + EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code); + + root.reset(JSONReader::DeprecatedReadAndReturnError( + "{\"foo\":\"bar\",}", JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma), + error_message); + + root.reset(JSONReader::DeprecatedReadAndReturnError( + "[nu]", JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError), + error_message); + EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); + + root.reset(JSONReader::DeprecatedReadAndReturnError( + "[\"xxx\\xq\"]", JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), + error_message); + EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); + + root.reset(JSONReader::DeprecatedReadAndReturnError( + "[\"xxx\\uq\"]", JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), + error_message); + EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); + + root.reset(JSONReader::DeprecatedReadAndReturnError( + "[\"xxx\\q\"]", JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_FALSE(root.get()); + EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), + error_message); + EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); +} + +TEST_F(JSONParserTest, Decode4ByteUtf8Char) { + // This test strings contains a 4 byte unicode character (a smiley!) that the + // reader should be able to handle (the character is \xf0\x9f\x98\x87). + const char kUtf8Data[] = + "[\"😇\",[],[],[],{\"google:suggesttype\":[]}]"; + std::string error_message; + int error_code = 0; + scoped_ptr<Value> root(JSONReader::DeprecatedReadAndReturnError( + kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message)); + EXPECT_TRUE(root.get()) << error_message; +} + +} // namespace internal +} // namespace base diff --git a/third_party/chromium/base/json/json_reader.cc b/third_party/chromium/base/json/json_reader.cc new file mode 100644 index 0000000..edff8dc --- /dev/null +++ b/third_party/chromium/base/json/json_reader.cc @@ -0,0 +1,132 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/json/json_reader.h" + +#include "base/json/json_parser.h" +#include "base/logging.h" +#include "base/values.h" + +namespace base { + +// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError. +COMPILE_ASSERT(JSONReader::JSON_PARSE_ERROR_COUNT < 1000, + json_reader_error_out_of_bounds); + +const char JSONReader::kInvalidEscape[] = + "Invalid escape sequence."; +const char JSONReader::kSyntaxError[] = + "Syntax error."; +const char JSONReader::kUnexpectedToken[] = + "Unexpected token."; +const char JSONReader::kTrailingComma[] = + "Trailing comma not allowed."; +const char JSONReader::kTooMuchNesting[] = + "Too much nesting."; +const char JSONReader::kUnexpectedDataAfterRoot[] = + "Unexpected data after root element."; +const char JSONReader::kUnsupportedEncoding[] = + "Unsupported encoding. JSON must be UTF-8."; +const char JSONReader::kUnquotedDictionaryKey[] = + "Dictionary keys must be quoted."; + +JSONReader::JSONReader() + : JSONReader(JSON_PARSE_RFC) { +} + +JSONReader::JSONReader(int options) + : parser_(new internal::JSONParser(options)) { +} + +JSONReader::~JSONReader() { +} + +// static +Value* JSONReader::DeprecatedRead(const std::string& json) { + return Read(json).release(); +} + +// static +scoped_ptr<Value> JSONReader::Read(const std::string& json) { + internal::JSONParser parser(JSON_PARSE_RFC); + return make_scoped_ptr(parser.Parse(json)); +} + +// static +Value* JSONReader::DeprecatedRead(const std::string& json, int options) { + return Read(json, options).release(); +} + +// static +scoped_ptr<Value> JSONReader::Read(const std::string& json, int options) { + internal::JSONParser parser(options); + return make_scoped_ptr(parser.Parse(json)); +} + +// static +Value* JSONReader::DeprecatedReadAndReturnError(const std::string& json, + int options, + int* error_code_out, + std::string* error_msg_out) { + return ReadAndReturnError(json, options, error_code_out, error_msg_out) + .release(); +} + +// static +scoped_ptr<Value> JSONReader::ReadAndReturnError(const std::string& json, + int options, + int* error_code_out, + std::string* error_msg_out) { + internal::JSONParser parser(options); + scoped_ptr<Value> root(parser.Parse(json)); + if (!root) { + if (error_code_out) + *error_code_out = parser.error_code(); + if (error_msg_out) + *error_msg_out = parser.GetErrorMessage(); + } + + return root; +} + +// static +std::string JSONReader::ErrorCodeToString(JsonParseError error_code) { + switch (error_code) { + case JSON_NO_ERROR: + return std::string(); + case JSON_INVALID_ESCAPE: + return kInvalidEscape; + case JSON_SYNTAX_ERROR: + return kSyntaxError; + case JSON_UNEXPECTED_TOKEN: + return kUnexpectedToken; + case JSON_TRAILING_COMMA: + return kTrailingComma; + case JSON_TOO_MUCH_NESTING: + return kTooMuchNesting; + case JSON_UNEXPECTED_DATA_AFTER_ROOT: + return kUnexpectedDataAfterRoot; + case JSON_UNSUPPORTED_ENCODING: + return kUnsupportedEncoding; + case JSON_UNQUOTED_DICTIONARY_KEY: + return kUnquotedDictionaryKey; + default: + NOTREACHED(); + return std::string(); + } +} + +scoped_ptr<Value> JSONReader::ReadToValue(const std::string& json) { + return make_scoped_ptr(parser_->Parse(json)); +} + +JSONReader::JsonParseError JSONReader::error_code() const { + return parser_->error_code(); +} + +std::string JSONReader::GetErrorMessage() const { + return parser_->GetErrorMessage(); +} + +} // namespace base diff --git a/third_party/chromium/base/json/json_reader.h b/third_party/chromium/base/json/json_reader.h new file mode 100644 index 0000000..e177ab8 --- /dev/null +++ b/third_party/chromium/base/json/json_reader.h @@ -0,0 +1,142 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// A JSON parser. Converts strings of JSON into a Value object (see +// base/values.h). +// http://www.ietf.org/rfc/rfc4627.txt?number=4627 +// +// Known limitations/deviations from the RFC: +// - Only knows how to parse ints within the range of a signed 32 bit int and +// decimal numbers within a double. +// - Assumes input is encoded as UTF8. The spec says we should allow UTF-16 +// (BE or LE) and UTF-32 (BE or LE) as well. +// - We limit nesting to 100 levels to prevent stack overflow (this is allowed +// by the RFC). +// - A Unicode FAQ ("http://unicode.org/faq/utf_bom.html") writes a data +// stream may start with a Unicode Byte-Order-Mark (U+FEFF), i.e. the input +// UTF-8 string for the JSONReader::JsonToValue() function may start with a +// UTF-8 BOM (0xEF, 0xBB, 0xBF). +// To avoid the function from mis-treating a UTF-8 BOM as an invalid +// character, the function skips a Unicode BOM at the beginning of the +// Unicode string (converted from the input UTF-8 string) before parsing it. +// +// TODO(tc): Add a parsing option to to relax object keys being wrapped in +// double quotes +// TODO(tc): Add an option to disable comment stripping + +#ifndef BASE_JSON_JSON_READER_H_ +#define BASE_JSON_JSON_READER_H_ + +#include <string> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" + +namespace base { + +class Value; + +namespace internal { +class JSONParser; +} + +enum JSONParserOptions { + // Parses the input strictly according to RFC 4627, except for where noted + // above. + JSON_PARSE_RFC = 0, + + // Allows commas to exist after the last element in structures. + JSON_ALLOW_TRAILING_COMMAS = 1 << 0, + + // The parser can perform optimizations by placing hidden data in the root of + // the JSON object, which speeds up certain operations on children. However, + // if the child is Remove()d from root, it would result in use-after-free + // unless it is DeepCopy()ed or this option is used. + JSON_DETACHABLE_CHILDREN = 1 << 1, +}; + +class BASE_EXPORT JSONReader { + public: + // Error codes during parsing. + enum JsonParseError { + JSON_NO_ERROR = 0, + JSON_INVALID_ESCAPE, + JSON_SYNTAX_ERROR, + JSON_UNEXPECTED_TOKEN, + JSON_TRAILING_COMMA, + JSON_TOO_MUCH_NESTING, + JSON_UNEXPECTED_DATA_AFTER_ROOT, + JSON_UNSUPPORTED_ENCODING, + JSON_UNQUOTED_DICTIONARY_KEY, + JSON_PARSE_ERROR_COUNT + }; + + // String versions of parse error codes. + static const char kInvalidEscape[]; + static const char kSyntaxError[]; + static const char kUnexpectedToken[]; + static const char kTrailingComma[]; + static const char kTooMuchNesting[]; + static const char kUnexpectedDataAfterRoot[]; + static const char kUnsupportedEncoding[]; + static const char kUnquotedDictionaryKey[]; + + // Constructs a reader with the default options, JSON_PARSE_RFC. + JSONReader(); + + // Constructs a reader with custom options. + explicit JSONReader(int options); + + ~JSONReader(); + + // Reads and parses |json|, returning a Value. The caller owns the returned + // instance. If |json| is not a properly formed JSON string, returns NULL. + static scoped_ptr<Value> Read(const std::string& json); + // TODO(estade): remove this bare pointer version. + static Value* DeprecatedRead(const std::string& json); + + // Reads and parses |json|, returning a Value owned by the caller. The + // parser respects the given |options|. If the input is not properly formed, + // returns NULL. + static scoped_ptr<Value> Read(const std::string& json, int options); + // TODO(estade): remove this bare pointer version. + static Value* DeprecatedRead(const std::string& json, int options); + + // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out| + // are optional. If specified and NULL is returned, they will be populated + // an error code and a formatted error message (including error location if + // appropriate). Otherwise, they will be unmodified. + static scoped_ptr<Value> ReadAndReturnError(const std::string& json, + int options, // JSONParserOptions + int* error_code_out, + std::string* error_msg_out); + // TODO(estade): remove this bare pointer version. + static Value* DeprecatedReadAndReturnError(const std::string& json, + int options, // JSONParserOptions + int* error_code_out, + std::string* error_msg_out); + + // Converts a JSON parse error code into a human readable message. + // Returns an empty string if error_code is JSON_NO_ERROR. + static std::string ErrorCodeToString(JsonParseError error_code); + + // Parses an input string into a Value that is owned by the caller. + scoped_ptr<Value> ReadToValue(const std::string& json); + + // Returns the error code if the last call to ReadToValue() failed. + // Returns JSON_NO_ERROR otherwise. + JsonParseError error_code() const; + + // Converts error_code_ to a human-readable string, including line and column + // numbers if appropriate. + std::string GetErrorMessage() const; + + private: + scoped_ptr<internal::JSONParser> parser_; +}; + +} // namespace base + +#endif // BASE_JSON_JSON_READER_H_ diff --git a/third_party/chromium/base/json/json_reader_unittest.cc b/third_party/chromium/base/json/json_reader_unittest.cc new file mode 100644 index 0000000..a5f2530 --- /dev/null +++ b/third_party/chromium/base/json/json_reader_unittest.cc @@ -0,0 +1,650 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/json/json_reader.h" + +#include <gtest/gtest.h> + +#include "base/build/build_config.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string_piece.h" +#include "base/strings/utf_string_conversion_utils.h" +#include "base/values.h" + +namespace base { + +TEST(JSONReaderTest, Reading) { + // some whitespace checking + scoped_ptr<Value> root; + root = JSONReader().ReadToValue(" null "); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); + + // Invalid JSON string + root = JSONReader().ReadToValue("nu"); + EXPECT_FALSE(root.get()); + + // Simple bool + root = JSONReader().ReadToValue("true "); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN)); + + // Embedded comment + root = JSONReader().ReadToValue("/* comment */null"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); + root = JSONReader().ReadToValue("40 /* comment */"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + root = JSONReader().ReadToValue("true // comment"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN)); + root = JSONReader().ReadToValue("/* comment */\"sample string\""); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + std::string value; + EXPECT_TRUE(root->GetAsString(&value)); + EXPECT_EQ("sample string", value); + root = JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]"); + ASSERT_TRUE(root.get()); + ListValue* list = static_cast<ListValue*>(root.get()); + EXPECT_EQ(2u, list->GetSize()); + int int_val = 0; + EXPECT_TRUE(list->GetInteger(0, &int_val)); + EXPECT_EQ(1, int_val); + EXPECT_TRUE(list->GetInteger(1, &int_val)); + EXPECT_EQ(3, int_val); + root = JSONReader().ReadToValue("[1, /*a*/2, 3]"); + ASSERT_TRUE(root.get()); + list = static_cast<ListValue*>(root.get()); + EXPECT_EQ(3u, list->GetSize()); + root = JSONReader().ReadToValue("/* comment **/42"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + EXPECT_TRUE(root->GetAsInteger(&int_val)); + EXPECT_EQ(42, int_val); + root = JSONReader().ReadToValue( + "/* comment **/\n" + "// */ 43\n" + "44"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + EXPECT_TRUE(root->GetAsInteger(&int_val)); + EXPECT_EQ(44, int_val); + + // Test number formats + root = JSONReader().ReadToValue("43"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + EXPECT_TRUE(root->GetAsInteger(&int_val)); + EXPECT_EQ(43, int_val); + + // According to RFC4627, oct, hex, and leading zeros are invalid JSON. + root = JSONReader().ReadToValue("043"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("0x43"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("00"); + EXPECT_FALSE(root.get()); + + // Test 0 (which needs to be special cased because of the leading zero + // clause). + root = JSONReader().ReadToValue("0"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER)); + int_val = 1; + EXPECT_TRUE(root->GetAsInteger(&int_val)); + EXPECT_EQ(0, int_val); + + // Numbers that overflow ints should succeed, being internally promoted to + // storage as doubles + root = JSONReader().ReadToValue("2147483648"); + ASSERT_TRUE(root.get()); + double double_val; + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(2147483648.0, double_val); + root = JSONReader().ReadToValue("-2147483649"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(-2147483649.0, double_val); + + // Parse a double + root = JSONReader().ReadToValue("43.1"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(43.1, double_val); + + root = JSONReader().ReadToValue("4.3e-1"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(.43, double_val); + + root = JSONReader().ReadToValue("2.1e0"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(2.1, double_val); + + root = JSONReader().ReadToValue("2.1e+0001"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(21.0, double_val); + + root = JSONReader().ReadToValue("0.01"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(0.01, double_val); + + root = JSONReader().ReadToValue("1.00"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE)); + double_val = 0.0; + EXPECT_TRUE(root->GetAsDouble(&double_val)); + EXPECT_DOUBLE_EQ(1.0, double_val); + + // Fractional parts must have a digit before and after the decimal point. + root = JSONReader().ReadToValue("1."); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue(".1"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("1.e10"); + EXPECT_FALSE(root.get()); + + // Exponent must have a digit following the 'e'. + root = JSONReader().ReadToValue("1e"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("1E"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("1e1."); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("1e1.0"); + EXPECT_FALSE(root.get()); + + // INF/-INF/NaN are not valid + root = JSONReader().ReadToValue("1e1000"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("-1e1000"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("NaN"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("nan"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("inf"); + EXPECT_FALSE(root.get()); + + // Invalid number formats + root = JSONReader().ReadToValue("4.3.1"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("4e3.1"); + EXPECT_FALSE(root.get()); + + // Test string parser + root = JSONReader().ReadToValue("\"hello world\""); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + std::string str_val; + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("hello world", str_val); + + // Empty string + root = JSONReader().ReadToValue("\"\""); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + str_val.clear(); + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("", str_val); + + // Test basic string escapes + root = JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\""); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + str_val.clear(); + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ(" \"\\/\b\f\n\r\t\v", str_val); + + // Test hex and unicode escapes including the null character. + root = JSONReader().ReadToValue("\"\\x41\\x00\\u1234\""); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + str_val.clear(); + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ((std::string{'A', '\0', '\xE1', '\x88', '\xB4'}), str_val); + + // Test invalid strings + root = JSONReader().ReadToValue("\"no closing quote"); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("\"\\z invalid escape char\""); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("\"\\xAQ invalid hex code\""); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("not enough hex chars\\x1\""); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("\"not enough escape chars\\u123\""); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("\"extra backslash at end of input\\\""); + EXPECT_FALSE(root.get()); + + // Basic array + root.reset(JSONReader::DeprecatedRead("[true, false, null]")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); + list = static_cast<ListValue*>(root.get()); + EXPECT_EQ(3U, list->GetSize()); + + // Test with trailing comma. Should be parsed the same as above. + scoped_ptr<Value> root2; + root2.reset(JSONReader::DeprecatedRead("[true, false, null, ]", + JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_TRUE(root->Equals(root2.get())); + + // Empty array + root.reset(JSONReader::DeprecatedRead("[]")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); + list = static_cast<ListValue*>(root.get()); + EXPECT_EQ(0U, list->GetSize()); + + // Nested arrays + root.reset( + JSONReader::DeprecatedRead("[[true], [], [false, [], [null]], null]")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); + list = static_cast<ListValue*>(root.get()); + EXPECT_EQ(4U, list->GetSize()); + + // Lots of trailing commas. + root2.reset(JSONReader::DeprecatedRead( + "[[true], [], [false, [], [null, ] , ], null,]", + JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_TRUE(root->Equals(root2.get())); + + // Invalid, missing close brace. + root.reset( + JSONReader::DeprecatedRead("[[true], [], [false, [], [null]], null")); + EXPECT_FALSE(root.get()); + + // Invalid, too many commas + root.reset(JSONReader::DeprecatedRead("[true,, null]")); + EXPECT_FALSE(root.get()); + root.reset( + JSONReader::DeprecatedRead("[true,, null]", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + + // Invalid, no commas + root.reset(JSONReader::DeprecatedRead("[true null]")); + EXPECT_FALSE(root.get()); + + // Invalid, trailing comma + root.reset(JSONReader::DeprecatedRead("[true,]")); + EXPECT_FALSE(root.get()); + + // Valid if we set |allow_trailing_comma| to true. + root.reset(JSONReader::DeprecatedRead("[true,]", JSON_ALLOW_TRAILING_COMMAS)); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); + list = static_cast<ListValue*>(root.get()); + EXPECT_EQ(1U, list->GetSize()); + Value* tmp_value = NULL; + ASSERT_TRUE(list->Get(0, &tmp_value)); + EXPECT_TRUE(tmp_value->IsType(Value::TYPE_BOOLEAN)); + bool bool_value = false; + EXPECT_TRUE(tmp_value->GetAsBoolean(&bool_value)); + EXPECT_TRUE(bool_value); + + // Don't allow empty elements, even if |allow_trailing_comma| is + // true. + root.reset(JSONReader::DeprecatedRead("[,]", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + root.reset( + JSONReader::DeprecatedRead("[true,,]", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + root.reset( + JSONReader::DeprecatedRead("[,true,]", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + root.reset( + JSONReader::DeprecatedRead("[true,,false]", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + + // Test objects + root.reset(JSONReader::DeprecatedRead("{}")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + + root.reset(JSONReader::DeprecatedRead( + "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + DictionaryValue* dict_val = static_cast<DictionaryValue*>(root.get()); + double_val = 0.0; + EXPECT_TRUE(dict_val->GetDouble("number", &double_val)); + EXPECT_DOUBLE_EQ(9.87654321, double_val); + Value* null_val = NULL; + ASSERT_TRUE(dict_val->Get("null", &null_val)); + EXPECT_TRUE(null_val->IsType(Value::TYPE_NULL)); + str_val.clear(); + EXPECT_TRUE(dict_val->GetString("S", &str_val)); + EXPECT_EQ("str", str_val); + + root2.reset(JSONReader::DeprecatedRead( + "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }", + JSON_ALLOW_TRAILING_COMMAS)); + ASSERT_TRUE(root2.get()); + EXPECT_TRUE(root->Equals(root2.get())); + + // Test newline equivalence. + root2.reset(JSONReader::DeprecatedRead( + "{\n" + " \"number\":9.87654321,\n" + " \"null\":null,\n" + " \"\\x53\":\"str\",\n" + "}\n", + JSON_ALLOW_TRAILING_COMMAS)); + ASSERT_TRUE(root2.get()); + EXPECT_TRUE(root->Equals(root2.get())); + + root2.reset(JSONReader::DeprecatedRead( + "{\r\n" + " \"number\":9.87654321,\r\n" + " \"null\":null,\r\n" + " \"\\x53\":\"str\",\r\n" + "}\r\n", + JSON_ALLOW_TRAILING_COMMAS)); + ASSERT_TRUE(root2.get()); + EXPECT_TRUE(root->Equals(root2.get())); + + // Test nesting + root.reset(JSONReader::DeprecatedRead( + "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + dict_val = static_cast<DictionaryValue*>(root.get()); + DictionaryValue* inner_dict = NULL; + ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict)); + ListValue* inner_array = NULL; + ASSERT_TRUE(inner_dict->GetList("array", &inner_array)); + EXPECT_EQ(1U, inner_array->GetSize()); + bool_value = true; + EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value)); + EXPECT_FALSE(bool_value); + inner_dict = NULL; + EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict)); + + root2.reset(JSONReader::DeprecatedRead( + "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}", + JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_TRUE(root->Equals(root2.get())); + + // Test keys with periods + root.reset(JSONReader::DeprecatedRead( + "{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + dict_val = static_cast<DictionaryValue*>(root.get()); + int integer_value = 0; + EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); + EXPECT_EQ(3, integer_value); + EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value)); + EXPECT_EQ(2, integer_value); + inner_dict = NULL; + ASSERT_TRUE(dict_val->GetDictionaryWithoutPathExpansion("d.e.f", + &inner_dict)); + EXPECT_EQ(1U, inner_dict->size()); + EXPECT_TRUE(inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j", + &integer_value)); + EXPECT_EQ(1, integer_value); + + root.reset(JSONReader::DeprecatedRead("{\"a\":{\"b\":2},\"a.b\":1}")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + dict_val = static_cast<DictionaryValue*>(root.get()); + EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value)); + EXPECT_EQ(2, integer_value); + EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value)); + EXPECT_EQ(1, integer_value); + + // Invalid, no closing brace + root.reset(JSONReader::DeprecatedRead("{\"a\": true")); + EXPECT_FALSE(root.get()); + + // Invalid, keys must be quoted + root.reset(JSONReader::DeprecatedRead("{foo:true}")); + EXPECT_FALSE(root.get()); + + // Invalid, trailing comma + root.reset(JSONReader::DeprecatedRead("{\"a\":true,}")); + EXPECT_FALSE(root.get()); + + // Invalid, too many commas + root.reset(JSONReader::DeprecatedRead("{\"a\":true,,\"b\":false}")); + EXPECT_FALSE(root.get()); + root.reset(JSONReader::DeprecatedRead("{\"a\":true,,\"b\":false}", + JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + + // Invalid, no separator + root.reset(JSONReader::DeprecatedRead("{\"a\" \"b\"}")); + EXPECT_FALSE(root.get()); + + // Invalid, lone comma. + root.reset(JSONReader::DeprecatedRead("{,}")); + EXPECT_FALSE(root.get()); + root.reset(JSONReader::DeprecatedRead("{,}", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + root.reset( + JSONReader::DeprecatedRead("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + root.reset( + JSONReader::DeprecatedRead("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + root.reset(JSONReader::DeprecatedRead("{\"a\":true,,\"b\":false}", + JSON_ALLOW_TRAILING_COMMAS)); + EXPECT_FALSE(root.get()); + + // Test stack overflow + std::string evil(1000000, '['); + evil.append(std::string(1000000, ']')); + root.reset(JSONReader::DeprecatedRead(evil)); + EXPECT_FALSE(root.get()); + + // A few thousand adjacent lists is fine. + std::string not_evil("["); + not_evil.reserve(15010); + for (int i = 0; i < 5000; ++i) { + not_evil.append("[],"); + } + not_evil.append("[]]"); + root.reset(JSONReader::DeprecatedRead(not_evil)); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_LIST)); + list = static_cast<ListValue*>(root.get()); + EXPECT_EQ(5001U, list->GetSize()); + + // Test utf8 encoded input + root = JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\""); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + str_val.clear(); + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("\xE7\xBD\x91\xE9\xA1\xB5", str_val); + + root = JSONReader().ReadToValue( + "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}"); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + EXPECT_TRUE(root->GetAsDictionary(&dict_val)); + EXPECT_TRUE(dict_val->GetString("path", &str_val)); + EXPECT_EQ("/tmp/\xC3\xA0\xC3\xA8\xC3\xB2.png", str_val); + + // Test invalid utf8 encoded input + root = JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\""); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("\"123\xc0\x81\""); + EXPECT_FALSE(root.get()); + root = JSONReader().ReadToValue("\"abc\xc0\xae\""); + EXPECT_FALSE(root.get()); + + // Test utf16 encoded strings. + root = JSONReader().ReadToValue("\"\\u20ac3,14\""); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + str_val.clear(); + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("\xe2\x82\xac""3,14", str_val); + + root = JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\""); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->IsType(Value::TYPE_STRING)); + str_val.clear(); + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", str_val); + + // Test invalid utf16 strings. + const char* const cases[] = { + "\"\\u123\"", // Invalid scalar. + "\"\\ud83d\"", // Invalid scalar. + "\"\\u$%@!\"", // Invalid scalar. + "\"\\uzz89\"", // Invalid scalar. + "\"\\ud83d\\udca\"", // Invalid lower surrogate. + "\"\\ud83d\\ud83d\"", // Invalid lower surrogate. + "\"\\ud83foo\"", // No lower surrogate. + "\"\\ud83\\foo\"" // No lower surrogate. + }; + for (size_t i = 0; i < arraysize(cases); ++i) { + root = JSONReader().ReadToValue(cases[i]); + EXPECT_FALSE(root.get()) << cases[i]; + } + + // Test literal root objects. + root.reset(JSONReader::DeprecatedRead("null")); + EXPECT_TRUE(root->IsType(Value::TYPE_NULL)); + + root.reset(JSONReader::DeprecatedRead("true")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->GetAsBoolean(&bool_value)); + EXPECT_TRUE(bool_value); + + root.reset(JSONReader::DeprecatedRead("10")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->GetAsInteger(&integer_value)); + EXPECT_EQ(10, integer_value); + + root.reset(JSONReader::DeprecatedRead("\"root\"")); + ASSERT_TRUE(root.get()); + EXPECT_TRUE(root->GetAsString(&str_val)); + EXPECT_EQ("root", str_val); +} + +// Tests that the root of a JSON object can be deleted safely while its +// children outlive it. +TEST(JSONReaderTest, StringOptimizations) { + scoped_ptr<Value> dict_literal_0; + scoped_ptr<Value> dict_literal_1; + scoped_ptr<Value> dict_string_0; + scoped_ptr<Value> dict_string_1; + scoped_ptr<Value> list_value_0; + scoped_ptr<Value> list_value_1; + + { + scoped_ptr<Value> root = JSONReader::Read( + "{" + " \"test\": {" + " \"foo\": true," + " \"bar\": 3.14," + " \"baz\": \"bat\"," + " \"moo\": \"cow\"" + " }," + " \"list\": [" + " \"a\"," + " \"b\"" + " ]" + "}", + JSON_DETACHABLE_CHILDREN); + ASSERT_TRUE(root.get()); + + DictionaryValue* root_dict = NULL; + ASSERT_TRUE(root->GetAsDictionary(&root_dict)); + + DictionaryValue* dict = NULL; + ListValue* list = NULL; + + ASSERT_TRUE(root_dict->GetDictionary("test", &dict)); + ASSERT_TRUE(root_dict->GetList("list", &list)); + + EXPECT_TRUE(dict->Remove("foo", &dict_literal_0)); + EXPECT_TRUE(dict->Remove("bar", &dict_literal_1)); + EXPECT_TRUE(dict->Remove("baz", &dict_string_0)); + EXPECT_TRUE(dict->Remove("moo", &dict_string_1)); + + ASSERT_EQ(2u, list->GetSize()); + EXPECT_TRUE(list->Remove(0, &list_value_0)); + EXPECT_TRUE(list->Remove(0, &list_value_1)); + } + + bool b = false; + double d = 0; + std::string s; + + EXPECT_TRUE(dict_literal_0->GetAsBoolean(&b)); + EXPECT_TRUE(b); + + EXPECT_TRUE(dict_literal_1->GetAsDouble(&d)); + EXPECT_EQ(3.14, d); + + EXPECT_TRUE(dict_string_0->GetAsString(&s)); + EXPECT_EQ("bat", s); + + EXPECT_TRUE(dict_string_1->GetAsString(&s)); + EXPECT_EQ("cow", s); + + EXPECT_TRUE(list_value_0->GetAsString(&s)); + EXPECT_EQ("a", s); + EXPECT_TRUE(list_value_1->GetAsString(&s)); + EXPECT_EQ("b", s); +} + +// A smattering of invalid JSON designed to test specific portions of the +// parser implementation against buffer overflow. Best run with DCHECKs so +// that the one in NextChar fires. +TEST(JSONReaderTest, InvalidSanity) { + const char* const invalid_json[] = { + "/* test *", + "{\"foo\"", + "{\"foo\":", + " [", + "\"\\u123g\"", + "{\n\"eh:\n}", + }; + + for (size_t i = 0; i < arraysize(invalid_json); ++i) { + JSONReader reader; + LOG(INFO) << "Sanity test " << i << ": <" << invalid_json[i] << ">"; + EXPECT_FALSE(reader.ReadToValue(invalid_json[i])); + EXPECT_NE(JSONReader::JSON_NO_ERROR, reader.error_code()); + EXPECT_NE("", reader.GetErrorMessage()); + } +} + +TEST(JSONReaderTest, IllegalTrailingNull) { + const char json[] = { '"', 'n', 'u', 'l', 'l', '"', '\0' }; + std::string json_string(json, sizeof(json)); + JSONReader reader; + EXPECT_FALSE(reader.ReadToValue(json_string)); + EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, reader.error_code()); +} + +} // namespace base diff --git a/third_party/chromium/base/json/json_writer.cc b/third_party/chromium/base/json/json_writer.cc new file mode 100644 index 0000000..8bf4c6f --- /dev/null +++ b/third_party/chromium/base/json/json_writer.cc @@ -0,0 +1,208 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/json/json_writer.h" + +#include <cmath> + +#include "base/json/string_escape.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversion_utils.h" +#include "base/values.h" + +namespace base { + +#if defined(OS_WIN) +const char kPrettyPrintLineEnding[] = "\r\n"; +#else +const char kPrettyPrintLineEnding[] = "\n"; +#endif + +// static +bool JSONWriter::Write(const Value& node, std::string* json) { + return WriteWithOptions(node, 0, json); +} + +// static +bool JSONWriter::WriteWithOptions(const Value& node, + int options, + std::string* json) { + json->clear(); + // Is there a better way to estimate the size of the output? + json->reserve(1024); + + JSONWriter writer(options, json); + bool result = writer.BuildJSONString(node, 0U); + + if (options & OPTIONS_PRETTY_PRINT) + json->append(kPrettyPrintLineEnding); + + return result; +} + +JSONWriter::JSONWriter(int options, std::string* json) + : omit_binary_values_((options & OPTIONS_OMIT_BINARY_VALUES) != 0), + omit_double_type_preservation_( + (options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION) != 0), + pretty_print_((options & OPTIONS_PRETTY_PRINT) != 0), + json_string_(json) { + DCHECK(json); +} + +bool JSONWriter::BuildJSONString(const Value& node, size_t depth) { + switch (node.GetType()) { + case Value::TYPE_NULL: { + json_string_->append("null"); + return true; + } + + case Value::TYPE_BOOLEAN: { + bool value; + bool result = node.GetAsBoolean(&value); + DCHECK(result); + json_string_->append(value ? "true" : "false"); + return result; + } + + case Value::TYPE_INTEGER: { + int value; + bool result = node.GetAsInteger(&value); + DCHECK(result); + json_string_->append(IntToString(value)); + return result; + } + + case Value::TYPE_DOUBLE: { + double value; + bool result = node.GetAsDouble(&value); + DCHECK(result); + if (omit_double_type_preservation_ && + value <= kint64max && + value >= kint64min && + std::floor(value) == value) { + json_string_->append(Int64ToString(static_cast<int64>(value))); + return result; + } + std::string real = DoubleToString(value); + // Ensure that the number has a .0 if there's no decimal or 'e'. This + // makes sure that when we read the JSON back, it's interpreted as a + // real rather than an int. + if (real.find('.') == std::string::npos && + real.find('e') == std::string::npos && + real.find('E') == std::string::npos) { + real.append(".0"); + } + // The JSON spec requires that non-integer values in the range (-1,1) + // have a zero before the decimal point - ".52" is not valid, "0.52" is. + if (real[0] == '.') { + real.insert(static_cast<size_t>(0), static_cast<size_t>(1), '0'); + } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') { + // "-.1" bad "-0.1" good + real.insert(static_cast<size_t>(1), static_cast<size_t>(1), '0'); + } + json_string_->append(real); + return result; + } + + case Value::TYPE_STRING: { + std::string value; + bool result = node.GetAsString(&value); + DCHECK(result); + EscapeJSONString(value, true, json_string_); + return result; + } + + case Value::TYPE_LIST: { + json_string_->push_back('['); + if (pretty_print_) + json_string_->push_back(' '); + + const ListValue* list = NULL; + bool first_value_has_been_output = false; + bool result = node.GetAsList(&list); + DCHECK(result); + for (ListValue::const_iterator it = list->begin(); it != list->end(); + ++it) { + const Value* value = *it; + if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) + continue; + + if (first_value_has_been_output) { + json_string_->push_back(','); + if (pretty_print_) + json_string_->push_back(' '); + } + + if (!BuildJSONString(*value, depth)) + result = false; + + first_value_has_been_output = true; + } + + if (pretty_print_) + json_string_->push_back(' '); + json_string_->push_back(']'); + return result; + } + + case Value::TYPE_DICTIONARY: { + json_string_->push_back('{'); + if (pretty_print_) + json_string_->append(kPrettyPrintLineEnding); + + const DictionaryValue* dict = NULL; + bool first_value_has_been_output = false; + bool result = node.GetAsDictionary(&dict); + DCHECK(result); + for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd(); + itr.Advance()) { + if (omit_binary_values_ && + itr.value().GetType() == Value::TYPE_BINARY) { + continue; + } + + if (first_value_has_been_output) { + json_string_->push_back(','); + if (pretty_print_) + json_string_->append(kPrettyPrintLineEnding); + } + + if (pretty_print_) + IndentLine(depth + 1U); + + EscapeJSONString(itr.key(), true, json_string_); + json_string_->push_back(':'); + if (pretty_print_) + json_string_->push_back(' '); + + if (!BuildJSONString(itr.value(), depth + 1U)) + result = false; + + first_value_has_been_output = true; + } + + if (pretty_print_) { + json_string_->append(kPrettyPrintLineEnding); + IndentLine(depth); + } + + json_string_->push_back('}'); + return result; + } + + case Value::TYPE_BINARY: + // Successful only if we're allowed to omit it. + DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value."; + return omit_binary_values_; + } + NOTREACHED(); + return false; +} + +void JSONWriter::IndentLine(size_t depth) { + json_string_->append(depth * 3U, ' '); +} + +} // namespace base diff --git a/third_party/chromium/base/json/json_writer.h b/third_party/chromium/base/json/json_writer.h new file mode 100644 index 0000000..5711665 --- /dev/null +++ b/third_party/chromium/base/json/json_writer.h @@ -0,0 +1,71 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_JSON_JSON_WRITER_H_ +#define BASE_JSON_JSON_WRITER_H_ + +#include <string> + +#include "base/base_export.h" +#include "base/basictypes.h" + +namespace base { + +class Value; + +class BASE_EXPORT JSONWriter { + public: + enum Options { + // This option instructs the writer that if a Binary value is encountered, + // the value (and key if within a dictionary) will be omitted from the + // output, and success will be returned. Otherwise, if a binary value is + // encountered, failure will be returned. + OPTIONS_OMIT_BINARY_VALUES = 1 << 0, + + // This option instructs the writer to write doubles that have no fractional + // part as a normal integer (i.e., without using exponential notation + // or appending a '.0') as long as the value is within the range of a + // 64-bit int. + OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 1, + + // Return a slightly nicer formatted json string (pads with whitespace to + // help with readability). + OPTIONS_PRETTY_PRINT = 1 << 2, + }; + + // Given a root node, generates a JSON string and puts it into |json|. + // TODO(tc): Should we generate json if it would be invalid json (e.g., + // |node| is not a DictionaryValue/ListValue or if there are inf/-inf float + // values)? Return true on success and false on failure. + static bool Write(const Value& node, std::string* json); + + // Same as above but with |options| which is a bunch of JSONWriter::Options + // bitwise ORed together. Return true on success and false on failure. + static bool WriteWithOptions(const Value& node, + int options, + std::string* json); + + private: + JSONWriter(int options, std::string* json); + + // Called recursively to build the JSON string. When completed, + // |json_string_| will contain the JSON. + bool BuildJSONString(const Value& node, size_t depth); + + // Adds space to json_string_ for the indent level. + void IndentLine(size_t depth); + + bool omit_binary_values_; + bool omit_double_type_preservation_; + bool pretty_print_; + + // Where we write JSON data as we generate it. + std::string* json_string_; + + DISALLOW_COPY_AND_ASSIGN(JSONWriter); +}; + +} // namespace base + +#endif // BASE_JSON_JSON_WRITER_H_ diff --git a/third_party/chromium/base/json/json_writer_unittest.cc b/third_party/chromium/base/json/json_writer_unittest.cc new file mode 100644 index 0000000..cb88cde --- /dev/null +++ b/third_party/chromium/base/json/json_writer_unittest.cc @@ -0,0 +1,156 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/json/json_writer.h" + +#include <gtest/gtest.h> + +#include "base/values.h" + +namespace base { + +TEST(JSONWriterTest, BasicTypes) { + std::string output_js; + + // Test null. + EXPECT_TRUE(JSONWriter::Write(*Value::CreateNullValue(), &output_js)); + EXPECT_EQ("null", output_js); + + // Test empty dict. + EXPECT_TRUE(JSONWriter::Write(DictionaryValue(), &output_js)); + EXPECT_EQ("{}", output_js); + + // Test empty list. + EXPECT_TRUE(JSONWriter::Write(ListValue(), &output_js)); + EXPECT_EQ("[]", output_js); + + // Test integer values. + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(42), &output_js)); + EXPECT_EQ("42", output_js); + + // Test boolean values. + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(true), &output_js)); + EXPECT_EQ("true", output_js); + + // Test Real values should always have a decimal or an 'e'. + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(1.0), &output_js)); + EXPECT_EQ("1.0", output_js); + + // Test Real values in the the range (-1, 1) must have leading zeros + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(0.2), &output_js)); + EXPECT_EQ("0.2", output_js); + + // Test Real values in the the range (-1, 1) must have leading zeros + EXPECT_TRUE(JSONWriter::Write(FundamentalValue(-0.8), &output_js)); + EXPECT_EQ("-0.8", output_js); + + // Test String values. + EXPECT_TRUE(JSONWriter::Write(StringValue("foo"), &output_js)); + EXPECT_EQ("\"foo\"", output_js); +} + +TEST(JSONWriterTest, NestedTypes) { + std::string output_js; + + // Writer unittests like empty list/dict nesting, + // list list nesting, etc. + DictionaryValue root_dict; + scoped_ptr<ListValue> list(new ListValue()); + scoped_ptr<DictionaryValue> inner_dict(new DictionaryValue()); + inner_dict->SetInteger("inner int", 10); + list->Append(inner_dict.Pass()); + list->Append(make_scoped_ptr(new ListValue())); + list->AppendBoolean(true); + root_dict.Set("list", list.Pass()); + + // Test the pretty-printer. + EXPECT_TRUE(JSONWriter::Write(root_dict, &output_js)); + EXPECT_EQ("{\"list\":[{\"inner int\":10},[],true]}", output_js); + EXPECT_TRUE(JSONWriter::WriteWithOptions( + root_dict, JSONWriter::OPTIONS_PRETTY_PRINT, &output_js)); + + // The pretty-printer uses a different newline style on Windows than on + // other platforms. +#if defined(OS_WIN) +#define JSON_NEWLINE "\r\n" +#else +#define JSON_NEWLINE "\n" +#endif + EXPECT_EQ("{" JSON_NEWLINE + " \"list\": [ {" JSON_NEWLINE + " \"inner int\": 10" JSON_NEWLINE + " }, [ ], true ]" JSON_NEWLINE + "}" JSON_NEWLINE, + output_js); +#undef JSON_NEWLINE +} + +TEST(JSONWriterTest, KeysWithPeriods) { + std::string output_js; + + DictionaryValue period_dict; + period_dict.SetIntegerWithoutPathExpansion("a.b", 3); + period_dict.SetIntegerWithoutPathExpansion("c", 2); + scoped_ptr<DictionaryValue> period_dict2(new DictionaryValue()); + period_dict2->SetIntegerWithoutPathExpansion("g.h.i.j", 1); + period_dict.SetWithoutPathExpansion("d.e.f", period_dict2.Pass()); + EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js)); + EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js); + + DictionaryValue period_dict3; + period_dict3.SetInteger("a.b", 2); + period_dict3.SetIntegerWithoutPathExpansion("a.b", 1); + EXPECT_TRUE(JSONWriter::Write(period_dict3, &output_js)); + EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js); +} + +TEST(JSONWriterTest, BinaryValues) { + std::string output_js; + + // Binary values should return errors unless suppressed via the + // OPTIONS_OMIT_BINARY_VALUES flag. + scoped_ptr<Value> root(BinaryValue::CreateWithCopiedBuffer("asdf", 4)); + EXPECT_FALSE(JSONWriter::Write(*root, &output_js)); + EXPECT_TRUE(JSONWriter::WriteWithOptions( + *root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); + EXPECT_TRUE(output_js.empty()); + + ListValue binary_list; + binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4)); + binary_list.Append(make_scoped_ptr(new FundamentalValue(5))); + binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4)); + binary_list.Append(make_scoped_ptr(new FundamentalValue(2))); + binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4)); + EXPECT_FALSE(JSONWriter::Write(binary_list, &output_js)); + EXPECT_TRUE(JSONWriter::WriteWithOptions( + binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); + EXPECT_EQ("[5,2]", output_js); + + DictionaryValue binary_dict; + binary_dict.Set( + "a", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4))); + binary_dict.SetInteger("b", 5); + binary_dict.Set( + "c", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4))); + binary_dict.SetInteger("d", 2); + binary_dict.Set( + "e", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4))); + EXPECT_FALSE(JSONWriter::Write(binary_dict, &output_js)); + EXPECT_TRUE(JSONWriter::WriteWithOptions( + binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js)); + EXPECT_EQ("{\"b\":5,\"d\":2}", output_js); +} + +TEST(JSONWriterTest, DoublesAsInts) { + std::string output_js; + + // Test allowing a double with no fractional part to be written as an integer. + FundamentalValue double_value(1e10); + EXPECT_TRUE(JSONWriter::WriteWithOptions( + double_value, JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, + &output_js)); + EXPECT_EQ("10000000000", output_js); +} + +} // namespace base diff --git a/third_party/chromium/base/json/string_escape.cc b/third_party/chromium/base/json/string_escape.cc new file mode 100644 index 0000000..7ba612f --- /dev/null +++ b/third_party/chromium/base/json/string_escape.cc @@ -0,0 +1,141 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/json/string_escape.h" + +#include <string> + +#include "base/logging.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversion_utils.h" +#include "base/third_party/icu/icu_utf.h" + +namespace base { + +namespace { + +// Format string for printing a \uXXXX escape sequence. +const char kU16EscapeFormat[] = "\\u%04X"; + +// The code point to output for an invalid input code unit. +const uint32 kReplacementCodePoint = 0xFFFD; + +// Used below in EscapeSpecialCodePoint(). +COMPILE_ASSERT('<' == 0x3C, less_than_sign_is_0x3c); + +// Try to escape the |code_point| if it is a known special character. If +// successful, returns true and appends the escape sequence to |dest|. This +// isn't required by the spec, but it's more readable by humans. +bool EscapeSpecialCodePoint(uint32 code_point, std::string* dest) { + // WARNING: if you add a new case here, you need to update the reader as well. + // Note: \v is in the reader, but not here since the JSON spec doesn't + // allow it. + switch (code_point) { + case '\b': + dest->append("\\b"); + break; + case '\f': + dest->append("\\f"); + break; + case '\n': + dest->append("\\n"); + break; + case '\r': + dest->append("\\r"); + break; + case '\t': + dest->append("\\t"); + break; + case '\\': + dest->append("\\\\"); + break; + case '"': + dest->append("\\\""); + break; + // Escape < to prevent script execution; escaping > is not necessary and + // not doing so save a few bytes. + case '<': + dest->append("\\u003C"); + break; + default: + return false; + } + return true; +} + +template <typename S> +bool EscapeJSONStringImpl(const S& str, bool put_in_quotes, std::string* dest) { + bool did_replacement = false; + + if (put_in_quotes) + dest->push_back('"'); + + // Casting is necessary because ICU uses int32. Try and do so safely. + CHECK_LE(str.length(), static_cast<size_t>(kint32max)); + const int32 length = static_cast<int32>(str.length()); + + for (int32 i = 0; i < length; ++i) { + uint32 code_point; + if (!ReadUnicodeCharacter(str.data(), length, &i, &code_point)) { + code_point = kReplacementCodePoint; + did_replacement = true; + } + + if (EscapeSpecialCodePoint(code_point, dest)) + continue; + + // Escape non-printing characters. + if (code_point < 32) + base::StringAppendF(dest, kU16EscapeFormat, code_point); + else + WriteUnicodeCharacter(code_point, dest); + } + + if (put_in_quotes) + dest->push_back('"'); + + return !did_replacement; +} + +} // namespace + +bool EscapeJSONString(const StringPiece& str, + bool put_in_quotes, + std::string* dest) { + return EscapeJSONStringImpl(str, put_in_quotes, dest); +} + +std::string GetQuotedJSONString(const StringPiece& str) { + std::string dest; + bool ok = EscapeJSONStringImpl(str, true, &dest); + DCHECK(ok); + return dest; +} + +std::string EscapeBytesAsInvalidJSONString(const StringPiece& str, + bool put_in_quotes) { + std::string dest; + + if (put_in_quotes) + dest.push_back('"'); + + for (StringPiece::const_iterator it = str.begin(); it != str.end(); ++it) { + unsigned char c = *it; + if (EscapeSpecialCodePoint(c, &dest)) + continue; + + if (c < 32 || c > 126) + base::StringAppendF(&dest, kU16EscapeFormat, c); + else + dest.push_back(*it); + } + + if (put_in_quotes) + dest.push_back('"'); + + return dest; +} + +} // namespace base diff --git a/third_party/chromium/base/json/string_escape.h b/third_party/chromium/base/json/string_escape.h new file mode 100644 index 0000000..6608b3b --- /dev/null +++ b/third_party/chromium/base/json/string_escape.h @@ -0,0 +1,52 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file defines utility functions for escaping strings suitable for JSON. + +#ifndef BASE_JSON_STRING_ESCAPE_H_ +#define BASE_JSON_STRING_ESCAPE_H_ + +#include <string> + +#include "base/base_export.h" +#include "base/strings/string_piece.h" + +namespace base { + +// Appends to |dest| an escaped version of |str|. Valid UTF-8 code units will +// pass through from the input to the output. Invalid code units will be +// replaced with the U+FFFD replacement character. This function returns true +// if no replacement was necessary and false if there was a lossy replacement. +// On return, |dest| will contain a valid UTF-8 JSON string. +// +// Non-printing control characters will be escaped as \uXXXX sequences for +// readability. +// +// If |put_in_quotes| is true, then a leading and trailing double-quote mark +// will be appended to |dest| as well. +bool EscapeJSONString(const StringPiece& str, + bool put_in_quotes, + std::string* dest); + +// Helper functions that wrap the above two functions but return the value +// instead of appending. |put_in_quotes| is always true. +std::string GetQuotedJSONString(const StringPiece& str); + +// Given an arbitrary byte string |str|, this will escape all non-ASCII bytes +// as \uXXXX escape sequences. This function is *NOT* meant to be used with +// Unicode strings and does not validate |str| as one. +// +// CAVEAT CALLER: The output of this function may not be valid JSON, since +// JSON requires escape sequences to be valid UTF-16 code units. This output +// will be mangled if passed to to the base::JSONReader, since the reader will +// interpret it as UTF-16 and convert it to UTF-8. +// +// The output of this function takes the *appearance* of JSON but is not in +// fact valid according to RFC 4627. +std::string EscapeBytesAsInvalidJSONString(const StringPiece& str, + bool put_in_quotes); + +} // namespace base + +#endif // BASE_JSON_STRING_ESCAPE_H_ diff --git a/third_party/chromium/base/json/string_escape_unittest.cc b/third_party/chromium/base/json/string_escape_unittest.cc new file mode 100644 index 0000000..615acc4 --- /dev/null +++ b/third_party/chromium/base/json/string_escape_unittest.cc @@ -0,0 +1,98 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/json/string_escape.h" + +#include <gtest/gtest.h> + +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversion_utils.h" + +namespace base { + +TEST(JSONStringEscapeTest, EscapeUTF8) { + const struct { + const char* to_escape; + const char* escaped; + } cases[] = { + {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"}, + {"a\b\f\n\r\t\v\1\\.\"z", + "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"}, + {"b\x0f\x7f\xf0\xff!", // \xf0\xff is not a valid UTF-8 unit. + "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"}, + {"c<>d", "c\\u003C>d"}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + const char* in_ptr = cases[i].to_escape; + std::string in_str = in_ptr; + + std::string out; + EscapeJSONString(in_ptr, false, &out); + EXPECT_EQ(std::string(cases[i].escaped), out); + EXPECT_TRUE(IsStringUTF8(out)); + + out.erase(); + bool convert_ok = EscapeJSONString(in_str, false, &out); + EXPECT_EQ(std::string(cases[i].escaped), out); + EXPECT_TRUE(IsStringUTF8(out)); + + if (convert_ok) { + std::string fooout = GetQuotedJSONString(in_str); + EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", fooout); + EXPECT_TRUE(IsStringUTF8(out)); + } + } + + std::string in = cases[0].to_escape; + std::string out; + EscapeJSONString(in, false, &out); + EXPECT_TRUE(IsStringUTF8(out)); + + // test quoting + std::string out_quoted; + EscapeJSONString(in, true, &out_quoted); + EXPECT_EQ(out.length() + 2, out_quoted.length()); + EXPECT_EQ(out_quoted.find(out), 1U); + EXPECT_TRUE(IsStringUTF8(out_quoted)); + + // now try with a NULL in the string + std::string null_prepend = "test"; + null_prepend.push_back(0); + in = null_prepend + in; + std::string expected = "test\\u0000"; + expected += cases[0].escaped; + out.clear(); + EscapeJSONString(in, false, &out); + EXPECT_EQ(expected, out); + EXPECT_TRUE(IsStringUTF8(out)); +} + +TEST(JSONStringEscapeTest, EscapeBytes) { + const struct { + const char* to_escape; + const char* escaped; + } cases[] = { + {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"}, + {"\xe5\xc4\x4f\x05\xb6\xfd", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + std::string in = std::string(cases[i].to_escape); + EXPECT_FALSE(IsStringUTF8(in)); + + EXPECT_EQ(std::string(cases[i].escaped), + EscapeBytesAsInvalidJSONString(in, false)); + EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", + EscapeBytesAsInvalidJSONString(in, true)); + } + + const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' }; + std::string in(kEmbedNull, arraysize(kEmbedNull)); + EXPECT_FALSE(IsStringUTF8(in)); + EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"), + EscapeBytesAsInvalidJSONString(in, false)); +} + +} // namespace base diff --git a/third_party/chromium/base/location.cc b/third_party/chromium/base/location.cc new file mode 100644 index 0000000..4b57912 --- /dev/null +++ b/third_party/chromium/base/location.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/build/build_config.h" + +#if defined(COMPILER_MSVC) +#include <intrin.h> +#endif + +#include "base/location.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" + +namespace tracked_objects { + +Location::Location(const char* function_name, + const char* file_name, + int line_number, + const void* program_counter) + : function_name_(function_name), + file_name_(file_name), + line_number_(line_number), + program_counter_(program_counter) { +} + +Location::Location() + : function_name_("Unknown"), + file_name_("Unknown"), + line_number_(-1), + program_counter_(NULL) { +} + +Location::Location(const Location& other) + : function_name_(other.function_name_), + file_name_(other.file_name_), + line_number_(other.line_number_), + program_counter_(other.program_counter_) { +} + +std::string Location::ToString() const { + return std::string(function_name_) + "@" + file_name_ + ":" + + base::IntToString(line_number_); +} + +void Location::Write(bool display_filename, bool display_function_name, + std::string* output) const { + base::StringAppendF(output, "%s[%d] ", + display_filename ? file_name_ : "line", + line_number_); + + if (display_function_name) { + WriteFunctionName(output); + output->push_back(' '); + } +} + +void Location::WriteFunctionName(std::string* output) const { + // Translate "<" to "<" for HTML safety. + // TODO(jar): Support ASCII or html for logging in ASCII. + for (const char *p = function_name_; *p; p++) { + switch (*p) { + case '<': + output->append("<"); + break; + + case '>': + output->append(">"); + break; + + default: + output->push_back(*p); + break; + } + } +} + +//------------------------------------------------------------------------------ +LocationSnapshot::LocationSnapshot() : line_number(-1) { +} + +LocationSnapshot::LocationSnapshot( + const tracked_objects::Location& location) + : file_name(location.file_name()), + function_name(location.function_name()), + line_number(location.line_number()) { +} + +LocationSnapshot::~LocationSnapshot() { +} + +//------------------------------------------------------------------------------ +#if defined(COMPILER_MSVC) +__declspec(noinline) +#endif + const void* GetProgramCounter() { +#if defined(COMPILER_MSVC) + return _ReturnAddress(); +#elif defined(COMPILER_GCC) && !defined(OS_NACL) + return __builtin_extract_return_addr(__builtin_return_address(0)); +#else + return NULL; +#endif +} + +} // namespace tracked_objects diff --git a/third_party/chromium/base/location.h b/third_party/chromium/base/location.h new file mode 100644 index 0000000..4a38264 --- /dev/null +++ b/third_party/chromium/base/location.h @@ -0,0 +1,92 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_LOCATION_H_ +#define BASE_LOCATION_H_ + +#include <cassert> +#include <string> + +#include "base/base_export.h" +#include "base/basictypes.h" + +namespace tracked_objects { + +// Location provides basic info where of an object was constructed, or was +// significantly brought to life. +class BASE_EXPORT Location { + public: + // Constructor should be called with a long-lived char*, such as __FILE__. + // It assumes the provided value will persist as a global constant, and it + // will not make a copy of it. + Location(const char* function_name, + const char* file_name, + int line_number, + const void* program_counter); + + // Provide a default constructor for easy of debugging. + Location(); + + // Copy constructor. + Location(const Location& other); + + // Comparator for hash map insertion. + // No need to use |function_name_| since the other two fields uniquely + // identify this location. + bool operator==(const Location& other) const { + return line_number_ == other.line_number_ && + file_name_ == other.file_name_; + } + + const char* function_name() const { return function_name_; } + const char* file_name() const { return file_name_; } + int line_number() const { return line_number_; } + const void* program_counter() const { return program_counter_; } + + std::string ToString() const; + + // Translate the some of the state in this instance into a human readable + // string with HTML characters in the function names escaped, and append that + // string to |output|. Inclusion of the file_name_ and function_name_ are + // optional, and controlled by the boolean arguments. + void Write(bool display_filename, bool display_function_name, + std::string* output) const; + + // Write function_name_ in HTML with '<' and '>' properly encoded. + void WriteFunctionName(std::string* output) const; + + private: + const char* function_name_; + const char* file_name_; + int line_number_; + const void* program_counter_; +}; + +// A "snapshotted" representation of the Location class that can safely be +// passed across process boundaries. +struct BASE_EXPORT LocationSnapshot { + // The default constructor is exposed to support the IPC serialization macros. + LocationSnapshot(); + explicit LocationSnapshot(const tracked_objects::Location& location); + ~LocationSnapshot(); + + std::string file_name; + std::string function_name; + int line_number; +}; + +BASE_EXPORT const void* GetProgramCounter(); + +// Define a macro to record the current source location. +#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__FUNCTION__) + +#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name) \ + ::tracked_objects::Location(function_name, \ + __FILE__, \ + __LINE__, \ + ::tracked_objects::GetProgramCounter()) + +} // namespace tracked_objects + +#endif // BASE_LOCATION_H_ diff --git a/third_party/chromium/base/logging.cc b/third_party/chromium/base/logging.cc new file mode 100644 index 0000000..1fd047f --- /dev/null +++ b/third_party/chromium/base/logging.cc @@ -0,0 +1,255 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/logging.h" + +#include <sys/syscall.h> +#include <time.h> +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <algorithm> +#include <cstring> +#include <ctime> +#include <iomanip> +#include <ostream> +#include <string> + +#include "base/posix/eintr_wrapper.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversion_utils.h" + +namespace logging { + +namespace { + +const char* const log_severity_names[LOG_NUM_SEVERITIES] = { + "INFO", "WARNING", "ERROR", "FATAL" }; + +const char* log_severity_name(int severity) { + if (severity >= 0 && severity < LOG_NUM_SEVERITIES) + return log_severity_names[severity]; + return "UNKNOWN"; +} + +int g_min_log_level = 0; + +LoggingDestination g_logging_destination = LOG_DEFAULT; + +// For LOG_ERROR and above, always print to stderr. +const int kAlwaysPrintErrorLevel = LOG_ERROR; + +// What should be prepended to each message? +bool g_log_timestamp = true; + +// Should we pop up fatal debug messages in a dialog? +bool show_error_dialogs = false; + +// An assert handler override specified by the client to be called instead of +// the debug message dialog and process termination. +LogAssertHandlerFunction log_assert_handler = nullptr; +// A log message handler that gets notified of every log message we process. +LogMessageHandlerFunction log_message_handler = nullptr; + +// Helper functions to wrap platform differences. + +} // namespace + +LoggingSettings::LoggingSettings() + : logging_dest(LOG_DEFAULT) {} + +bool BaseInitLoggingImpl(const LoggingSettings& settings) { + g_logging_destination = settings.logging_dest; + + return true; +} + +void SetMinLogLevel(int level) { + g_min_log_level = std::min(LOG_FATAL, level); +} + +int GetMinLogLevel() { + return g_min_log_level; +} + +int GetVlogVerbosity() { + return std::max(-1, LOG_INFO - GetMinLogLevel()); +} + +void SetLogItems(bool enable_process_id, bool enable_thread_id, + bool enable_timestamp, bool enable_tickcount) { + g_log_timestamp = enable_timestamp; +} + +void SetShowErrorDialogs(bool enable_dialogs) { + show_error_dialogs = enable_dialogs; +} + +void SetLogAssertHandler(LogAssertHandlerFunction handler) { + log_assert_handler = handler; +} + +void SetLogMessageHandler(LogMessageHandlerFunction handler) { + log_message_handler = handler; +} + +LogMessageHandlerFunction GetLogMessageHandler() { + return log_message_handler; +} + +// Explicit instantiations for commonly used comparisons. +template std::string* MakeCheckOpString<int, int>( + const int&, const int&, const char* names); +template std::string* MakeCheckOpString<unsigned long, unsigned long>( + const unsigned long&, const unsigned long&, const char* names); +template std::string* MakeCheckOpString<unsigned long, unsigned int>( + const unsigned long&, const unsigned int&, const char* names); +template std::string* MakeCheckOpString<unsigned int, unsigned long>( + const unsigned int&, const unsigned long&, const char* names); +template std::string* MakeCheckOpString<std::string, std::string>( + const std::string&, const std::string&, const char* name); + +LogMessage::LogMessage(const char* file, int line, LogSeverity severity) + : severity_(severity), file_(file), line_(line) { + Init(file, line); +} + +LogMessage::LogMessage(const char* file, int line, std::string* result) + : severity_(LOG_FATAL), file_(file), line_(line) { + Init(file, line); + stream_ << "Check failed: " << *result; + delete result; +} + +LogMessage::LogMessage(const char* file, int line, LogSeverity severity, + std::string* result) + : severity_(severity), file_(file), line_(line) { + Init(file, line); + stream_ << "Check failed: " << *result; + delete result; +} + +LogMessage::~LogMessage() { + stream_ << std::endl; + std::string str_newline(stream_.str()); + + // Give any log message handler first dibs on the message. + if (log_message_handler && + log_message_handler(severity_, file_, line_, + message_start_, str_newline)) { + // The handler took care of it, no further processing. + return; + } + + if ((g_logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) { + ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr)); + fflush(stderr); + } else if (severity_ >= kAlwaysPrintErrorLevel) { + // When we're only outputting to a log file, above a certain log level, we + // should still output to stderr so that we can better detect and diagnose + // problems with unit tests, especially on the buildbots. + ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr)); + fflush(stderr); + } + + if (severity_ == LOG_FATAL) { + // Ensure the first characters of the string are on the stack so they + // are contained in minidumps for diagnostic purposes. + char str_stack[1024]; + str_newline.copy(str_stack, arraysize(str_stack)); + + if (log_assert_handler) { + // Make a copy of the string for the handler out of paranoia. + log_assert_handler(std::string(stream_.str())); + } else { + // Crash the process to generate a dump. + abort(); + } + } +} + +// writes the common header info to the stream +void LogMessage::Init(const char* file, int line) { + base::StringPiece filename(file); + size_t last_slash_pos = filename.find_last_of("\\/"); + if (last_slash_pos != base::StringPiece::npos) + filename.remove_prefix(last_slash_pos + 1); + + // TODO(darin): It might be nice if the columns were fixed width. + + stream_ << '['; + if (g_log_timestamp) { + time_t t = time(nullptr); + struct tm local_time = {0}; +#ifdef _MSC_VER + localtime_s(&local_time, &t); +#else + localtime_r(&t, &local_time); +#endif + struct tm* tm_time = &local_time; + stream_ << std::setfill('0') + << std::setw(2) << 1 + tm_time->tm_mon + << std::setw(2) << tm_time->tm_mday + << '/' + << std::setw(2) << tm_time->tm_hour + << std::setw(2) << tm_time->tm_min + << std::setw(2) << tm_time->tm_sec + << ':'; + } + if (severity_ >= 0) + stream_ << log_severity_name(severity_); + else + stream_ << "VERBOSE" << -severity_; + + stream_ << ":" << filename << "(" << line << ")] "; + + message_start_ = stream_.str().length(); +} + +void RawLog(int level, const char* message) { + if (level >= g_min_log_level) { + size_t bytes_written = 0; + const size_t message_len = strlen(message); + int rv; + while (bytes_written < message_len) { + rv = HANDLE_EINTR( + write(STDERR_FILENO, message + bytes_written, + message_len - bytes_written)); + if (rv < 0) { + // Give up, nothing we can do now. + break; + } + bytes_written += rv; + } + + if (message_len > 0 && message[message_len - 1] != '\n') { + do { + rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); + if (rv < 0) { + // Give up, nothing we can do now. + break; + } + } while (rv != 1); + } + } + + if (level == LOG_FATAL) + abort(); +} + +// This was defined at the beginning of this file. +#undef write + +void LogErrorNotReached(const char* file, int line) { + LogMessage(file, line, LOG_ERROR).stream() + << "NOTREACHED() hit."; +} + +} // namespace logging diff --git a/third_party/chromium/base/logging.h b/third_party/chromium/base/logging.h new file mode 100644 index 0000000..61e9f9d --- /dev/null +++ b/third_party/chromium/base/logging.h @@ -0,0 +1,671 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_LOGGING_H_ +#define BASE_LOGGING_H_ + +#include <cassert> +#include <string> +#include <cstring> +#include <sstream> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/build/build_config.h" + +// +// Optional message capabilities +// ----------------------------- +// Assertion failed messages and fatal errors are displayed in a dialog box +// before the application exits. However, running this UI creates a message +// loop, which causes application messages to be processed and potentially +// dispatched to existing application windows. Since the application is in a +// bad state when this assertion dialog is displayed, these messages may not +// get processed and hang the dialog, or the application might go crazy. +// +// Therefore, it can be beneficial to display the error dialog in a separate +// process from the main application. When the logging system needs to display +// a fatal error dialog box, it will look for a program called +// "DebugMessage.exe" in the same directory as the application executable. It +// will run this application with the message as the command line, and will +// not include the name of the application as is traditional for easier +// parsing. +// +// The code for DebugMessage.exe is only one line. In WinMain, do: +// MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0); +// +// If DebugMessage.exe is not found, the logging code will use a normal +// MessageBox, potentially causing the problems discussed above. + + +// Instructions +// ------------ +// +// Make a bunch of macros for logging. The way to log things is to stream +// things to LOG(<a particular severity level>). E.g., +// +// LOG(INFO) << "Found " << num_cookies << " cookies"; +// +// You can also do conditional logging: +// +// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// The CHECK(condition) macro is active in both debug and release builds and +// effectively performs a LOG(FATAL) which terminates the process and +// generates a crashdump unless a debugger is attached. +// +// There are also "debug mode" logging macros like the ones above: +// +// DLOG(INFO) << "Found cookies"; +// +// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// All "debug mode" logging is compiled away to nothing for non-debug mode +// compiles. LOG_IF and development flags also work well together +// because the code can be compiled away sometimes. +// +// We also have +// +// LOG_ASSERT(assertion); +// DLOG_ASSERT(assertion); +// +// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; +// +// There are "verbose level" logging macros. They look like +// +// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; +// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; +// +// These always log at the INFO log level (when they log at all). +// The verbose logging can also be turned on module-by-module. For instance, +// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0 +// will cause: +// a. VLOG(2) and lower messages to be printed from profile.{h,cc} +// b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc} +// c. VLOG(3) and lower messages to be printed from files prefixed with +// "browser" +// d. VLOG(4) and lower messages to be printed from files under a +// "chromeos" directory. +// e. VLOG(0) and lower messages to be printed from elsewhere +// +// The wildcarding functionality shown by (c) supports both '*' (match +// 0 or more characters) and '?' (match any single character) +// wildcards. Any pattern containing a forward or backward slash will +// be tested against the whole pathname and not just the module. +// E.g., "*/foo/bar/*=2" would change the logging level for all code +// in source files under a "foo/bar" directory. +// +// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as +// +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished with just VLOG(2) << ...; +// } +// +// There is also a VLOG_IF "verbose level" condition macro for sample +// cases, when some extra computation and preparation for logs is not +// needed. +// +// VLOG_IF(1, (size > 1024)) +// << "I'm printed when size is more than 1024 and when you run the " +// "program with --v=1 or more"; +// +// We also override the standard 'assert' to use 'DLOG_ASSERT'. +// +// The supported severity levels for macros that allow you to specify one +// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. +// +// Very important: logging a message at the FATAL severity level causes +// the program to terminate (after the message is logged). +// +// There is the special severity of DFATAL, which logs FATAL in debug mode, +// ERROR in normal mode. + +namespace logging { + +// Where to record logging output? A flat file and/or system debug log +// via OutputDebugString. +enum LoggingDestination { + LOG_NONE = 0, + LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1, + + LOG_TO_ALL = LOG_TO_SYSTEM_DEBUG_LOG, + + LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG, +}; + +struct BASE_EXPORT LoggingSettings { + // The defaults values are: + // + // logging_dest: LOG_DEFAULT + LoggingSettings(); + + LoggingDestination logging_dest; +}; + +// Define different names for the BaseInitLoggingImpl() function depending on +// whether NDEBUG is defined or not so that we'll fail to link if someone tries +// to compile logging.cc with NDEBUG but includes logging.h without defining it, +// or vice versa. +#if NDEBUG +#define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG +#else +#define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG +#endif + +// Implementation of the InitLogging() method declared below. We use a +// more-specific name so we can #define it above without affecting other code +// that has named stuff "InitLogging". +BASE_EXPORT bool BaseInitLoggingImpl(const LoggingSettings& settings); + +// Sets the log file name and other global logging state. Calling this function +// is recommended, and is normally done at the beginning of application init. +// If you don't call it, all the flags will be initialized to their default +// values, and there is a race condition that may leak a critical section +// object if two threads try to do the first log at the same time. +// See the definition of the enums above for descriptions and default values. +// +// The default log file is initialized to "debug.log" in the application +// directory. You probably don't want this, especially since the program +// directory may not be writable on an enduser's system. +// +// This function may be called a second time to re-direct logging (e.g after +// loging in to a user partition), however it should never be called more than +// twice. +inline bool InitLogging(const LoggingSettings& settings) { + return BaseInitLoggingImpl(settings); +} + +// Sets the log level. Anything at or above this level will be written to the +// log file/displayed to the user (if applicable). Anything below this level +// will be silently ignored. The log level defaults to 0 (everything is logged +// up to level INFO) if this function is not called. +// Note that log messages for VLOG(x) are logged at level -x, so setting +// the min log level to negative values enables verbose logging. +BASE_EXPORT void SetMinLogLevel(int level); + +// Gets the current log level. +BASE_EXPORT int GetMinLogLevel(); + +// Gets the VLOG default verbosity level. +BASE_EXPORT int GetVlogVerbosity(); + +// Gets the current vlog level for the given file (usually taken from +// __FILE__). + +// Note that |N| is the size *with* the null terminator. +inline int GetVlogLevelHelper(const char* file_start, size_t N) { + return GetVlogVerbosity(); +} + +template <size_t N> +int GetVlogLevel(const char (&file)[N]) { + return GetVlogLevelHelper(file, N); +} + +// Sets the common items you want to be prepended to each log message. +// process and thread IDs default to off, the timestamp defaults to on. +// If this function is not called, logging defaults to writing the timestamp +// only. +BASE_EXPORT void SetLogItems(bool enable_process_id, + bool enable_thread_id, + bool enable_timestamp, + bool enable_tickcount); + +// Sets whether or not you'd like to see fatal debug messages popped up in +// a dialog box or not. +// Dialogs are not shown by default. +void SetShowErrorDialogs(bool enable_dialogs); + +// Sets the Log Assert Handler that will be used to notify of check failures. +// The default handler shows a dialog box and then terminate the process, +// however clients can use this function to override with their own handling +// (e.g. a silent one for Unit Tests) +typedef void (*LogAssertHandlerFunction)(const std::string& str); +BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler); + +// Sets the Log Message Handler that gets passed every log message before +// it's sent to other log destinations (if any). +// Returns true to signal that it handled the message and the message +// should not be sent to other log destinations. +typedef bool (*LogMessageHandlerFunction)(int severity, + const char* file, int line, size_t message_start, const std::string& str); +BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler); +BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler(); + +typedef int LogSeverity; +const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity +// Note: the log severities are used to index into the array of names, +// see log_severity_names. +const LogSeverity LOG_INFO = 0; +const LogSeverity LOG_WARNING = 1; +const LogSeverity LOG_ERROR = 2; +const LogSeverity LOG_FATAL = 3; +const LogSeverity LOG_NUM_SEVERITIES = 4; + +// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode +#ifdef NDEBUG +const LogSeverity LOG_DFATAL = LOG_ERROR; +#else +const LogSeverity LOG_DFATAL = LOG_FATAL; +#endif + +// A few definitions of macros that don't generate much code. These are used +// by LOG() and LOG_IF, etc. Since these are used all over our code, it's +// better to have compact code for these operations. +#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \ + logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__) + +#define COMPACT_GOOGLE_LOG_INFO \ + COMPACT_GOOGLE_LOG_EX_INFO(LogMessage) +#define COMPACT_GOOGLE_LOG_WARNING \ + COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage) +#define COMPACT_GOOGLE_LOG_ERROR \ + COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage) +#define COMPACT_GOOGLE_LOG_FATAL \ + COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage) +#define COMPACT_GOOGLE_LOG_DFATAL \ + COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage) + +// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also, +// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will +// always fire if they fail. +#define LOG_IS_ON(severity) \ + ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel()) + +// We can't do any caching tricks with VLOG_IS_ON() like the +// google-glog version since it requires GCC extensions. This means +// that using the v-logging functions in conjunction with --vmodule +// may be slow. +#define VLOG_IS_ON(verboselevel) \ + ((verboselevel) <= ::logging::GetVlogLevel(__FILE__)) + +// Helper macro which avoids evaluating the arguments to a stream if +// the condition doesn't hold. Condition is evaluated once and only once. +#define LAZY_STREAM(stream, condition) \ + !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream) + +// We use the preprocessor's merging operator, "##", so that, e.g., +// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny +// subtle difference between ostream member streaming functions (e.g., +// ostream::operator<<(int) and ostream non-member streaming functions +// (e.g., ::operator<<(ostream&, string&): it turns out that it's +// impossible to stream something like a string directly to an unnamed +// ostream. We employ a neat hack by calling the stream() member +// function of LogMessage which seems to avoid the problem. +#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() + +#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity)) +#define LOG_IF(severity, condition) \ + LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition)) + +#define SYSLOG(severity) LOG(severity) +#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition) + +// The VLOG macros log with negative verbosities. +#define VLOG_STREAM(verbose_level) \ + logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream() + +#define VLOG(verbose_level) \ + LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level)) + +#define VLOG_IF(verbose_level, condition) \ + LAZY_STREAM(VLOG_STREAM(verbose_level), \ + VLOG_IS_ON(verbose_level) && (condition)) + +#define LOG_ASSERT(condition) \ + LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " +#define SYSLOG_ASSERT(condition) \ + SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". " + +// The actual stream used isn't important. +#define EAT_STREAM_PARAMETERS \ + true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL) + +// CHECK dies with a fatal error if condition is not true. It is *not* +// controlled by NDEBUG, so the check will be executed regardless of +// compilation mode. +// +// We make sure CHECK et al. always evaluates their arguments, as +// doing CHECK(FunctionWithSideEffect()) is a common idiom. + +#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID) + +// Make all CHECK functions discard their log strings to reduce code +// bloat for official release builds. + +// TODO(akalin): This would be more valuable if there were some way to +// remove BreakDebugger() from the backtrace, perhaps by turning it +// into a macro (like __debugbreak() on Windows). +#define CHECK(condition) \ + !(condition) ? ::base::debug::BreakDebugger() : EAT_STREAM_PARAMETERS + +#define PCHECK(condition) CHECK(condition) + +#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2)) + +#else + +#define CHECK(condition) \ + LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \ + << "Check failed: " #condition ". " + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use CHECK_EQ et al below. +// +// TODO(akalin): Rewrite this so that constructs like if (...) +// CHECK_EQ(...) else { ... } work properly. +#define CHECK_OP(name, op, val1, val2) \ + if (std::string* _result = \ + logging::Check##name##Impl((val1), (val2), \ + #val1 " " #op " " #val2)) \ + logging::LogMessage(__FILE__, __LINE__, _result).stream() + +#endif + +// Build the error message string. This is separate from the "Impl" +// function template because it is not performance critical and so can +// be out of line, while the "Impl" code should be inline. Caller +// takes ownership of the returned string. +template<class t1, class t2> +std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) { + std::ostringstream ss; + ss << names << " (" << v1 << " vs. " << v2 << ")"; + std::string* msg = new std::string(ss.str()); + return msg; +} + +// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated +// in logging.cc. +extern template BASE_EXPORT std::string* +MakeCheckOpString<int, int>(const int&, const int&, const char* names); +extern template BASE_EXPORT +std::string* MakeCheckOpString<unsigned long, unsigned long>( + const unsigned long&, const unsigned long&, const char* names); +extern template BASE_EXPORT +std::string* MakeCheckOpString<unsigned long, unsigned int>( + const unsigned long&, const unsigned int&, const char* names); +extern template BASE_EXPORT +std::string* MakeCheckOpString<unsigned int, unsigned long>( + const unsigned int&, const unsigned long&, const char* names); +extern template BASE_EXPORT +std::string* MakeCheckOpString<std::string, std::string>( + const std::string&, const std::string&, const char* name); + +// Helper functions for CHECK_OP macro. +// The (int, int) specialization works around the issue that the compiler +// will not instantiate the template version of the function on values of +// unnamed enum type - see comment below. +#define DEFINE_CHECK_OP_IMPL(name, op) \ + template <class t1, class t2> \ + inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ + const char* names) { \ + if (v1 op v2) return NULL; \ + else return MakeCheckOpString(v1, v2, names); \ + } \ + inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ + if (v1 op v2) return NULL; \ + else return MakeCheckOpString(v1, v2, names); \ + } +DEFINE_CHECK_OP_IMPL(EQ, ==) +DEFINE_CHECK_OP_IMPL(NE, !=) +DEFINE_CHECK_OP_IMPL(LE, <=) +DEFINE_CHECK_OP_IMPL(LT, < ) +DEFINE_CHECK_OP_IMPL(GE, >=) +DEFINE_CHECK_OP_IMPL(GT, > ) +#undef DEFINE_CHECK_OP_IMPL + +#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2) +#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2) +#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2) +#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2) +#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2) +#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2) +#define CHECK_IMPLIES(val1, val2) CHECK(!(val1) || (val2)) + +#if defined(NDEBUG) +#define ENABLE_DLOG 0 +#else +#define ENABLE_DLOG 1 +#endif + +#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) +#define DCHECK_IS_ON() 0 +#else +#define DCHECK_IS_ON() 1 +#endif + +// Definitions for DLOG et al. + +#if ENABLE_DLOG + +#define DLOG_IS_ON(severity) LOG_IS_ON(severity) +#define DLOG_IF(severity, condition) LOG_IF(severity, condition) +#define DLOG_ASSERT(condition) LOG_ASSERT(condition) +#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition) + +#else // ENABLE_DLOG + +// If ENABLE_DLOG is off, we want to avoid emitting any references to +// |condition| (which may reference a variable defined only if NDEBUG +// is not defined). Contrast this with DCHECK et al., which has +// different behavior. + +#define DLOG_IS_ON(severity) false +#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS +#define DLOG_ASSERT(condition) EAT_STREAM_PARAMETERS +#define DVLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS + +#endif // ENABLE_DLOG + +// DEBUG_MODE is for uses like +// if (DEBUG_MODE) foo.CheckThatFoo(); +// instead of +// #ifndef NDEBUG +// foo.CheckThatFoo(); +// #endif +// +// We tie its state to ENABLE_DLOG. +enum { DEBUG_MODE = ENABLE_DLOG }; + +#undef ENABLE_DLOG + +#define DLOG(severity) \ + LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity)) + +#define DVLOG(verboselevel) DVLOG_IF(verboselevel, VLOG_IS_ON(verboselevel)) + +// Definitions for DCHECK et al. + +#if DCHECK_IS_ON() + +#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ + COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL +const LogSeverity LOG_DCHECK = LOG_FATAL; + +#else // DCHECK_IS_ON() + +// These are just dummy values. +#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \ + COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO +const LogSeverity LOG_DCHECK = LOG_INFO; + +#endif // DCHECK_IS_ON() + +// DCHECK et al. make sure to reference |condition| regardless of +// whether DCHECKs are enabled; this is so that we don't get unused +// variable warnings if the only use of a variable is in a DCHECK. +// This behavior is different from DLOG_IF et al. + +#define DCHECK(condition) \ + LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \ + << "Check failed: " #condition ". " + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use DCHECK_EQ et al below. +#define DCHECK_OP(name, op, val1, val2) \ + if (DCHECK_IS_ON()) \ + if (std::string* _result = logging::Check##name##Impl( \ + (val1), (val2), #val1 " " #op " " #val2)) \ + logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, _result) \ + .stream() + +// Equality/Inequality checks - compare two values, and log a +// LOG_DCHECK message including the two values when the result is not +// as expected. The values must have operator<<(ostream, ...) +// defined. +// +// You may append to the error message like so: +// DCHECK_NE(1, 2) << ": The world must be ending!"; +// +// We are very careful to ensure that each argument is evaluated exactly +// once, and that anything which is legal to pass as a function argument is +// legal here. In particular, the arguments may be temporary expressions +// which will end up being destroyed at the end of the apparent statement, +// for example: +// DCHECK_EQ(string("abc")[1], 'b'); +// +// WARNING: These may not compile correctly if one of the arguments is a pointer +// and the other is NULL. To work around this, simply static_cast NULL to the +// type of the desired pointer. + +#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2) +#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2) +#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2) +#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2) +#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2) +#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2) +#define DCHECK_IMPLIES(val1, val2) DCHECK(!(val1) || (val2)) + +#define NOTREACHED() DCHECK(false) + +// Redefine the standard assert to use our nice log files +#undef assert +#define assert(x) DLOG_ASSERT(x) + +// This class more or less represents a particular log message. You +// create an instance of LogMessage and then stream stuff to it. +// When you finish streaming to it, ~LogMessage is called and the +// full message gets streamed to the appropriate destination. +// +// You shouldn't actually use LogMessage's constructor to log things, +// though. You should use the LOG() macro (and variants thereof) +// above. +class BASE_EXPORT LogMessage { + public: + // Used for LOG(severity). + LogMessage(const char* file, int line, LogSeverity severity); + + // Used for CHECK_EQ(), etc. Takes ownership of the given string. + // Implied severity = LOG_FATAL. + LogMessage(const char* file, int line, std::string* result); + + // Used for DCHECK_EQ(), etc. Takes ownership of the given string. + LogMessage(const char* file, int line, LogSeverity severity, + std::string* result); + + ~LogMessage(); + + std::ostream& stream() { return stream_; } + + private: + void Init(const char* file, int line); + + LogSeverity severity_; + std::ostringstream stream_; + size_t message_start_; // Offset of the start of the message (past prefix + // info). + // The file and line information passed in to the constructor. + const char* file_; + const int line_; + + DISALLOW_COPY_AND_ASSIGN(LogMessage); +}; + +// A non-macro interface to the log facility; (useful +// when the logging level is not a compile-time constant). +inline void LogAtLevel(int const log_level, std::string const &msg) { + LogMessage(__FILE__, __LINE__, log_level).stream() << msg; +} + +// This class is used to explicitly ignore values in the conditional +// logging macros. This avoids compiler warnings like "value computed +// is not used" and "statement has no effect". +class LogMessageVoidify { + public: + LogMessageVoidify() { } + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) { } +}; + +// Async signal safe logging mechanism. +BASE_EXPORT void RawLog(int level, const char* message); + +#define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message) + +#define RAW_CHECK(condition) \ + do { \ + if (!(condition)) \ + logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n"); \ + } while (0) + + +} // namespace logging + +// The NOTIMPLEMENTED() macro annotates codepaths which have +// not been implemented yet. +// +// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY: +// 0 -- Do nothing (stripped by compiler) +// 1 -- Warn at compile time +// 2 -- Fail at compile time +// 3 -- Fail at runtime (DCHECK) +// 4 -- [default] LOG(ERROR) at runtime +// 5 -- LOG(ERROR) at runtime, only once per call-site + +#ifndef NOTIMPLEMENTED_POLICY +// Select default policy: LOG(ERROR) +#define NOTIMPLEMENTED_POLICY 4 +#endif + +#if defined(COMPILER_GCC) +// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name +// of the current function in the NOTIMPLEMENTED message. +#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__ +#else +#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED" +#endif + +#if NOTIMPLEMENTED_POLICY == 0 +#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS +#elif NOTIMPLEMENTED_POLICY == 1 +// TODO, figure out how to generate a warning +#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED) +#elif NOTIMPLEMENTED_POLICY == 2 +#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED) +#elif NOTIMPLEMENTED_POLICY == 3 +#define NOTIMPLEMENTED() NOTREACHED() +#elif NOTIMPLEMENTED_POLICY == 4 +#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG +#elif NOTIMPLEMENTED_POLICY == 5 +#define NOTIMPLEMENTED() do {\ + static bool logged_once = false;\ + LOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG;\ + logged_once = true;\ +} while(0);\ +EAT_STREAM_PARAMETERS +#endif + +#endif // BASE_LOGGING_H_ diff --git a/third_party/chromium/base/logging_unittest.cc b/third_party/chromium/base/logging_unittest.cc new file mode 100644 index 0000000..e3c84e3 --- /dev/null +++ b/third_party/chromium/base/logging_unittest.cc @@ -0,0 +1,218 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/logging.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" + +namespace logging { + +namespace { + +using ::testing::Return; + +// Needs to be global since log assert handlers can't maintain state. +int log_sink_call_count = 0; + +#if !defined(OFFICIAL_BUILD) || defined(DCHECK_ALWAYS_ON) || !defined(NDEBUG) +void LogSink(const std::string& str) { + ++log_sink_call_count; +} +#endif + +// Class to make sure any manipulations we do to the min log level are +// contained (i.e., do not affect other unit tests). +class LogStateSaver { + public: + LogStateSaver() : old_min_log_level_(GetMinLogLevel()) {} + + ~LogStateSaver() { + SetMinLogLevel(old_min_log_level_); + SetLogAssertHandler(NULL); + log_sink_call_count = 0; + } + + private: + int old_min_log_level_; + + DISALLOW_COPY_AND_ASSIGN(LogStateSaver); +}; + +class LoggingTest : public testing::Test { + private: + LogStateSaver log_state_saver_; +}; + +class MockLogSource { + public: + MOCK_METHOD0(Log, const char*()); +}; + +TEST_F(LoggingTest, BasicLogging) { + MockLogSource mock_log_source; + EXPECT_CALL(mock_log_source, Log()). + WillRepeatedly(Return("log message")); + + SetMinLogLevel(LOG_INFO); + + EXPECT_TRUE(LOG_IS_ON(INFO)); + // As of g++-4.5, the first argument to EXPECT_EQ cannot be a + // constant expression. + const bool kIsDebugMode = (DEBUG_MODE != 0); + EXPECT_TRUE(kIsDebugMode == DLOG_IS_ON(INFO)); + EXPECT_TRUE(VLOG_IS_ON(0)); + + LOG(INFO) << mock_log_source.Log(); + LOG_IF(INFO, true) << mock_log_source.Log(); + VLOG(0) << mock_log_source.Log(); + VLOG_IF(0, true) << mock_log_source.Log(); + + DLOG(INFO) << mock_log_source.Log(); + DLOG_IF(INFO, true) << mock_log_source.Log(); + DVLOG(0) << mock_log_source.Log(); + DVLOG_IF(0, true) << mock_log_source.Log(); +} + +TEST_F(LoggingTest, LogIsOn) { +#if defined(NDEBUG) + const bool kDfatalIsFatal = false; +#else // defined(NDEBUG) + const bool kDfatalIsFatal = true; +#endif // defined(NDEBUG) + + SetMinLogLevel(LOG_INFO); + EXPECT_TRUE(LOG_IS_ON(INFO)); + EXPECT_TRUE(LOG_IS_ON(WARNING)); + EXPECT_TRUE(LOG_IS_ON(ERROR)); + EXPECT_TRUE(LOG_IS_ON(FATAL)); + EXPECT_TRUE(LOG_IS_ON(DFATAL)); + + SetMinLogLevel(LOG_WARNING); + EXPECT_FALSE(LOG_IS_ON(INFO)); + EXPECT_TRUE(LOG_IS_ON(WARNING)); + EXPECT_TRUE(LOG_IS_ON(ERROR)); + EXPECT_TRUE(LOG_IS_ON(FATAL)); + EXPECT_TRUE(LOG_IS_ON(DFATAL)); + + SetMinLogLevel(LOG_ERROR); + EXPECT_FALSE(LOG_IS_ON(INFO)); + EXPECT_FALSE(LOG_IS_ON(WARNING)); + EXPECT_TRUE(LOG_IS_ON(ERROR)); + EXPECT_TRUE(LOG_IS_ON(FATAL)); + EXPECT_TRUE(LOG_IS_ON(DFATAL)); + + // LOG_IS_ON(FATAL) should always be true. + SetMinLogLevel(LOG_FATAL + 1); + EXPECT_FALSE(LOG_IS_ON(INFO)); + EXPECT_FALSE(LOG_IS_ON(WARNING)); + EXPECT_FALSE(LOG_IS_ON(ERROR)); + EXPECT_TRUE(LOG_IS_ON(FATAL)); + EXPECT_TRUE(kDfatalIsFatal == LOG_IS_ON(DFATAL)); +} + +TEST_F(LoggingTest, LoggingIsLazy) { + MockLogSource mock_log_source; + EXPECT_CALL(mock_log_source, Log()).Times(0); + + SetMinLogLevel(LOG_WARNING); + + EXPECT_FALSE(LOG_IS_ON(INFO)); + EXPECT_FALSE(DLOG_IS_ON(INFO)); + EXPECT_FALSE(VLOG_IS_ON(1)); + + LOG(INFO) << mock_log_source.Log(); + LOG_IF(INFO, false) << mock_log_source.Log(); + VLOG(1) << mock_log_source.Log(); + VLOG_IF(1, true) << mock_log_source.Log(); + + DLOG(INFO) << mock_log_source.Log(); + DLOG_IF(INFO, true) << mock_log_source.Log(); + DVLOG(1) << mock_log_source.Log(); + DVLOG_IF(1, true) << mock_log_source.Log(); +} + +// Official builds have CHECKs directly call BreakDebugger. +#if !defined(OFFICIAL_BUILD) + +TEST_F(LoggingTest, CheckStreamsAreLazy) { + MockLogSource mock_log_source, uncalled_mock_log_source; + EXPECT_CALL(mock_log_source, Log()). + WillRepeatedly(Return("check message")); + EXPECT_CALL(uncalled_mock_log_source, Log()).Times(0); + + SetLogAssertHandler(&LogSink); + + CHECK(mock_log_source.Log()) << uncalled_mock_log_source.Log(); + CHECK_EQ(mock_log_source.Log(), mock_log_source.Log()) + << uncalled_mock_log_source.Log(); + CHECK_NE(mock_log_source.Log(), mock_log_source.Log()) + << mock_log_source.Log(); +} + +#endif + +TEST_F(LoggingTest, DebugLoggingReleaseBehavior) { +#if !defined(NDEBUG) + int debug_only_variable = 1; +#endif + // These should avoid emitting references to |debug_only_variable| + // in release mode. + DLOG_IF(INFO, debug_only_variable) << "test"; + DLOG_ASSERT(debug_only_variable) << "test"; + DVLOG_IF(1, debug_only_variable) << "test"; +} + +TEST_F(LoggingTest, DcheckStreamsAreLazy) { + MockLogSource mock_log_source; + EXPECT_CALL(mock_log_source, Log()).Times(0); +#if DCHECK_IS_ON() + DCHECK(true) << mock_log_source.Log(); + DCHECK_EQ(0, 0) << mock_log_source.Log(); +#else + DCHECK(mock_log_source.Log()) << mock_log_source.Log(); + DCHECK_EQ(0, 0) << mock_log_source.Log(); + DCHECK_EQ(mock_log_source.Log(), static_cast<const char*>(NULL)) + << mock_log_source.Log(); +#endif +} + +TEST_F(LoggingTest, Dcheck) { +#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) + // Release build. + EXPECT_FALSE(DCHECK_IS_ON()); + EXPECT_FALSE(DLOG_IS_ON(DCHECK)); +#elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON) + // Release build with real DCHECKS. + SetLogAssertHandler(&LogSink); + EXPECT_TRUE(DCHECK_IS_ON()); + EXPECT_FALSE(DLOG_IS_ON(DCHECK)); +#else + // Debug build. + SetLogAssertHandler(&LogSink); + EXPECT_TRUE(DCHECK_IS_ON()); + EXPECT_TRUE(DLOG_IS_ON(DCHECK)); +#endif + + EXPECT_EQ(0, log_sink_call_count); + DCHECK(false); + EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count); + DCHECK_EQ(0, 1); + EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count); +} + +TEST_F(LoggingTest, DcheckReleaseBehavior) { + int some_variable = 1; + // These should still reference |some_variable| so we don't get + // unused variable warnings. + DCHECK(some_variable) << "test"; + DCHECK_EQ(some_variable, 1) << "test"; +} + +} // namespace + +} // namespace logging diff --git a/third_party/chromium/base/macros.h b/third_party/chromium/base/macros.h new file mode 100644 index 0000000..0325e74 --- /dev/null +++ b/third_party/chromium/base/macros.h @@ -0,0 +1,198 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains macros and macro-like constructs (e.g., templates) that +// are commonly used throughout Chromium source. (It may also contain things +// that are closely related to things that are commonly used that belong in this +// file.) + +#ifndef BASE_MACROS_H_ +#define BASE_MACROS_H_ + +#include <stddef.h> // For size_t. +#include <string.h> // For memcpy. + +// Put this in the declarations for a class to be uncopyable. +#define DISALLOW_COPY(TypeName) \ + TypeName(const TypeName&) = delete + +// Put this in the declarations for a class to be unassignable. +#define DISALLOW_ASSIGN(TypeName) \ + void operator=(const TypeName&) = delete + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +// An older, deprecated, politically incorrect name for the above. +// NOTE: The usage of this macro was banned from our code base, but some +// third_party libraries are yet using it. +// TODO(tfarina): Figure out how to fix the usage of this macro in the +// third_party libraries and get rid of it. +#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName) + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// +// This should be used in the private: declarations for a class +// that wants to prevent anyone from instantiating it. This is +// especially useful for classes containing only static methods. +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + DISALLOW_COPY_AND_ASSIGN(TypeName) + +// The arraysize(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. If you use arraysize on +// a pointer by mistake, you will get a compile-time error. + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N]; +#define arraysize(array) (sizeof(ArraySizeHelper(array))) + + +// Use implicit_cast as a safe version of static_cast or const_cast +// for upcasting in the type hierarchy (i.e. casting a pointer to Foo +// to a pointer to SuperclassOfFoo or casting a pointer to Foo to +// a const pointer to Foo). +// When you use implicit_cast, the compiler checks that the cast is safe. +// Such explicit implicit_casts are necessary in surprisingly many +// situations where C++ demands an exact type match instead of an +// argument type convertible to a target type. +// +// The From type can be inferred, so the preferred syntax for using +// implicit_cast is the same as for static_cast etc.: +// +// implicit_cast<ToType>(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template<typename To, typename From> +inline To implicit_cast(From const &f) { + return f; +} + +// The COMPILE_ASSERT macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// COMPILE_ASSERT(arraysize(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +#undef COMPILE_ASSERT +#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg) + +// bit_cast<Dest,Source> is a template function that implements the +// equivalent of "*reinterpret_cast<Dest*>(&source)". We need this in +// very low-level functions like the protobuf library and fast math +// support. +// +// float f = 3.14159265358979; +// int i = bit_cast<int32>(f); +// // i = 0x40490fdb +// +// The classical address-casting method is: +// +// // WRONG +// float f = 3.14159265358979; // WRONG +// int i = * reinterpret_cast<int*>(&f); // WRONG +// +// The address-casting method actually produces undefined behavior +// according to ISO C++ specification section 3.10 -15 -. Roughly, this +// section says: if an object in memory has one type, and a program +// accesses it with a different type, then the result is undefined +// behavior for most values of "different type". +// +// This is true for any cast syntax, either *(int*)&f or +// *reinterpret_cast<int*>(&f). And it is particularly true for +// conversions between integral lvalues and floating-point lvalues. +// +// The purpose of 3.10 -15- is to allow optimizing compilers to assume +// that expressions with different types refer to different memory. gcc +// 4.0.1 has an optimizer that takes advantage of this. So a +// non-conforming program quietly produces wildly incorrect output. +// +// The problem is not the use of reinterpret_cast. The problem is type +// punning: holding an object in memory of one type and reading its bits +// back using a different type. +// +// The C++ standard is more subtle and complex than this, but that +// is the basic idea. +// +// Anyways ... +// +// bit_cast<> calls memcpy() which is blessed by the standard, +// especially by the example in section 3.9 . Also, of course, +// bit_cast<> wraps up the nasty logic in one place. +// +// Fortunately memcpy() is very fast. In optimized mode, with a +// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline +// code with the minimal amount of data movement. On a 32-bit system, +// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8) +// compiles to two loads and two stores. +// +// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1. +// +// WARNING: if Dest or Source is a non-POD type, the result of the memcpy +// is likely to surprise you. + +template <class Dest, class Source> +inline Dest bit_cast(const Source& source) { + COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), VerifySizesAreEqual); + + Dest dest; + memcpy(&dest, &source, sizeof(dest)); + return dest; +} + +// Used to explicitly mark the return value of a function as unused. If you are +// really sure you don't want to do anything with the return value of a function +// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example: +// +// scoped_ptr<MyType> my_var = ...; +// if (TakeOwnership(my_var.get()) == SUCCESS) +// ignore_result(my_var.release()); +// +template<typename T> +inline void ignore_result(const T&) { +} + +// The following enum should be used only as a constructor argument to indicate +// that the variable has static storage class, and that the constructor should +// do nothing to its state. It indicates to the reader that it is legal to +// declare a static instance of the class, provided the constructor is given +// the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declare a +// static variable that has a constructor or a destructor because invocation +// order is undefined. However, IF the type can be initialized by filling with +// zeroes (which the loader does for static variables), AND the destructor also +// does nothing to the storage, AND there are no virtual methods, then a +// constructor declared as +// explicit MyClass(base::LinkerInitialized x) {} +// and invoked as +// static MyClass my_variable_name(base::LINKER_INITIALIZED); +namespace base { +enum LinkerInitialized { LINKER_INITIALIZED }; + +// Use these to declare and define a static local variable (static T;) so that +// it is leaked so that its destructors are not called at exit. If you need +// thread-safe initialization, use base/lazy_instance.h instead. +#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \ + static type& name = *new type arguments + +} // base + +#endif // BASE_MACROS_H_ diff --git a/third_party/chromium/base/memory/ref_counted.cc b/third_party/chromium/base/memory/ref_counted.cc new file mode 100644 index 0000000..42e777c --- /dev/null +++ b/third_party/chromium/base/memory/ref_counted.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/ref_counted.h" + +namespace base { + +namespace subtle { + +bool RefCountedThreadSafeBase::HasOneRef() const { + return ref_count_ == 1; +} + +RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) { +#ifndef NDEBUG + in_dtor_ = false; +#endif +} + +RefCountedThreadSafeBase::~RefCountedThreadSafeBase() { +#ifndef NDEBUG + DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without " + "calling Release()"; +#endif +} + +void RefCountedThreadSafeBase::AddRef() const { +#ifndef NDEBUG + DCHECK(!in_dtor_); +#endif + ++ref_count_; +} + +bool RefCountedThreadSafeBase::Release() const { +#ifndef NDEBUG + DCHECK(!in_dtor_); + DCHECK(ref_count_ != 0); +#endif + if (--ref_count_ == 0) { +#ifndef NDEBUG + in_dtor_ = true; +#endif + return true; + } + return false; +} + +} // namespace subtle + +} // namespace base diff --git a/third_party/chromium/base/memory/ref_counted.h b/third_party/chromium/base/memory/ref_counted.h new file mode 100644 index 0000000..23b9038 --- /dev/null +++ b/third_party/chromium/base/memory/ref_counted.h @@ -0,0 +1,427 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_MEMORY_REF_COUNTED_H_ +#define BASE_MEMORY_REF_COUNTED_H_ + +#include <atomic> +#include <cassert> +#include <iosfwd> + +#include "base/base_export.h" +#include "base/build/build_config.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/move.h" + +namespace base { + +namespace subtle { + +class BASE_EXPORT RefCountedBase { + public: + bool HasOneRef() const { return ref_count_ == 1; } + + protected: + RefCountedBase() + : ref_count_(0) + #ifndef NDEBUG + , in_dtor_(false) + #endif + { + } + + ~RefCountedBase() { + #ifndef NDEBUG + DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; + #endif + } + + + void AddRef() const { + #ifndef NDEBUG + DCHECK(!in_dtor_); + #endif + ++ref_count_; + } + + // Returns true if the object should self-delete. + bool Release() const { + #ifndef NDEBUG + DCHECK(!in_dtor_); + #endif + if (--ref_count_ == 0) { + #ifndef NDEBUG + in_dtor_ = true; + #endif + return true; + } + return false; + } + + private: + mutable int ref_count_; +#ifndef NDEBUG + mutable bool in_dtor_; +#endif + + DISALLOW_COPY_AND_ASSIGN(RefCountedBase); +}; + +class BASE_EXPORT RefCountedThreadSafeBase { + public: + bool HasOneRef() const; + + protected: + RefCountedThreadSafeBase(); + ~RefCountedThreadSafeBase(); + + void AddRef() const; + + // Returns true if the object should self-delete. + bool Release() const; + + private: + mutable std::atomic<int32_t> ref_count_; +#ifndef NDEBUG + mutable bool in_dtor_; +#endif + + DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); +}; + +} // namespace subtle + +// +// A base class for reference counted classes. Otherwise, known as a cheap +// knock-off of WebKit's RefCounted<T> class. To use this guy just extend your +// class from it like so: +// +// class MyFoo : public base::RefCounted<MyFoo> { +// ... +// private: +// friend class base::RefCounted<MyFoo>; +// ~MyFoo(); +// }; +// +// You should always make your destructor private, to avoid any code deleting +// the object accidently while there are references to it. +template <class T> +class RefCounted : public subtle::RefCountedBase { + public: + RefCounted() {} + + void AddRef() const { + subtle::RefCountedBase::AddRef(); + } + + void Release() const { + if (subtle::RefCountedBase::Release()) { + delete static_cast<const T*>(this); + } + } + + protected: + ~RefCounted() {} + + private: + DISALLOW_COPY_AND_ASSIGN(RefCounted<T>); +}; + +// Forward declaration. +template <class T, typename Traits> class RefCountedThreadSafe; + +// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref +// count reaches 0. Overload to delete it on a different thread etc. +template<typename T> +struct DefaultRefCountedThreadSafeTraits { + static void Destruct(const T* x) { + // Delete through RefCountedThreadSafe to make child classes only need to be + // friend with RefCountedThreadSafe instead of this struct, which is an + // implementation detail. + RefCountedThreadSafe<T, + DefaultRefCountedThreadSafeTraits>::DeleteInternal(x); + } +}; + +// +// A thread-safe variant of RefCounted<T> +// +// class MyFoo : public base::RefCountedThreadSafe<MyFoo> { +// ... +// }; +// +// If you're using the default trait, then you should add compile time +// asserts that no one else is deleting your object. i.e. +// private: +// friend class base::RefCountedThreadSafe<MyFoo>; +// ~MyFoo(); +template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > +class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { + public: + RefCountedThreadSafe() {} + + void AddRef() const { + subtle::RefCountedThreadSafeBase::AddRef(); + } + + void Release() const { + if (subtle::RefCountedThreadSafeBase::Release()) { + Traits::Destruct(static_cast<const T*>(this)); + } + } + + protected: + ~RefCountedThreadSafe() {} + + private: + friend struct DefaultRefCountedThreadSafeTraits<T>; + static void DeleteInternal(const T* x) { delete x; } + + DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe); +}; + +// +// A thread-safe wrapper for some piece of data so we can place other +// things in scoped_refptrs<>. +// +template<typename T> +class RefCountedData + : public base::RefCountedThreadSafe< base::RefCountedData<T> > { + public: + RefCountedData() : data() {} + RefCountedData(const T& in_value) : data(in_value) {} + + T data; + + private: + friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; + ~RefCountedData() {} +}; + +} // namespace base + +// +// A smart pointer class for reference counted objects. Use this class instead +// of calling AddRef and Release manually on a reference counted object to +// avoid common memory leaks caused by forgetting to Release an object +// reference. Sample usage: +// +// class MyFoo : public RefCounted<MyFoo> { +// ... +// }; +// +// void some_function() { +// scoped_refptr<MyFoo> foo = new MyFoo(); +// foo->Method(param); +// // |foo| is released when this function returns +// } +// +// void some_other_function() { +// scoped_refptr<MyFoo> foo = new MyFoo(); +// ... +// foo = NULL; // explicitly releases |foo| +// ... +// if (foo) +// foo->Method(param); +// } +// +// The above examples show how scoped_refptr<T> acts like a pointer to T. +// Given two scoped_refptr<T> classes, it is also possible to exchange +// references between the two objects, like so: +// +// { +// scoped_refptr<MyFoo> a = new MyFoo(); +// scoped_refptr<MyFoo> b; +// +// b.swap(a); +// // now, |b| references the MyFoo object, and |a| references NULL. +// } +// +// To make both |a| and |b| in the above example reference the same MyFoo +// object, simply use the assignment operator: +// +// { +// scoped_refptr<MyFoo> a = new MyFoo(); +// scoped_refptr<MyFoo> b; +// +// b = a; +// // now, |a| and |b| each own a reference to the same MyFoo object. +// } +// +template <class T> +class scoped_refptr { + TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_refptr) + public: + typedef T element_type; + + scoped_refptr() : ptr_(NULL) { + } + + scoped_refptr(T* p) : ptr_(p) { + if (ptr_) + AddRef(ptr_); + } + + scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { + if (ptr_) + AddRef(ptr_); + } + + template <typename U> + scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { + if (ptr_) + AddRef(ptr_); + } + + template <typename U> + scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) { + r.ptr_ = nullptr; + } + + ~scoped_refptr() { + if (ptr_) + Release(ptr_); + } + + T* get() const { return ptr_; } + + T& operator*() const { + assert(ptr_ != NULL); + return *ptr_; + } + + T* operator->() const { + assert(ptr_ != NULL); + return ptr_; + } + + scoped_refptr<T>& operator=(T* p) { + // AddRef first so that self assignment should work + if (p) + AddRef(p); + T* old_ptr = ptr_; + ptr_ = p; + if (old_ptr) + Release(old_ptr); + return *this; + } + + scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { + return *this = r.ptr_; + } + + template <typename U> + scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { + return *this = r.get(); + } + + scoped_refptr<T>& operator=(scoped_refptr<T>&& r) { + scoped_refptr<T>(r.Pass()).swap(*this); + return *this; + } + + template <typename U> + scoped_refptr<T>& operator=(scoped_refptr<U>&& r) { + scoped_refptr<T>(r.Pass()).swap(*this); + return *this; + } + + void swap(T** pp) { + T* p = ptr_; + ptr_ = *pp; + *pp = p; + } + + void swap(scoped_refptr<T>& r) { + swap(&r.ptr_); + } + + private: + template <typename U> friend class scoped_refptr; + + // Allow scoped_refptr<T> to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + // + // Note that this trick is only safe when the == and != operators + // are declared explicitly, as otherwise "refptr1 == refptr2" + // will compile but do the wrong thing (i.e., convert to Testable + // and then do the comparison). + typedef T* scoped_refptr::*Testable; + + public: + operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : nullptr; } + + template <typename U> + bool operator==(const scoped_refptr<U>& rhs) const { + return ptr_ == rhs.get(); + } + + template <typename U> + bool operator!=(const scoped_refptr<U>& rhs) const { + return !operator==(rhs); + } + + template <typename U> + bool operator<(const scoped_refptr<U>& rhs) const { + return ptr_ < rhs.get(); + } + + protected: + T* ptr_; + + private: + // Non-inline helpers to allow: + // class Opaque; + // extern template class scoped_refptr<Opaque>; + // Otherwise the compiler will complain that Opaque is an incomplete type. + static void AddRef(T* ptr); + static void Release(T* ptr); +}; + +template <typename T> +void scoped_refptr<T>::AddRef(T* ptr) { + ptr->AddRef(); +} + +template <typename T> +void scoped_refptr<T>::Release(T* ptr) { + ptr->Release(); +} + +// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without +// having to retype all the template arguments +template <typename T> +scoped_refptr<T> make_scoped_refptr(T* t) { + return scoped_refptr<T>(t); +} + +// Temporary operator overloads to facilitate the transition. See +// https://crbug.com/110610. +template <typename T, typename U> +bool operator==(const scoped_refptr<T>& lhs, const U* rhs) { + return lhs.get() == rhs; +} + +template <typename T, typename U> +bool operator==(const T* lhs, const scoped_refptr<U>& rhs) { + return lhs == rhs.get(); +} + +template <typename T, typename U> +bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) { + return !operator==(lhs, rhs); +} + +template <typename T, typename U> +bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) { + return !operator==(lhs, rhs); +} + +template <typename T> +std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { + return out << p.get(); +} + +#endif // BASE_MEMORY_REF_COUNTED_H_ diff --git a/third_party/chromium/base/memory/ref_counted_unittest.cc b/third_party/chromium/base/memory/ref_counted_unittest.cc new file mode 100644 index 0000000..9eda813 --- /dev/null +++ b/third_party/chromium/base/memory/ref_counted_unittest.cc @@ -0,0 +1,451 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/ref_counted.h" + +#include <gtest/gtest.h> + +namespace { + +class SelfAssign : public base::RefCounted<SelfAssign> { + protected: + virtual ~SelfAssign() {} + + private: + friend class base::RefCounted<SelfAssign>; +}; + +class Derived : public SelfAssign { + protected: + ~Derived() override {} + + private: + friend class base::RefCounted<Derived>; +}; + +class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> { + public: + CheckDerivedMemberAccess() { + // This shouldn't compile if we don't have access to the member variable. + SelfAssign** pptr = &ptr_; + EXPECT_EQ(*pptr, ptr_); + } +}; + +class ScopedRefPtrToSelf : public base::RefCounted<ScopedRefPtrToSelf> { + public: + ScopedRefPtrToSelf() : self_ptr_(this) {} + + static bool was_destroyed() { return was_destroyed_; } + + static void reset_was_destroyed() { was_destroyed_ = false; } + + scoped_refptr<ScopedRefPtrToSelf> self_ptr_; + + private: + friend class base::RefCounted<ScopedRefPtrToSelf>; + ~ScopedRefPtrToSelf() { was_destroyed_ = true; } + + static bool was_destroyed_; +}; + +bool ScopedRefPtrToSelf::was_destroyed_ = false; + +class ScopedRefPtrCountBase : public base::RefCounted<ScopedRefPtrCountBase> { + public: + ScopedRefPtrCountBase() { ++constructor_count_; } + + static int constructor_count() { return constructor_count_; } + + static int destructor_count() { return destructor_count_; } + + static void reset_count() { + constructor_count_ = 0; + destructor_count_ = 0; + } + + protected: + virtual ~ScopedRefPtrCountBase() { ++destructor_count_; } + + private: + friend class base::RefCounted<ScopedRefPtrCountBase>; + + static int constructor_count_; + static int destructor_count_; +}; + +int ScopedRefPtrCountBase::constructor_count_ = 0; +int ScopedRefPtrCountBase::destructor_count_ = 0; + +class ScopedRefPtrCountDerived : public ScopedRefPtrCountBase { + public: + ScopedRefPtrCountDerived() { ++constructor_count_; } + + static int constructor_count() { return constructor_count_; } + + static int destructor_count() { return destructor_count_; } + + static void reset_count() { + constructor_count_ = 0; + destructor_count_ = 0; + } + + protected: + ~ScopedRefPtrCountDerived() override { ++destructor_count_; } + + private: + friend class base::RefCounted<ScopedRefPtrCountDerived>; + + static int constructor_count_; + static int destructor_count_; +}; + +int ScopedRefPtrCountDerived::constructor_count_ = 0; +int ScopedRefPtrCountDerived::destructor_count_ = 0; + +} // end namespace + +TEST(RefCountedUnitTest, TestSelfAssignment) { + SelfAssign* p = new SelfAssign; + scoped_refptr<SelfAssign> var(p); + var = var; + EXPECT_EQ(var.get(), p); +} + +TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) { + CheckDerivedMemberAccess check; +} + +TEST(RefCountedUnitTest, ScopedRefPtrToSelfPointerAssignment) { + ScopedRefPtrToSelf::reset_was_destroyed(); + + ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf(); + EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed()); + check->self_ptr_ = nullptr; + EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed()); +} + +TEST(RefCountedUnitTest, ScopedRefPtrToSelfMoveAssignment) { + ScopedRefPtrToSelf::reset_was_destroyed(); + + ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf(); + EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed()); + // Releasing |check->self_ptr_| will delete |check|. + // The move assignment operator must assign |check->self_ptr_| first then + // release |check->self_ptr_|. + check->self_ptr_ = scoped_refptr<ScopedRefPtrToSelf>(); + EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed()); +} + +TEST(RefCountedUnitTest, BooleanTesting) { + scoped_refptr<SelfAssign> p; + EXPECT_FALSE(p); + p = new SelfAssign; + EXPECT_TRUE(p); +} + +TEST(RefCountedUnitTest, Equality) { + scoped_refptr<SelfAssign> p1(new SelfAssign); + scoped_refptr<SelfAssign> p2(new SelfAssign); + + EXPECT_EQ(p1, p1); + EXPECT_EQ(p2, p2); + + EXPECT_NE(p1, p2); + EXPECT_NE(p2, p1); +} + +TEST(RefCountedUnitTest, ConvertibleEquality) { + scoped_refptr<Derived> p1(new Derived); + scoped_refptr<SelfAssign> p2; + + EXPECT_NE(p1, p2); + EXPECT_NE(p2, p1); + + p2 = p1; + + EXPECT_EQ(p1, p2); + EXPECT_EQ(p2, p1); +} + +TEST(RefCountedUnitTest, SelfMoveAssignment) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p = p.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(raw, p.get()); + + // p goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignment1) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2; + + p2 = p1.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(nullptr, p1.get()); + EXPECT_EQ(raw, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignment2) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1; + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p1 = p2.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(raw, p1.get()); + EXPECT_EQ(nullptr, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(p1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p1 = p2.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(raw, p1.get()); + EXPECT_EQ(nullptr, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(p1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p2 = p1.Pass(); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(nullptr, p1.get()); + EXPECT_EQ(raw, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + ScopedRefPtrCountBase *raw2 = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p2(raw2); + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + p1 = p2.Pass(); + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(raw2, p1.get()); + EXPECT_EQ(nullptr, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveAssignmentDerived) { + ScopedRefPtrCountBase::reset_count(); + ScopedRefPtrCountDerived::reset_count(); + + { + ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + + { + ScopedRefPtrCountDerived *raw2 = new ScopedRefPtrCountDerived(); + scoped_refptr<ScopedRefPtrCountDerived> p2(raw2); + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + + p1 = p2.Pass(); + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + EXPECT_EQ(raw2, p1.get()); + EXPECT_EQ(nullptr, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveConstructor) { + ScopedRefPtrCountBase::reset_count(); + + { + ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase(); + scoped_refptr<ScopedRefPtrCountBase> p1(raw); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass()); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(nullptr, p1.get()); + EXPECT_EQ(raw, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); +} + +TEST(RefCountedUnitTest, MoveConstructorDerived) { + ScopedRefPtrCountBase::reset_count(); + ScopedRefPtrCountDerived::reset_count(); + + { + ScopedRefPtrCountDerived *raw1 = new ScopedRefPtrCountDerived(); + scoped_refptr<ScopedRefPtrCountDerived> p1(raw1); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + + { + scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass()); + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count()); + EXPECT_EQ(nullptr, p1.get()); + EXPECT_EQ(raw1, p2.get()); + + // p2 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count()); + + // p1 goes out of scope. + } + EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count()); + EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count()); +} + diff --git a/third_party/chromium/base/memory/scoped_ptr.h b/third_party/chromium/base/memory/scoped_ptr.h new file mode 100644 index 0000000..2aa1b32 --- /dev/null +++ b/third_party/chromium/base/memory/scoped_ptr.h @@ -0,0 +1,594 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Scopers help you manage ownership of a pointer, helping you easily manage a +// pointer within a scope, and automatically destroying the pointer at the end +// of a scope. There are two main classes you will use, which correspond to the +// operators new/delete and new[]/delete[]. +// +// Example usage (scoped_ptr<T>): +// { +// scoped_ptr<Foo> foo(new Foo("wee")); +// } // foo goes out of scope, releasing the pointer with it. +// +// { +// scoped_ptr<Foo> foo; // No pointer managed. +// foo.reset(new Foo("wee")); // Now a pointer is managed. +// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed. +// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed. +// foo->Method(); // Foo::Method() called. +// foo.get()->Method(); // Foo::Method() called. +// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer +// // manages a pointer. +// foo.reset(new Foo("wee4")); // foo manages a pointer again. +// foo.reset(); // Foo("wee4") destroyed, foo no longer +// // manages a pointer. +// } // foo wasn't managing a pointer, so nothing was destroyed. +// +// Example usage (scoped_ptr<T[]>): +// { +// scoped_ptr<Foo[]> foo(new Foo[100]); +// foo.get()->Method(); // Foo::Method on the 0th element. +// foo[10].Method(); // Foo::Method on the 10th element. +// } +// +// These scopers also implement part of the functionality of C++11 unique_ptr +// in that they are "movable but not copyable." You can use the scopers in +// the parameter and return types of functions to signify ownership transfer +// in to and out of a function. When calling a function that has a scoper +// as the argument type, it must be called with the result of an analogous +// scoper's Pass() function or another function that generates a temporary; +// passing by copy will NOT work. Here is an example using scoped_ptr: +// +// void TakesOwnership(scoped_ptr<Foo> arg) { +// // Do something with arg +// } +// scoped_ptr<Foo> CreateFoo() { +// // No need for calling Pass() because we are constructing a temporary +// // for the return value. +// return scoped_ptr<Foo>(new Foo("new")); +// } +// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) { +// return arg.Pass(); +// } +// +// { +// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay"). +// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay"). +// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo. +// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2. +// PassThru(ptr2.Pass()); // ptr2 is correspondingly nullptr. +// } +// +// Notice that if you do not call Pass() when returning from PassThru(), or +// when invoking TakesOwnership(), the code will not compile because scopers +// are not copyable; they only implement move semantics which require calling +// the Pass() function to signify a destructive transfer of state. CreateFoo() +// is different though because we are constructing a temporary on the return +// line and thus can avoid needing to call Pass(). +// +// Pass() properly handles upcast in initialization, i.e. you can use a +// scoped_ptr<Child> to initialize a scoped_ptr<Parent>: +// +// scoped_ptr<Foo> foo(new Foo()); +// scoped_ptr<FooParent> parent(foo.Pass()); + +#ifndef BASE_MEMORY_SCOPED_PTR_H_ +#define BASE_MEMORY_SCOPED_PTR_H_ + +// This is an implementation designed to match the anticipated future TR2 +// implementation of the scoped_ptr class. + +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> + +#include <algorithm> // For std::swap(). +#include <iosfwd> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/move.h" +#include "base/template_util.h" + +namespace base { + +namespace subtle { +class RefCountedBase; +class RefCountedThreadSafeBase; +} // namespace subtle + +// Function object which deletes its parameter, which must be a pointer. +// If C is an array type, invokes 'delete[]' on the parameter; otherwise, +// invokes 'delete'. The default deleter for scoped_ptr<T>. +template <class T> +struct DefaultDeleter { + DefaultDeleter() {} + template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) { + // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor + // if U* is implicitly convertible to T* and U is not an array type. + // + // Correct implementation should use SFINAE to disable this + // constructor. However, since there are no other 1-argument constructors, + // using a COMPILE_ASSERT() based on is_convertible<> and requiring + // complete types is simpler and will cause compile failures for equivalent + // misuses. + // + // Note, the is_convertible<U*, T*> check also ensures that U is not an + // array. T is guaranteed to be a non-array, so any U* where U is an array + // cannot convert to T*. + enum { T_must_be_complete = sizeof(T) }; + enum { U_must_be_complete = sizeof(U) }; + COMPILE_ASSERT((std::is_convertible<U*, T*>::value), + U_ptr_must_implicitly_convert_to_T_ptr); + } + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete ptr; + } +}; + +// Specialization of DefaultDeleter for array types. +template <class T> +struct DefaultDeleter<T[]> { + inline void operator()(T* ptr) const { + enum { type_must_be_complete = sizeof(T) }; + delete[] ptr; + } + + private: + // Disable this operator for any U != T because it is undefined to execute + // an array delete when the static type of the array mismatches the dynamic + // type. + // + // References: + // C++98 [expr.delete]p3 + // http://cplusplus.github.com/LWG/lwg-defects.html#938 + template <typename U> void operator()(U* array) const; +}; + +template <class T, int n> +struct DefaultDeleter<T[n]> { + // Never allow someone to declare something like scoped_ptr<int[10]>. + COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type); +}; + +// Function object which invokes 'free' on its parameter, which must be +// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr: +// +// scoped_ptr<int, base::FreeDeleter> foo_ptr( +// static_cast<int*>(malloc(sizeof(int)))); +struct FreeDeleter { + inline void operator()(void* ptr) const { + free(ptr); + } +}; + +namespace internal { + +template <typename T> struct IsNotRefCounted { + enum { + value = !std::is_convertible<T*, base::subtle::RefCountedBase*>::value && + !std::is_convertible<T*, base::subtle::RefCountedThreadSafeBase*>:: + value + }; +}; + +template <typename T> +struct ShouldAbortOnSelfReset { + template <typename U> + static NoType Test(const typename U::AllowSelfReset*); + + template <typename U> + static YesType Test(...); + + static const bool value = sizeof(Test<T>(0)) == sizeof(YesType); +}; + +// Minimal implementation of the core logic of scoped_ptr, suitable for +// reuse in both scoped_ptr and its specializations. +template <class T, class D> +class scoped_ptr_impl { + public: + explicit scoped_ptr_impl(T* p) : data_(p) {} + + // Initializer for deleters that have data parameters. + scoped_ptr_impl(T* p, const D& d) : data_(p, d) {} + + // Templated constructor that destructively takes the value from another + // scoped_ptr_impl. + template <typename U, typename V> + scoped_ptr_impl(scoped_ptr_impl<U, V>* other) + : data_(other->release(), other->get_deleter()) { + // We do not support move-only deleters. We could modify our move + // emulation to have base::subtle::move() and base::subtle::forward() + // functions that are imperfect emulations of their C++11 equivalents, + // but until there's a requirement, just assume deleters are copyable. + } + + template <typename U, typename V> + void TakeState(scoped_ptr_impl<U, V>* other) { + // See comment in templated constructor above regarding lack of support + // for move-only deleters. + reset(other->release()); + get_deleter() = other->get_deleter(); + } + + ~scoped_ptr_impl() { + if (data_.ptr != nullptr) { + // Not using get_deleter() saves one function call in non-optimized + // builds. + static_cast<D&>(data_)(data_.ptr); + } + } + + void reset(T* p) { + // This is a self-reset, which is no longer allowed for default deleters: + // https://crbug.com/162971 + assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr); + + // Note that running data_.ptr = p can lead to undefined behavior if + // get_deleter()(get()) deletes this. In order to prevent this, reset() + // should update the stored pointer before deleting its old value. + // + // However, changing reset() to use that behavior may cause current code to + // break in unexpected ways. If the destruction of the owned object + // dereferences the scoped_ptr when it is destroyed by a call to reset(), + // then it will incorrectly dispatch calls to |p| rather than the original + // value of |data_.ptr|. + // + // During the transition period, set the stored pointer to nullptr while + // deleting the object. Eventually, this safety check will be removed to + // prevent the scenario initially described from occuring and + // http://crbug.com/176091 can be closed. + T* old = data_.ptr; + data_.ptr = nullptr; + if (old != nullptr) + static_cast<D&>(data_)(old); + data_.ptr = p; + } + + T* get() const { return data_.ptr; } + + D& get_deleter() { return data_; } + const D& get_deleter() const { return data_; } + + void swap(scoped_ptr_impl& p2) { + // Standard swap idiom: 'using std::swap' ensures that std::swap is + // present in the overload set, but we call swap unqualified so that + // any more-specific overloads can be used, if available. + using std::swap; + swap(static_cast<D&>(data_), static_cast<D&>(p2.data_)); + swap(data_.ptr, p2.data_.ptr); + } + + T* release() { + T* old_ptr = data_.ptr; + data_.ptr = nullptr; + return old_ptr; + } + + private: + // Needed to allow type-converting constructor. + template <typename U, typename V> friend class scoped_ptr_impl; + + // Use the empty base class optimization to allow us to have a D + // member, while avoiding any space overhead for it when D is an + // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good + // discussion of this technique. + struct Data : public D { + explicit Data(T* ptr_in) : ptr(ptr_in) {} + Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {} + T* ptr; + }; + + Data data_; + + DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl); +}; + +} // namespace internal + +} // namespace base + +// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T> +// automatically deletes the pointer it holds (if any). +// That is, scoped_ptr<T> owns the T object that it points to. +// Like a T*, a scoped_ptr<T> may hold either nullptr or a pointer to a T +// object. Also like T*, scoped_ptr<T> is thread-compatible, and once you +// dereference it, you get the thread safety guarantees of T. +// +// The size of scoped_ptr is small. On most compilers, when using the +// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will +// increase the size proportional to whatever state they need to have. See +// comments inside scoped_ptr_impl<> for details. +// +// Current implementation targets having a strict subset of C++11's +// unique_ptr<> features. Known deficiencies include not supporting move-only +// deleteres, function pointers as deleters, and deleters with reference +// types. +template <class T, class D = base::DefaultDeleter<T> > +class scoped_ptr { + MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr) + + COMPILE_ASSERT(base::internal::IsNotRefCounted<T>::value, + T_is_refcounted_type_and_needs_scoped_refptr); + + public: + // The element and deleter types. + typedef T element_type; + typedef D deleter_type; + + // Constructor. Defaults to initializing with nullptr. + scoped_ptr() : impl_(nullptr) {} + + // Constructor. Takes ownership of p. + explicit scoped_ptr(element_type* p) : impl_(p) {} + + // Constructor. Allows initialization of a stateful deleter. + scoped_ptr(element_type* p, const D& d) : impl_(p, d) {} + + // Constructor. Allows construction from a nullptr. + scoped_ptr(decltype(nullptr)) : impl_(nullptr) {} + + // Constructor. Allows construction from a scoped_ptr rvalue for a + // convertible type and deleter. + // + // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct + // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor + // has different post-conditions if D is a reference type. Since this + // implementation does not support deleters with reference type, + // we do not need a separate move constructor allowing us to avoid one + // use of SFINAE. You only need to care about this if you modify the + // implementation of scoped_ptr. + template <typename U, typename V> + scoped_ptr(scoped_ptr<U, V>&& other) + : impl_(&other.impl_) { + COMPILE_ASSERT(!std::is_array<U>::value, U_cannot_be_an_array); + } + + // operator=. Allows assignment from a scoped_ptr rvalue for a convertible + // type and deleter. + // + // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from + // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated + // form has different requirements on for move-only Deleters. Since this + // implementation does not support move-only Deleters, we do not need a + // separate move assignment operator allowing us to avoid one use of SFINAE. + // You only need to care about this if you modify the implementation of + // scoped_ptr. + template <typename U, typename V> + scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) { + COMPILE_ASSERT(!std::is_array<U>::value, U_cannot_be_an_array); + impl_.TakeState(&rhs.impl_); + return *this; + } + + // operator=. Allows assignment from a nullptr. Deletes the currently owned + // object, if any. + scoped_ptr& operator=(decltype(nullptr)) { + reset(); + return *this; + } + + // Reset. Deletes the currently owned object, if any. + // Then takes ownership of a new object, if given. + void reset(element_type* p = nullptr) { impl_.reset(p); } + + // Accessors to get the owned object. + // operator* and operator-> will assert() if there is no current object. + element_type& operator*() const { + assert(impl_.get() != nullptr); + return *impl_.get(); + } + element_type* operator->() const { + assert(impl_.get() != nullptr); + return impl_.get(); + } + element_type* get() const { return impl_.get(); } + + // Access to the deleter. + deleter_type& get_deleter() { return impl_.get_deleter(); } + const deleter_type& get_deleter() const { return impl_.get_deleter(); } + + // Allow scoped_ptr<element_type> to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + // + // Note that this trick is only safe when the == and != operators + // are declared explicitly, as otherwise "scoped_ptr1 == + // scoped_ptr2" will compile but do the wrong thing (i.e., convert + // to Testable and then do the comparison). + private: + typedef base::internal::scoped_ptr_impl<element_type, deleter_type> + scoped_ptr::*Testable; + + public: + operator Testable() const { + return impl_.get() ? &scoped_ptr::impl_ : nullptr; + } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(const element_type* p) const { return impl_.get() == p; } + bool operator!=(const element_type* p) const { return impl_.get() != p; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + impl_.swap(p2.impl_); + } + + // Release a pointer. + // The return value is the current pointer held by this object. If this object + // holds a nullptr, the return value is nullptr. After this operation, this + // object will hold a nullptr, and will not own the object any more. + element_type* release() WARN_UNUSED_RESULT { + return impl_.release(); + } + + private: + // Needed to reach into |impl_| in the constructor. + template <typename U, typename V> friend class scoped_ptr; + base::internal::scoped_ptr_impl<element_type, deleter_type> impl_; + + // Forbidden for API compatibility with std::unique_ptr. + explicit scoped_ptr(int disallow_construction_from_null); + + // Forbid comparison of scoped_ptr types. If U != T, it totally + // doesn't make sense, and if U == T, it still doesn't make sense + // because you should never have the same object owned by two different + // scoped_ptrs. + template <class U> bool operator==(scoped_ptr<U> const& p2) const; + template <class U> bool operator!=(scoped_ptr<U> const& p2) const; +}; + +template <class T, class D> +class scoped_ptr<T[], D> { + MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr) + + public: + // The element and deleter types. + typedef T element_type; + typedef D deleter_type; + + // Constructor. Defaults to initializing with nullptr. + scoped_ptr() : impl_(nullptr) {} + + // Constructor. Stores the given array. Note that the argument's type + // must exactly match T*. In particular: + // - it cannot be a pointer to a type derived from T, because it is + // inherently unsafe in the general case to access an array through a + // pointer whose dynamic type does not match its static type (eg., if + // T and the derived types had different sizes access would be + // incorrectly calculated). Deletion is also always undefined + // (C++98 [expr.delete]p3). If you're doing this, fix your code. + // - it cannot be const-qualified differently from T per unique_ptr spec + // (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting + // to work around this may use implicit_cast<const T*>(). + // However, because of the first bullet in this comment, users MUST + // NOT use implicit_cast<Base*>() to upcast the static type of the array. + explicit scoped_ptr(element_type* array) : impl_(array) {} + + // Constructor. Allows construction from a nullptr. + scoped_ptr(decltype(nullptr)) : impl_(nullptr) {} + + // Constructor. Allows construction from a scoped_ptr rvalue. + scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {} + + // operator=. Allows assignment from a scoped_ptr rvalue. + scoped_ptr& operator=(scoped_ptr&& rhs) { + impl_.TakeState(&rhs.impl_); + return *this; + } + + // operator=. Allows assignment from a nullptr. Deletes the currently owned + // array, if any. + scoped_ptr& operator=(decltype(nullptr)) { + reset(); + return *this; + } + + // Reset. Deletes the currently owned array, if any. + // Then takes ownership of a new object, if given. + void reset(element_type* array = nullptr) { impl_.reset(array); } + + // Accessors to get the owned array. + element_type& operator[](size_t i) const { + assert(impl_.get() != nullptr); + return impl_.get()[i]; + } + element_type* get() const { return impl_.get(); } + + // Access to the deleter. + deleter_type& get_deleter() { return impl_.get_deleter(); } + const deleter_type& get_deleter() const { return impl_.get_deleter(); } + + // Allow scoped_ptr<element_type> to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + private: + typedef base::internal::scoped_ptr_impl<element_type, deleter_type> + scoped_ptr::*Testable; + + public: + operator Testable() const { + return impl_.get() ? &scoped_ptr::impl_ : nullptr; + } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(element_type* array) const { return impl_.get() == array; } + bool operator!=(element_type* array) const { return impl_.get() != array; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + impl_.swap(p2.impl_); + } + + // Release a pointer. + // The return value is the current pointer held by this object. If this object + // holds a nullptr, the return value is nullptr. After this operation, this + // object will hold a nullptr, and will not own the object any more. + element_type* release() WARN_UNUSED_RESULT { + return impl_.release(); + } + + private: + // Force element_type to be a complete type. + enum { type_must_be_complete = sizeof(element_type) }; + + // Actually hold the data. + base::internal::scoped_ptr_impl<element_type, deleter_type> impl_; + + // Disable initialization from any type other than element_type*, by + // providing a constructor that matches such an initialization, but is + // private and has no definition. This is disabled because it is not safe to + // call delete[] on an array whose static type does not match its dynamic + // type. + template <typename U> explicit scoped_ptr(U* array); + explicit scoped_ptr(int disallow_construction_from_null); + + // Disable reset() from any type other than element_type*, for the same + // reasons as the constructor above. + template <typename U> void reset(U* array); + void reset(int disallow_reset_from_null); + + // Forbid comparison of scoped_ptr types. If U != T, it totally + // doesn't make sense, and if U == T, it still doesn't make sense + // because you should never have the same object owned by two different + // scoped_ptrs. + template <class U> bool operator==(scoped_ptr<U> const& p2) const; + template <class U> bool operator!=(scoped_ptr<U> const& p2) const; +}; + +// Free functions +template <class T, class D> +void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) { + p1.swap(p2); +} + +template <class T, class D> +bool operator==(T* p1, const scoped_ptr<T, D>& p2) { + return p1 == p2.get(); +} + +template <class T, class D> +bool operator!=(T* p1, const scoped_ptr<T, D>& p2) { + return p1 != p2.get(); +} + +// A function to convert T* into scoped_ptr<T> +// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation +// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg)) +template <typename T> +scoped_ptr<T> make_scoped_ptr(T* ptr) { + return scoped_ptr<T>(ptr); +} + +template <typename T> +std::ostream& operator<<(std::ostream& out, const scoped_ptr<T>& p) { + return out << p.get(); +} + +#endif // BASE_MEMORY_SCOPED_PTR_H_ diff --git a/third_party/chromium/base/memory/scoped_ptr_unittest.cc b/third_party/chromium/base/memory/scoped_ptr_unittest.cc new file mode 100644 index 0000000..d4ff410 --- /dev/null +++ b/third_party/chromium/base/memory/scoped_ptr_unittest.cc @@ -0,0 +1,696 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/scoped_ptr.h" + +#include <sstream> + +#include <gtest/gtest.h> + +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/callback.h" + +namespace { + +// Used to test depth subtyping. +class ConDecLoggerParent { + public: + virtual ~ConDecLoggerParent() {} + + virtual void SetPtr(int* ptr) = 0; + + virtual int SomeMeth(int x) const = 0; +}; + +class ConDecLogger : public ConDecLoggerParent { + public: + ConDecLogger() : ptr_(NULL) { } + explicit ConDecLogger(int* ptr) { SetPtr(ptr); } + ~ConDecLogger() override { --*ptr_; } + + void SetPtr(int* ptr) override { + ptr_ = ptr; + ++*ptr_; + } + + int SomeMeth(int x) const override { return x; } + + private: + int* ptr_; + + DISALLOW_COPY_AND_ASSIGN(ConDecLogger); +}; + +struct CountingDeleter { + explicit CountingDeleter(int* count) : count_(count) {} + inline void operator()(double* ptr) const { + (*count_)++; + } + int* count_; +}; + +// Used to test assignment of convertible deleters. +struct CountingDeleterChild : public CountingDeleter { + explicit CountingDeleterChild(int* count) : CountingDeleter(count) {} +}; + +class OverloadedNewAndDelete { + public: + void* operator new(size_t size) { + g_new_count++; + return malloc(size); + } + + void operator delete(void* ptr) { + g_delete_count++; + free(ptr); + } + + static void ResetCounters() { + g_new_count = 0; + g_delete_count = 0; + } + + static int new_count() { return g_new_count; } + static int delete_count() { return g_delete_count; } + + private: + static int g_new_count; + static int g_delete_count; +}; + +int OverloadedNewAndDelete::g_new_count = 0; +int OverloadedNewAndDelete::g_delete_count = 0; + +scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) { + return logger.Pass(); +} + +void GrabAndDrop(scoped_ptr<ConDecLogger> logger) { +} + +// Do not delete this function! It's existence is to test that you can +// return a temporarily constructed version of the scoper. +scoped_ptr<ConDecLogger> TestReturnOfType(int* constructed) { + return scoped_ptr<ConDecLogger>(new ConDecLogger(constructed)); +} + +} // namespace + +TEST(ScopedPtrTest, ScopedPtr) { + int constructed = 0; + + // Ensure size of scoped_ptr<> doesn't increase unexpectedly. + COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr<int>), + scoped_ptr_larger_than_raw_ptr); + + { + scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper.get()); + + EXPECT_EQ(10, scoper->SomeMeth(10)); + EXPECT_EQ(10, scoper.get()->SomeMeth(10)); + EXPECT_EQ(10, (*scoper).SomeMeth(10)); + } + EXPECT_EQ(0, constructed); + + // Test reset() and release() + { + scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper.get()); + + scoper.reset(new ConDecLogger(&constructed)); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper.get()); + + scoper.reset(); + EXPECT_EQ(0, constructed); + EXPECT_FALSE(scoper.get()); + + scoper.reset(new ConDecLogger(&constructed)); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper.get()); + + ConDecLogger* take = scoper.release(); + EXPECT_EQ(1, constructed); + EXPECT_FALSE(scoper.get()); + delete take; + EXPECT_EQ(0, constructed); + + scoper.reset(new ConDecLogger(&constructed)); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper.get()); + } + EXPECT_EQ(0, constructed); + + // Test swap(), == and != + { + scoped_ptr<ConDecLogger> scoper1; + scoped_ptr<ConDecLogger> scoper2; + EXPECT_TRUE(scoper1 == scoper2.get()); + EXPECT_FALSE(scoper1 != scoper2.get()); + + ConDecLogger* logger = new ConDecLogger(&constructed); + scoper1.reset(logger); + EXPECT_EQ(logger, scoper1.get()); + EXPECT_FALSE(scoper2.get()); + EXPECT_FALSE(scoper1 == scoper2.get()); + EXPECT_TRUE(scoper1 != scoper2.get()); + + scoper2.swap(scoper1); + EXPECT_EQ(logger, scoper2.get()); + EXPECT_FALSE(scoper1.get()); + EXPECT_FALSE(scoper1 == scoper2.get()); + EXPECT_TRUE(scoper1 != scoper2.get()); + } + EXPECT_EQ(0, constructed); +} + +TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) { + int constructed = 0; + + // Test construction from a scoped_ptr to a derived class. + { + scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper.get()); + + scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass()); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper_parent.get()); + EXPECT_FALSE(scoper.get()); + + EXPECT_EQ(10, scoper_parent->SomeMeth(10)); + EXPECT_EQ(10, scoper_parent.get()->SomeMeth(10)); + EXPECT_EQ(10, (*scoper_parent).SomeMeth(10)); + } + EXPECT_EQ(0, constructed); + + // Test assignment from a scoped_ptr to a derived class. + { + scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper.get()); + + scoped_ptr<ConDecLoggerParent> scoper_parent; + scoper_parent = scoper.Pass(); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper_parent.get()); + EXPECT_FALSE(scoper.get()); + } + EXPECT_EQ(0, constructed); + + // Test construction of a scoped_ptr with an additional const annotation. + { + scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper.get()); + + scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass()); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper_const.get()); + EXPECT_FALSE(scoper.get()); + + EXPECT_EQ(10, scoper_const->SomeMeth(10)); + EXPECT_EQ(10, scoper_const.get()->SomeMeth(10)); + EXPECT_EQ(10, (*scoper_const).SomeMeth(10)); + } + EXPECT_EQ(0, constructed); + + // Test assignment to a scoped_ptr with an additional const annotation. + { + scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper.get()); + + scoped_ptr<const ConDecLogger> scoper_const; + scoper_const = scoper.Pass(); + EXPECT_EQ(1, constructed); + EXPECT_TRUE(scoper_const.get()); + EXPECT_FALSE(scoper.get()); + } + EXPECT_EQ(0, constructed); + + // Test assignment to a scoped_ptr deleter of parent type. + { + // Custom deleters never touch these value. + double dummy_value, dummy_value2; + int deletes = 0; + int alternate_deletes = 0; + scoped_ptr<double, CountingDeleter> scoper(&dummy_value, + CountingDeleter(&deletes)); + scoped_ptr<double, CountingDeleterChild> scoper_child( + &dummy_value2, CountingDeleterChild(&alternate_deletes)); + + EXPECT_TRUE(scoper); + EXPECT_TRUE(scoper_child); + EXPECT_EQ(0, deletes); + EXPECT_EQ(0, alternate_deletes); + + // Test this compiles and correctly overwrites the deleter state. + scoper = scoper_child.Pass(); + EXPECT_TRUE(scoper); + EXPECT_FALSE(scoper_child); + EXPECT_EQ(1, deletes); + EXPECT_EQ(0, alternate_deletes); + + scoper.reset(); + EXPECT_FALSE(scoper); + EXPECT_FALSE(scoper_child); + EXPECT_EQ(1, deletes); + EXPECT_EQ(1, alternate_deletes); + + scoper_child.reset(&dummy_value); + EXPECT_TRUE(scoper_child); + EXPECT_EQ(1, deletes); + EXPECT_EQ(1, alternate_deletes); + scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass()); + EXPECT_TRUE(scoper_construct); + EXPECT_FALSE(scoper_child); + EXPECT_EQ(1, deletes); + EXPECT_EQ(1, alternate_deletes); + + scoper_construct.reset(); + EXPECT_EQ(1, deletes); + EXPECT_EQ(2, alternate_deletes); + } +} + +TEST(ScopedPtrTest, ScopedPtrWithArray) { + static const int kNumLoggers = 12; + + int constructed = 0; + + { + scoped_ptr<ConDecLogger[]> scoper(new ConDecLogger[kNumLoggers]); + EXPECT_TRUE(scoper); + EXPECT_EQ(&scoper[0], scoper.get()); + for (int i = 0; i < kNumLoggers; ++i) { + scoper[i].SetPtr(&constructed); + } + EXPECT_EQ(12, constructed); + + EXPECT_EQ(10, scoper.get()->SomeMeth(10)); + EXPECT_EQ(10, scoper[2].SomeMeth(10)); + } + EXPECT_EQ(0, constructed); + + // Test reset() and release() + { + scoped_ptr<ConDecLogger[]> scoper; + EXPECT_FALSE(scoper.get()); + EXPECT_FALSE(scoper.release()); + EXPECT_FALSE(scoper.get()); + scoper.reset(); + EXPECT_FALSE(scoper.get()); + + scoper.reset(new ConDecLogger[kNumLoggers]); + for (int i = 0; i < kNumLoggers; ++i) { + scoper[i].SetPtr(&constructed); + } + EXPECT_EQ(12, constructed); + scoper.reset(); + EXPECT_EQ(0, constructed); + + scoper.reset(new ConDecLogger[kNumLoggers]); + for (int i = 0; i < kNumLoggers; ++i) { + scoper[i].SetPtr(&constructed); + } + EXPECT_EQ(12, constructed); + ConDecLogger* ptr = scoper.release(); + EXPECT_EQ(12, constructed); + delete[] ptr; + EXPECT_EQ(0, constructed); + } + EXPECT_EQ(0, constructed); + + // Test swap(), ==, !=, and type-safe Boolean. + { + scoped_ptr<ConDecLogger[]> scoper1; + scoped_ptr<ConDecLogger[]> scoper2; + EXPECT_TRUE(scoper1 == scoper2.get()); + EXPECT_FALSE(scoper1 != scoper2.get()); + + ConDecLogger* loggers = new ConDecLogger[kNumLoggers]; + for (int i = 0; i < kNumLoggers; ++i) { + loggers[i].SetPtr(&constructed); + } + scoper1.reset(loggers); + EXPECT_TRUE(scoper1); + EXPECT_EQ(loggers, scoper1.get()); + EXPECT_FALSE(scoper2); + EXPECT_FALSE(scoper2.get()); + EXPECT_FALSE(scoper1 == scoper2.get()); + EXPECT_TRUE(scoper1 != scoper2.get()); + + scoper2.swap(scoper1); + EXPECT_EQ(loggers, scoper2.get()); + EXPECT_FALSE(scoper1.get()); + EXPECT_FALSE(scoper1 == scoper2.get()); + EXPECT_TRUE(scoper1 != scoper2.get()); + } + EXPECT_EQ(0, constructed); + + { + ConDecLogger* loggers = new ConDecLogger[kNumLoggers]; + scoped_ptr<ConDecLogger[]> scoper(loggers); + EXPECT_TRUE(scoper); + for (int i = 0; i < kNumLoggers; ++i) { + scoper[i].SetPtr(&constructed); + } + EXPECT_EQ(kNumLoggers, constructed); + + // Test Pass() with constructor; + scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass()); + EXPECT_EQ(kNumLoggers, constructed); + + // Test Pass() with assignment; + scoped_ptr<ConDecLogger[]> scoper3; + scoper3 = scoper2.Pass(); + EXPECT_EQ(kNumLoggers, constructed); + EXPECT_FALSE(scoper); + EXPECT_FALSE(scoper2); + EXPECT_TRUE(scoper3); + } + EXPECT_EQ(0, constructed); +} + +TEST(ScopedPtrTest, PassBehavior) { + int constructed = 0; + { + ConDecLogger* logger = new ConDecLogger(&constructed); + scoped_ptr<ConDecLogger> scoper(logger); + EXPECT_EQ(1, constructed); + + // Test Pass() with constructor; + scoped_ptr<ConDecLogger> scoper2(scoper.Pass()); + EXPECT_EQ(1, constructed); + + // Test Pass() with assignment; + scoped_ptr<ConDecLogger> scoper3; + scoper3 = scoper2.Pass(); + EXPECT_EQ(1, constructed); + EXPECT_FALSE(scoper.get()); + EXPECT_FALSE(scoper2.get()); + EXPECT_TRUE(scoper3.get()); + } + + // Test uncaught Pass() does not have side effects. + { + ConDecLogger* logger = new ConDecLogger(&constructed); + scoped_ptr<ConDecLogger> scoper(logger); + EXPECT_EQ(1, constructed); + + // Should auto-destruct logger by end of scope. + scoped_ptr<ConDecLogger>&& rvalue = scoper.Pass(); + // The Pass() function mimics std::move(), which does not have side-effects. + EXPECT_TRUE(scoper.get()); + EXPECT_TRUE(rvalue); + } + EXPECT_EQ(0, constructed); + + // Test that passing to function which does nothing does not leak. + { + ConDecLogger* logger = new ConDecLogger(&constructed); + scoped_ptr<ConDecLogger> scoper(logger); + EXPECT_EQ(1, constructed); + + // Should auto-destruct logger by end of scope. + GrabAndDrop(scoper.Pass()); + EXPECT_FALSE(scoper.get()); + } + EXPECT_EQ(0, constructed); +} + +TEST(ScopedPtrTest, ReturnTypeBehavior) { + int constructed = 0; + + // Test that we can return a scoped_ptr. + { + ConDecLogger* logger = new ConDecLogger(&constructed); + scoped_ptr<ConDecLogger> scoper(logger); + EXPECT_EQ(1, constructed); + + PassThru(scoper.Pass()); + EXPECT_FALSE(scoper.get()); + } + EXPECT_EQ(0, constructed); + + // Test uncaught return type not leak. + { + ConDecLogger* logger = new ConDecLogger(&constructed); + scoped_ptr<ConDecLogger> scoper(logger); + EXPECT_EQ(1, constructed); + + // Should auto-destruct logger by end of scope. + PassThru(scoper.Pass()); + EXPECT_FALSE(scoper.get()); + } + EXPECT_EQ(0, constructed); + + // Call TestReturnOfType() so the compiler doesn't warn for an unused + // function. + { + TestReturnOfType(&constructed); + } + EXPECT_EQ(0, constructed); +} + +TEST(ScopedPtrTest, CustomDeleter) { + double dummy_value; // Custom deleter never touches this value. + int deletes = 0; + int alternate_deletes = 0; + + // Normal delete support. + { + deletes = 0; + scoped_ptr<double, CountingDeleter> scoper(&dummy_value, + CountingDeleter(&deletes)); + EXPECT_EQ(0, deletes); + EXPECT_TRUE(scoper.get()); + } + EXPECT_EQ(1, deletes); + + // Test reset() and release(). + deletes = 0; + { + scoped_ptr<double, CountingDeleter> scoper(NULL, + CountingDeleter(&deletes)); + EXPECT_FALSE(scoper.get()); + EXPECT_FALSE(scoper.release()); + EXPECT_FALSE(scoper.get()); + scoper.reset(); + EXPECT_FALSE(scoper.get()); + EXPECT_EQ(0, deletes); + + scoper.reset(&dummy_value); + scoper.reset(); + EXPECT_EQ(1, deletes); + + scoper.reset(&dummy_value); + EXPECT_EQ(&dummy_value, scoper.release()); + } + EXPECT_EQ(1, deletes); + + // Test get_deleter(). + deletes = 0; + alternate_deletes = 0; + { + scoped_ptr<double, CountingDeleter> scoper(&dummy_value, + CountingDeleter(&deletes)); + // Call deleter manually. + EXPECT_EQ(0, deletes); + scoper.get_deleter()(&dummy_value); + EXPECT_EQ(1, deletes); + + // Deleter is still there after reset. + scoper.reset(); + EXPECT_EQ(2, deletes); + scoper.get_deleter()(&dummy_value); + EXPECT_EQ(3, deletes); + + // Deleter can be assigned into (matches C++11 unique_ptr<> spec). + scoper.get_deleter() = CountingDeleter(&alternate_deletes); + scoper.reset(&dummy_value); + EXPECT_EQ(0, alternate_deletes); + + } + EXPECT_EQ(3, deletes); + EXPECT_EQ(1, alternate_deletes); + + // Test operator= deleter support. + deletes = 0; + alternate_deletes = 0; + { + double dummy_value2; + scoped_ptr<double, CountingDeleter> scoper(&dummy_value, + CountingDeleter(&deletes)); + scoped_ptr<double, CountingDeleter> scoper2( + &dummy_value2, + CountingDeleter(&alternate_deletes)); + EXPECT_EQ(0, deletes); + EXPECT_EQ(0, alternate_deletes); + + // Pass the second deleter through a constructor and an operator=. Then + // reinitialize the empty scopers to ensure that each one is deleting + // properly. + scoped_ptr<double, CountingDeleter> scoper3(scoper2.Pass()); + scoper = scoper3.Pass(); + EXPECT_EQ(1, deletes); + + scoper2.reset(&dummy_value2); + scoper3.reset(&dummy_value2); + EXPECT_EQ(0, alternate_deletes); + + } + EXPECT_EQ(1, deletes); + EXPECT_EQ(3, alternate_deletes); + + // Test swap(), ==, !=, and type-safe Boolean. + { + scoped_ptr<double, CountingDeleter> scoper1(NULL, + CountingDeleter(&deletes)); + scoped_ptr<double, CountingDeleter> scoper2(NULL, + CountingDeleter(&deletes)); + EXPECT_TRUE(scoper1 == scoper2.get()); + EXPECT_FALSE(scoper1 != scoper2.get()); + + scoper1.reset(&dummy_value); + EXPECT_TRUE(scoper1); + EXPECT_EQ(&dummy_value, scoper1.get()); + EXPECT_FALSE(scoper2); + EXPECT_FALSE(scoper2.get()); + EXPECT_FALSE(scoper1 == scoper2.get()); + EXPECT_TRUE(scoper1 != scoper2.get()); + + scoper2.swap(scoper1); + EXPECT_EQ(&dummy_value, scoper2.get()); + EXPECT_FALSE(scoper1.get()); + EXPECT_FALSE(scoper1 == scoper2.get()); + EXPECT_TRUE(scoper1 != scoper2.get()); + } +} + +// Sanity check test for overloaded new and delete operators. Does not do full +// coverage of reset/release/Pass() operations as that is redundant with the +// above. +TEST(ScopedPtrTest, OverloadedNewAndDelete) { + { + OverloadedNewAndDelete::ResetCounters(); + scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete()); + EXPECT_TRUE(scoper.get()); + + scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass()); + } + EXPECT_EQ(1, OverloadedNewAndDelete::delete_count()); + EXPECT_EQ(1, OverloadedNewAndDelete::new_count()); +} + +scoped_ptr<int> NullIntReturn() { + return nullptr; +} + +TEST(ScopedPtrTest, Nullptr) { + scoped_ptr<int> scoper1(nullptr); + scoped_ptr<int> scoper2(new int); + scoper2 = nullptr; + scoped_ptr<int> scoper3(NullIntReturn()); + scoped_ptr<int> scoper4 = NullIntReturn(); + EXPECT_EQ(nullptr, scoper1.get()); + EXPECT_EQ(nullptr, scoper2.get()); + EXPECT_EQ(nullptr, scoper3.get()); + EXPECT_EQ(nullptr, scoper4.get()); +} + +scoped_ptr<int[]> NullIntArrayReturn() { + return nullptr; +} + +TEST(ScopedPtrTest, NullptrArray) { + scoped_ptr<int[]> scoper1(nullptr); + scoped_ptr<int[]> scoper2(new int[3]); + scoper2 = nullptr; + scoped_ptr<int[]> scoper3(NullIntArrayReturn()); + scoped_ptr<int[]> scoper4 = NullIntArrayReturn(); + EXPECT_EQ(nullptr, scoper1.get()); + EXPECT_EQ(nullptr, scoper2.get()); + EXPECT_EQ(nullptr, scoper3.get()); + EXPECT_EQ(nullptr, scoper4.get()); +} + +class Super {}; +class Sub : public Super {}; + +scoped_ptr<Sub> SubClassReturn() { + return make_scoped_ptr(new Sub); +} + +TEST(ScopedPtrTest, Conversion) { + scoped_ptr<Sub> sub1(new Sub); + scoped_ptr<Sub> sub2(new Sub); + + // Upcast with Pass() works. + scoped_ptr<Super> super1 = sub1.Pass(); + super1 = sub2.Pass(); + + // Upcast with an rvalue works. + scoped_ptr<Super> super2 = SubClassReturn(); + super2 = SubClassReturn(); +} + +// Android death tests don't work properly with assert(). Yay. +#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) +TEST(ScopedPtrTest, SelfResetAbortsWithDefaultDeleter) { + scoped_ptr<int> x(new int); + EXPECT_DEATH(x.reset(x.get()), ""); +} + +TEST(ScopedPtrTest, SelfResetAbortsWithDefaultArrayDeleter) { + scoped_ptr<int[]> y(new int[4]); + EXPECT_DEATH(y.reset(y.get()), ""); +} + +TEST(ScopedPtrTest, SelfResetAbortsWithDefaultFreeDeleter) { + scoped_ptr<int, base::FreeDeleter> z(static_cast<int*>(malloc(sizeof(int)))); + EXPECT_DEATH(z.reset(z.get()), ""); +} + +// A custom deleter that doesn't opt out should still crash. +TEST(ScopedPtrTest, SelfResetAbortsWithCustomDeleter) { + struct CustomDeleter { + inline void operator()(int* x) { delete x; } + }; + scoped_ptr<int, CustomDeleter> x(new int); + EXPECT_DEATH(x.reset(x.get()), ""); +} +#endif + +TEST(ScopedPtrTest, SelfResetWithCustomDeleterOptOut) { + // A custom deleter should be able to opt out of self-reset abort behavior. + struct NoOpDeleter { +#if !defined(NDEBUG) + typedef void AllowSelfReset; +#endif + inline void operator()(int*) {} + }; + scoped_ptr<int> owner(new int); + scoped_ptr<int, NoOpDeleter> x(owner.get()); + x.reset(x.get()); +} + +// Logging a scoped_ptr<T> to an ostream shouldn't convert it to a boolean +// value first. +TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) { + scoped_ptr<int> x(new int); + std::stringstream s1; + s1 << x; + + std::stringstream s2; + s2 << x.get(); + + EXPECT_EQ(s2.str(), s1.str()); +} diff --git a/third_party/chromium/base/memory/weak_ptr.cc b/third_party/chromium/base/memory/weak_ptr.cc new file mode 100644 index 0000000..0f91ef3 --- /dev/null +++ b/third_party/chromium/base/memory/weak_ptr.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/weak_ptr.h" + +namespace base { +namespace internal { + +WeakReference::Flag::Flag() : is_valid_(true) { +} + +void WeakReference::Flag::Invalidate() { + is_valid_ = false; +} + +bool WeakReference::Flag::IsValid() const { + return is_valid_; +} + +WeakReference::Flag::~Flag() { +} + +WeakReference::WeakReference() { +} + +WeakReference::WeakReference(const Flag* flag) : flag_(flag) { +} + +WeakReference::~WeakReference() { +} + +bool WeakReference::is_valid() const { return flag_.get() && flag_->IsValid(); } + +WeakReferenceOwner::WeakReferenceOwner() { +} + +WeakReferenceOwner::~WeakReferenceOwner() { + Invalidate(); +} + +WeakReference WeakReferenceOwner::GetRef() const { + // If we hold the last reference to the Flag then create a new one. + if (!HasRefs()) + flag_ = new WeakReference::Flag(); + + return WeakReference(flag_.get()); +} + +void WeakReferenceOwner::Invalidate() { + if (flag_.get()) { + flag_->Invalidate(); + flag_ = NULL; + } +} + +WeakPtrBase::WeakPtrBase() { +} + +WeakPtrBase::~WeakPtrBase() { +} + +WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) { +} + +} // namespace internal +} // namespace base diff --git a/third_party/chromium/base/memory/weak_ptr.h b/third_party/chromium/base/memory/weak_ptr.h new file mode 100644 index 0000000..e07beeb --- /dev/null +++ b/third_party/chromium/base/memory/weak_ptr.h @@ -0,0 +1,336 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Weak pointers are pointers to an object that do not affect its lifetime, +// and which may be invalidated (i.e. reset to NULL) by the object, or its +// owner, at any time, most commonly when the object is about to be deleted. + +// Weak pointers are useful when an object needs to be accessed safely by one +// or more objects other than its owner, and those callers can cope with the +// object vanishing and e.g. tasks posted to it being silently dropped. +// Reference-counting such an object would complicate the ownership graph and +// make it harder to reason about the object's lifetime. + +// EXAMPLE: +// +// class Controller { +// public: +// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); } +// void WorkComplete(const Result& result) { ... } +// private: +// // Member variables should appear before the WeakPtrFactory, to ensure +// // that any WeakPtrs to Controller are invalidated before its members +// // variable's destructors are executed, rendering them invalid. +// WeakPtrFactory<Controller> weak_factory_; +// }; +// +// class Worker { +// public: +// static void StartNew(const WeakPtr<Controller>& controller) { +// Worker* worker = new Worker(controller); +// // Kick off asynchronous processing... +// } +// private: +// Worker(const WeakPtr<Controller>& controller) +// : controller_(controller) {} +// void DidCompleteAsynchronousProcessing(const Result& result) { +// if (controller_) +// controller_->WorkComplete(result); +// } +// WeakPtr<Controller> controller_; +// }; +// +// With this implementation a caller may use SpawnWorker() to dispatch multiple +// Workers and subsequently delete the Controller, without waiting for all +// Workers to have completed. + +// ------------------------- IMPORTANT: Thread-safety ------------------------- + +// Weak pointers may be passed safely between threads, but must always be +// dereferenced and invalidated on the same SequencedTaskRunner otherwise +// checking the pointer would be racey. +// +// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory +// is dereferenced, the factory and its WeakPtrs become bound to the calling +// thread or current SequencedWorkerPool token, and cannot be dereferenced or +// invalidated on any other task runner. Bound WeakPtrs can still be handed +// off to other task runners, e.g. to use to post tasks back to object on the +// bound sequence. +// +// Invalidating the factory's WeakPtrs un-binds it from the sequence, allowing +// it to be passed for a different sequence to use or delete it. + +#ifndef BASE_MEMORY_WEAK_PTR_H_ +#define BASE_MEMORY_WEAK_PTR_H_ + +#include "base/basictypes.h" +#include "base/base_export.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" + +namespace base { + +template <typename T> class SupportsWeakPtr; +template <typename T> class WeakPtr; + +namespace internal { +// These classes are part of the WeakPtr implementation. +// DO NOT USE THESE CLASSES DIRECTLY YOURSELF. + +class BASE_EXPORT WeakReference { + public: + // Although Flag is bound to a specific SequencedTaskRunner, it may be + // deleted from another via base::WeakPtr::~WeakPtr(). + class Flag : public RefCountedThreadSafe<Flag> { + public: + Flag(); + + void Invalidate(); + bool IsValid() const; + + private: + friend class base::RefCountedThreadSafe<Flag>; + + ~Flag(); + + bool is_valid_; + }; + + WeakReference(); + explicit WeakReference(const Flag* flag); + ~WeakReference(); + + bool is_valid() const; + + private: + scoped_refptr<const Flag> flag_; +}; + +class BASE_EXPORT WeakReferenceOwner { + public: + WeakReferenceOwner(); + ~WeakReferenceOwner(); + + WeakReference GetRef() const; + + bool HasRefs() const { + return flag_.get() && !flag_->HasOneRef(); + } + + void Invalidate(); + + private: + mutable scoped_refptr<WeakReference::Flag> flag_; +}; + +// This class simplifies the implementation of WeakPtr's type conversion +// constructor by avoiding the need for a public accessor for ref_. A +// WeakPtr<T> cannot access the private members of WeakPtr<U>, so this +// base class gives us a way to access ref_ in a protected fashion. +class BASE_EXPORT WeakPtrBase { + public: + WeakPtrBase(); + ~WeakPtrBase(); + + protected: + explicit WeakPtrBase(const WeakReference& ref); + + WeakReference ref_; +}; + +// This class provides a common implementation of common functions that would +// otherwise get instantiated separately for each distinct instantiation of +// SupportsWeakPtr<>. +class SupportsWeakPtrBase { + public: + // A safe static downcast of a WeakPtr<Base> to WeakPtr<Derived>. This + // conversion will only compile if there is exists a Base which inherits + // from SupportsWeakPtr<Base>. See base::AsWeakPtr() below for a helper + // function that makes calling this easier. + template<typename Derived> + static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) { + typedef std::is_convertible<Derived*, internal::SupportsWeakPtrBase*> + convertible; + COMPILE_ASSERT(convertible::value, + AsWeakPtr_argument_inherits_from_SupportsWeakPtr); + return AsWeakPtrImpl<Derived>(t, *t); + } + + private: + // This template function uses type inference to find a Base of Derived + // which is an instance of SupportsWeakPtr<Base>. We can then safely + // static_cast the Base* to a Derived*. + template <typename Derived, typename Base> + static WeakPtr<Derived> AsWeakPtrImpl( + Derived* t, const SupportsWeakPtr<Base>&) { + WeakPtr<Base> ptr = t->Base::AsWeakPtr(); + return WeakPtr<Derived>(ptr.ref_, static_cast<Derived*>(ptr.ptr_)); + } +}; + +} // namespace internal + +template <typename T> class WeakPtrFactory; + +// The WeakPtr class holds a weak reference to |T*|. +// +// This class is designed to be used like a normal pointer. You should always +// null-test an object of this class before using it or invoking a method that +// may result in the underlying object being destroyed. +// +// EXAMPLE: +// +// class Foo { ... }; +// WeakPtr<Foo> foo; +// if (foo) +// foo->method(); +// +template <typename T> +class WeakPtr : public internal::WeakPtrBase { + public: + WeakPtr() : ptr_(NULL) { + } + + // Allow conversion from U to T provided U "is a" T. Note that this + // is separate from the (implicit) copy constructor. + template <typename U> + WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) { + } + + T* get() const { return ref_.is_valid() ? ptr_ : NULL; } + + T& operator*() const { + DCHECK(get() != NULL); + return *get(); + } + T* operator->() const { + DCHECK(get() != NULL); + return get(); + } + + // Allow WeakPtr<element_type> to be used in boolean expressions, but not + // implicitly convertible to a real bool (which is dangerous). + // + // Note that this trick is only safe when the == and != operators + // are declared explicitly, as otherwise "weak_ptr1 == weak_ptr2" + // will compile but do the wrong thing (i.e., convert to Testable + // and then do the comparison). + private: + typedef T* WeakPtr::*Testable; + + public: + operator Testable() const { return get() ? &WeakPtr::ptr_ : NULL; } + + void reset() { + ref_ = internal::WeakReference(); + ptr_ = NULL; + } + + private: + // Explicitly declare comparison operators as required by the bool + // trick, but keep them private. + template <class U> bool operator==(WeakPtr<U> const&) const; + template <class U> bool operator!=(WeakPtr<U> const&) const; + + friend class internal::SupportsWeakPtrBase; + template <typename U> friend class WeakPtr; + friend class SupportsWeakPtr<T>; + friend class WeakPtrFactory<T>; + + WeakPtr(const internal::WeakReference& ref, T* ptr) + : WeakPtrBase(ref), + ptr_(ptr) { + } + + // This pointer is only valid when ref_.is_valid() is true. Otherwise, its + // value is undefined (as opposed to NULL). + T* ptr_; +}; + +// A class may be composed of a WeakPtrFactory and thereby +// control how it exposes weak pointers to itself. This is helpful if you only +// need weak pointers within the implementation of a class. This class is also +// useful when working with primitive types. For example, you could have a +// WeakPtrFactory<bool> that is used to pass around a weak reference to a bool. +template <class T> +class WeakPtrFactory { + public: + explicit WeakPtrFactory(T* ptr) : ptr_(ptr) { + } + + ~WeakPtrFactory() { + ptr_ = NULL; + } + + WeakPtr<T> GetWeakPtr() { + DCHECK(ptr_); + return WeakPtr<T>(weak_reference_owner_.GetRef(), ptr_); + } + + // Call this method to invalidate all existing weak pointers. + void InvalidateWeakPtrs() { + DCHECK(ptr_); + weak_reference_owner_.Invalidate(); + } + + // Call this method to determine if any weak pointers exist. + bool HasWeakPtrs() const { + DCHECK(ptr_); + return weak_reference_owner_.HasRefs(); + } + + private: + internal::WeakReferenceOwner weak_reference_owner_; + T* ptr_; + DISALLOW_IMPLICIT_CONSTRUCTORS(WeakPtrFactory); +}; + +// A class may extend from SupportsWeakPtr to let others take weak pointers to +// it. This avoids the class itself implementing boilerplate to dispense weak +// pointers. However, since SupportsWeakPtr's destructor won't invalidate +// weak pointers to the class until after the derived class' members have been +// destroyed, its use can lead to subtle use-after-destroy issues. +template <class T> +class SupportsWeakPtr : public internal::SupportsWeakPtrBase { + public: + SupportsWeakPtr() {} + + WeakPtr<T> AsWeakPtr() { + return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T*>(this)); + } + + protected: + ~SupportsWeakPtr() {} + + private: + internal::WeakReferenceOwner weak_reference_owner_; + DISALLOW_COPY_AND_ASSIGN(SupportsWeakPtr); +}; + +// Helper function that uses type deduction to safely return a WeakPtr<Derived> +// when Derived doesn't directly extend SupportsWeakPtr<Derived>, instead it +// extends a Base that extends SupportsWeakPtr<Base>. +// +// EXAMPLE: +// class Base : public base::SupportsWeakPtr<Producer> {}; +// class Derived : public Base {}; +// +// Derived derived; +// base::WeakPtr<Derived> ptr = base::AsWeakPtr(&derived); +// +// Note that the following doesn't work (invalid type conversion) since +// Derived::AsWeakPtr() is WeakPtr<Base> SupportsWeakPtr<Base>::AsWeakPtr(), +// and there's no way to safely cast WeakPtr<Base> to WeakPtr<Derived> at +// the caller. +// +// base::WeakPtr<Derived> ptr = derived.AsWeakPtr(); // Fails. + +template <typename Derived> +WeakPtr<Derived> AsWeakPtr(Derived* t) { + return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t); +} + +} // namespace base + +#endif // BASE_MEMORY_WEAK_PTR_H_ diff --git a/third_party/chromium/base/memory/weak_ptr_unittest.cc b/third_party/chromium/base/memory/weak_ptr_unittest.cc new file mode 100644 index 0000000..8d4057c --- /dev/null +++ b/third_party/chromium/base/memory/weak_ptr_unittest.cc @@ -0,0 +1,153 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/memory/weak_ptr.h" + +#include <string> + +#include <gtest/gtest.h> + +#include "base/bind.h" +#include "base/location.h" +#include "base/memory/scoped_ptr.h" + +namespace base { +namespace { + +struct Base { + std::string member; +}; +struct Derived : public Base {}; + +struct TargetBase {}; +struct Target : public TargetBase, public SupportsWeakPtr<Target> { + virtual ~Target() {} +}; +struct DerivedTarget : public Target {}; +struct Arrow { + WeakPtr<Target> target; +}; +struct TargetWithFactory : public Target { + TargetWithFactory() : factory(this) {} + WeakPtrFactory<Target> factory; +}; + +} // namespace + +TEST(WeakPtrFactoryTest, Basic) { + int data; + WeakPtrFactory<int> factory(&data); + WeakPtr<int> ptr = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr.get()); +} + +TEST(WeakPtrFactoryTest, Comparison) { + int data; + WeakPtrFactory<int> factory(&data); + WeakPtr<int> ptr = factory.GetWeakPtr(); + WeakPtr<int> ptr2 = ptr; + EXPECT_EQ(ptr.get(), ptr2.get()); +} + +TEST(WeakPtrFactoryTest, OutOfScope) { + WeakPtr<int> ptr; + EXPECT_EQ(NULL, ptr.get()); + { + int data; + WeakPtrFactory<int> factory(&data); + ptr = factory.GetWeakPtr(); + } + EXPECT_EQ(NULL, ptr.get()); +} + +TEST(WeakPtrFactoryTest, Multiple) { + WeakPtr<int> a, b; + { + int data; + WeakPtrFactory<int> factory(&data); + a = factory.GetWeakPtr(); + b = factory.GetWeakPtr(); + EXPECT_EQ(&data, a.get()); + EXPECT_EQ(&data, b.get()); + } + EXPECT_EQ(NULL, a.get()); + EXPECT_EQ(NULL, b.get()); +} + +TEST(WeakPtrFactoryTest, MultipleStaged) { + WeakPtr<int> a; + { + int data; + WeakPtrFactory<int> factory(&data); + a = factory.GetWeakPtr(); + { + WeakPtr<int> b = factory.GetWeakPtr(); + } + EXPECT_TRUE(NULL != a.get()); + } + EXPECT_EQ(NULL, a.get()); +} + +TEST(WeakPtrFactoryTest, Dereference) { + Base data; + data.member = "123456"; + WeakPtrFactory<Base> factory(&data); + WeakPtr<Base> ptr = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr.get()); + EXPECT_EQ(data.member, (*ptr).member); + EXPECT_EQ(data.member, ptr->member); +} + +TEST(WeakPtrFactoryTest, UpCast) { + Derived data; + WeakPtrFactory<Derived> factory(&data); + WeakPtr<Base> ptr = factory.GetWeakPtr(); + ptr = factory.GetWeakPtr(); + EXPECT_EQ(ptr.get(), &data); +} + +TEST(WeakPtrTest, SupportsWeakPtr) { + Target target; + WeakPtr<Target> ptr = target.AsWeakPtr(); + EXPECT_EQ(&target, ptr.get()); +} + +TEST(WeakPtrTest, DerivedTarget) { + DerivedTarget target; + WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target); + EXPECT_EQ(&target, ptr.get()); +} + +TEST(WeakPtrTest, InvalidateWeakPtrs) { + int data; + WeakPtrFactory<int> factory(&data); + WeakPtr<int> ptr = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr.get()); + EXPECT_TRUE(factory.HasWeakPtrs()); + factory.InvalidateWeakPtrs(); + EXPECT_EQ(NULL, ptr.get()); + EXPECT_FALSE(factory.HasWeakPtrs()); + + // Test that the factory can create new weak pointers after a + // InvalidateWeakPtrs call, and they remain valid until the next + // InvalidateWeakPtrs call. + WeakPtr<int> ptr2 = factory.GetWeakPtr(); + EXPECT_EQ(&data, ptr2.get()); + EXPECT_TRUE(factory.HasWeakPtrs()); + factory.InvalidateWeakPtrs(); + EXPECT_EQ(NULL, ptr2.get()); + EXPECT_FALSE(factory.HasWeakPtrs()); +} + +TEST(WeakPtrTest, HasWeakPtrs) { + int data; + WeakPtrFactory<int> factory(&data); + { + WeakPtr<int> ptr = factory.GetWeakPtr(); + EXPECT_TRUE(factory.HasWeakPtrs()); + } + EXPECT_FALSE(factory.HasWeakPtrs()); +} + +} // namespace base diff --git a/third_party/chromium/base/move.h b/third_party/chromium/base/move.h new file mode 100644 index 0000000..87dc52d --- /dev/null +++ b/third_party/chromium/base/move.h @@ -0,0 +1,234 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_MOVE_H_ +#define BASE_MOVE_H_ + +#include "base/compiler_specific.h" + +// Macro with the boilerplate that makes a type move-only in C++03. +// +// USAGE +// +// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create +// a "move-only" type. Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be +// the first line in a class declaration. +// +// A class using this macro must call .Pass() (or somehow be an r-value already) +// before it can be: +// +// * Passed as a function argument +// * Used as the right-hand side of an assignment +// * Returned from a function +// +// Each class will still need to define their own "move constructor" and "move +// operator=" to make this useful. Here's an example of the macro, the move +// constructor, and the move operator= from the scoped_ptr class: +// +// template <typename T> +// class scoped_ptr { +// MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) +// public: +// scoped_ptr(RValue& other) : ptr_(other.release()) { } +// scoped_ptr& operator=(RValue& other) { +// swap(other); +// return *this; +// } +// }; +// +// Note that the constructor must NOT be marked explicit. +// +// For consistency, the second parameter to the macro should always be RValue +// unless you have a strong reason to do otherwise. It is only exposed as a +// macro parameter so that the move constructor and move operator= don't look +// like they're using a phantom type. +// +// +// HOW THIS WORKS +// +// For a thorough explanation of this technique, see: +// +// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor +// +// The summary is that we take advantage of 2 properties: +// +// 1) non-const references will not bind to r-values. +// 2) C++ can apply one user-defined conversion when initializing a +// variable. +// +// The first lets us disable the copy constructor and assignment operator +// by declaring private version of them with a non-const reference parameter. +// +// For l-values, direct initialization still fails like in +// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment +// operators are private. +// +// For r-values, the situation is different. The copy constructor and +// assignment operator are not viable due to (1), so we are trying to call +// a non-existent constructor and non-existing operator= rather than a private +// one. Since we have not committed an error quite yet, we can provide an +// alternate conversion sequence and a constructor. We add +// +// * a private struct named "RValue" +// * a user-defined conversion "operator RValue()" +// * a "move constructor" and "move operator=" that take the RValue& as +// their sole parameter. +// +// Only r-values will trigger this sequence and execute our "move constructor" +// or "move operator=." L-values will match the private copy constructor and +// operator= first giving a "private in this context" error. This combination +// gives us a move-only type. +// +// For signaling a destructive transfer of data from an l-value, we provide a +// method named Pass() which creates an r-value for the current instance +// triggering the move constructor or move operator=. +// +// Other ways to get r-values is to use the result of an expression like a +// function call. +// +// Here's an example with comments explaining what gets triggered where: +// +// class Foo { +// MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue); +// +// public: +// ... API ... +// Foo(RValue other); // Move constructor. +// Foo& operator=(RValue rhs); // Move operator= +// }; +// +// Foo MakeFoo(); // Function that returns a Foo. +// +// Foo f; +// Foo f_copy(f); // ERROR: Foo(Foo&) is private in this context. +// Foo f_assign; +// f_assign = f; // ERROR: operator=(Foo&) is private in this context. +// +// +// Foo f(MakeFoo()); // R-value so alternate conversion executed. +// Foo f_copy(f.Pass()); // R-value so alternate conversion executed. +// f = f_copy.Pass(); // R-value so alternate conversion executed. +// +// +// IMPLEMENTATION SUBTLETIES WITH RValue +// +// The RValue struct is just a container for a pointer back to the original +// object. It should only ever be created as a temporary, and no external +// class should ever declare it or use it in a parameter. +// +// It is tempting to want to use the RValue type in function parameters, but +// excluding the limited usage here for the move constructor and move +// operator=, doing so would mean that the function could take both r-values +// and l-values equially which is unexpected. See COMPARED To Boost.Move for +// more details. +// +// An alternate, and incorrect, implementation of the RValue class used by +// Boost.Move makes RValue a fieldless child of the move-only type. RValue& +// is then used in place of RValue in the various operators. The RValue& is +// "created" by doing *reinterpret_cast<RValue*>(this). This has the appeal +// of never creating a temporary RValue struct even with optimizations +// disabled. Also, by virtue of inheritance you can treat the RValue +// reference as if it were the move-only type itself. Unfortunately, +// using the result of this reinterpret_cast<> is actually undefined behavior +// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer +// will generate non-working code. +// +// In optimized builds, both implementations generate the same assembly so we +// choose the one that adheres to the standard. +// +// +// WHY HAVE typedef void MoveOnlyTypeForCPP03 +// +// Callback<>/Bind() needs to understand movable-but-not-copyable semantics +// to call .Pass() appropriately when it is expected to transfer the value. +// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check +// easy and automatic in helper templates for Callback<>/Bind(). +// See IsMoveOnlyType template and its usage in base/callback_internal.h +// for more details. +// +// +// COMPARED TO C++11 +// +// In C++11, you would implement this functionality using an r-value reference +// and our .Pass() method would be replaced with a call to std::move(). +// +// This emulation also has a deficiency where it uses up the single +// user-defined conversion allowed by C++ during initialization. This can +// cause problems in some API edge cases. For instance, in scoped_ptr, it is +// impossible to make a function "void Foo(scoped_ptr<Parent> p)" accept a +// value of type scoped_ptr<Child> even if you add a constructor to +// scoped_ptr<> that would make it look like it should work. C++11 does not +// have this deficiency. +// +// +// COMPARED TO Boost.Move +// +// Our implementation similar to Boost.Move, but we keep the RValue struct +// private to the move-only type, and we don't use the reinterpret_cast<> hack. +// +// In Boost.Move, RValue is the boost::rv<> template. This type can be used +// when writing APIs like: +// +// void MyFunc(boost::rv<Foo>& f) +// +// that can take advantage of rv<> to avoid extra copies of a type. However you +// would still be able to call this version of MyFunc with an l-value: +// +// Foo f; +// MyFunc(f); // Uh oh, we probably just destroyed |f| w/o calling Pass(). +// +// unless someone is very careful to also declare a parallel override like: +// +// void MyFunc(const Foo& f) +// +// that would catch the l-values first. This was declared unsafe in C++11 and +// a C++11 compiler will explicitly fail MyFunc(f). Unfortunately, we cannot +// ensure this in C++03. +// +// Since we have no need for writing such APIs yet, our implementation keeps +// RValue private and uses a .Pass() method to do the conversion instead of +// trying to write a version of "std::move()." Writing an API like std::move() +// would require the RValue struct to be public. +// +// +// CAVEATS +// +// If you include a move-only type as a field inside a class that does not +// explicitly declare a copy constructor, the containing class's implicit +// copy constructor will change from Containing(const Containing&) to +// Containing(Containing&). This can cause some unexpected errors. +// +// http://llvm.org/bugs/show_bug.cgi?id=11528 +// +// The workaround is to explicitly declare your copy constructor. +// +#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \ + private: \ + struct rvalue_type { \ + explicit rvalue_type(type* object) : object(object) {} \ + type* object; \ + }; \ + type(type&); \ + void operator=(type&); \ + public: \ + operator rvalue_type() { return rvalue_type(this); } \ + type Pass() WARN_UNUSED_RESULT { return type(rvalue_type(this)); } \ + typedef void MoveOnlyTypeForCPP03; \ + private: + +#define MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \ + private: \ + type(const type&); \ + void operator=(const type&); \ + public: \ + type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \ + typedef void MoveOnlyTypeForCPP03; \ + private: + +#define TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \ + public: \ + type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \ + private: + +#endif // BASE_MOVE_H_ diff --git a/third_party/chromium/base/move_unittest.cc b/third_party/chromium/base/move_unittest.cc new file mode 100644 index 0000000..bebcfd8 --- /dev/null +++ b/third_party/chromium/base/move_unittest.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2015 The Chromium 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/move.h" + +#include <gtest/gtest.h> + +namespace { + +class MoveOnly { + MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(MoveOnly) + + public: + MoveOnly() {} + + MoveOnly(MoveOnly&& other) {} + MoveOnly& operator=(MoveOnly&& other) { return *this; } +}; + +class Container { + public: + Container() = default; + Container(const Container& other) = default; + Container& operator=(const Container& other) = default; + + Container(Container&& other) { value_ = other.value_.Pass(); } + + Container& operator=(Container&& other) { + value_ = other.value_.Pass(); + return *this; + } + + private: + MoveOnly value_; +}; + +Container GetContainerRvalue() { + Container x; + return x; +} + +TEST(MoveTest, CopyableContainerCanBeMoved) { + // Container should be move-constructible and move-assignable. + Container y = GetContainerRvalue(); + y = GetContainerRvalue(); +} + +} // namespace diff --git a/third_party/chromium/base/numerics/safe_conversions.h b/third_party/chromium/base/numerics/safe_conversions.h new file mode 100644 index 0000000..5dd5191 --- /dev/null +++ b/third_party/chromium/base/numerics/safe_conversions.h @@ -0,0 +1,125 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_ +#define BASE_NUMERICS_SAFE_CONVERSIONS_H_ + +#include <limits> + +#include "base/logging.h" +#include "base/numerics/safe_conversions_impl.h" + +namespace base { + +// Convenience function that returns true if the supplied value is in range +// for the destination type. +template <typename Dst, typename Src> +inline bool IsValueInRangeForNumericType(Src value) { + return internal::DstRangeRelationToSrcRange<Dst>(value) == + internal::RANGE_VALID; +} + +// checked_cast<> is analogous to static_cast<> for numeric types, +// except that it CHECKs that the specified numeric conversion will not +// overflow or underflow. NaN source will always trigger a CHECK. +template <typename Dst, typename Src> +inline Dst checked_cast(Src value) { + CHECK(IsValueInRangeForNumericType<Dst>(value)); + return static_cast<Dst>(value); +} + +// saturated_cast<> is analogous to static_cast<> for numeric types, except +// that the specified numeric conversion will saturate rather than overflow or +// underflow. NaN assignment to an integral will trigger a CHECK condition. +template <typename Dst, typename Src> +inline Dst saturated_cast(Src value) { + // Optimization for floating point values, which already saturate. + if (std::numeric_limits<Dst>::is_iec559) + return static_cast<Dst>(value); + + switch (internal::DstRangeRelationToSrcRange<Dst>(value)) { + case internal::RANGE_VALID: + return static_cast<Dst>(value); + + case internal::RANGE_UNDERFLOW: + return std::numeric_limits<Dst>::min(); + + case internal::RANGE_OVERFLOW: + return std::numeric_limits<Dst>::max(); + + // Should fail only on attempting to assign NaN to a saturated integer. + case internal::RANGE_INVALID: + CHECK(false); + return std::numeric_limits<Dst>::max(); + } + + NOTREACHED(); + return static_cast<Dst>(value); +} + +// strict_cast<> is analogous to static_cast<> for numeric types, except that +// it will cause a compile failure if the destination type is not large enough +// to contain any value in the source type. It performs no runtime checking. +template <typename Dst, typename Src> +inline Dst strict_cast(Src value) { + static_assert(std::numeric_limits<Src>::is_specialized, + "Argument must be numeric."); + static_assert(std::numeric_limits<Dst>::is_specialized, + "Result must be numeric."); + static_assert((internal::StaticDstRangeRelationToSrcRange<Dst, Src>::value == + internal::NUMERIC_RANGE_CONTAINED), + "The numeric conversion is out of range for this type. You " + "should probably use one of the following conversion " + "mechanisms on the value you want to pass:\n" + "- base::checked_cast\n" + "- base::saturated_cast\n" + "- base::CheckedNumeric"); + + return static_cast<Dst>(value); +} + +// StrictNumeric implements compile time range checking between numeric types by +// wrapping assignment operations in a strict_cast. This class is intended to be +// used for function arguments and return types, to ensure the destination type +// can always contain the source type. This is essentially the same as enforcing +// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied +// incrementally at API boundaries, making it easier to convert code so that it +// compiles cleanly with truncation warnings enabled. +// This template should introduce no runtime overhead, but it also provides no +// runtime checking of any of the associated mathematical operations. Use +// CheckedNumeric for runtime range checks of tha actual value being assigned. +template <typename T> +class StrictNumeric { + public: + typedef T type; + + StrictNumeric() : value_(0) {} + + // Copy constructor. + template <typename Src> + StrictNumeric(const StrictNumeric<Src>& rhs) + : value_(strict_cast<T>(rhs.value_)) {} + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to StrictNumerics to make them easier to use. + template <typename Src> + StrictNumeric(Src value) + : value_(strict_cast<T>(value)) {} + + // The numeric cast operator basically handles all the magic. + template <typename Dst> + operator Dst() const { + return strict_cast<Dst>(value_); + } + + private: + T value_; +}; + +// Explicitly make a shorter size_t typedef for convenience. +typedef StrictNumeric<size_t> SizeT; + +} // namespace base + +#endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ diff --git a/third_party/chromium/base/numerics/safe_conversions_impl.h b/third_party/chromium/base/numerics/safe_conversions_impl.h new file mode 100644 index 0000000..d07221e --- /dev/null +++ b/third_party/chromium/base/numerics/safe_conversions_impl.h @@ -0,0 +1,213 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ +#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ + +#include <limits> + +namespace base { +namespace internal { + +// The std library doesn't provide a binary max_exponent for integers, however +// we can compute one by adding one to the number of non-sign bits. This allows +// for accurate range comparisons between floating point and integer types. +template <typename NumericType> +struct MaxExponent { + static const int value = std::numeric_limits<NumericType>::is_iec559 + ? std::numeric_limits<NumericType>::max_exponent + : (sizeof(NumericType) * 8 + 1 - + std::numeric_limits<NumericType>::is_signed); +}; + +enum IntegerRepresentation { + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED +}; + +// A range for a given nunmeric Src type is contained for a given numeric Dst +// type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and +// numeric_limits<Src>::min() >= numeric_limits<Dst>::min() are true. +// We implement this as template specializations rather than simple static +// comparisons to ensure type correctness in our comparisons. +enum NumericRangeRepresentation { + NUMERIC_RANGE_NOT_CONTAINED, + NUMERIC_RANGE_CONTAINED +}; + +// Helper templates to statically determine if our destination type can contain +// maximum and minimum values represented by the source type. + +template < + typename Dst, + typename Src, + IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = + std::numeric_limits<Src>::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED > +struct StaticDstRangeRelationToSrcRange; + +// Same sign: Dst is guaranteed to contain Src only if its range is equal or +// larger. +template <typename Dst, typename Src, IntegerRepresentation Sign> +struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> { + static const NumericRangeRepresentation value = + MaxExponent<Dst>::value >= MaxExponent<Src>::value + ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Unsigned to signed: Dst is guaranteed to contain source only if its range is +// larger. +template <typename Dst, typename Src> +struct StaticDstRangeRelationToSrcRange<Dst, + Src, + INTEGER_REPRESENTATION_SIGNED, + INTEGER_REPRESENTATION_UNSIGNED> { + static const NumericRangeRepresentation value = + MaxExponent<Dst>::value > MaxExponent<Src>::value + ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Signed to unsigned: Dst cannot be statically determined to contain Src. +template <typename Dst, typename Src> +struct StaticDstRangeRelationToSrcRange<Dst, + Src, + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED> { + static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; +}; + +enum RangeConstraint { + RANGE_VALID = 0x0, // Value can be represented by the destination type. + RANGE_UNDERFLOW = 0x1, // Value would overflow. + RANGE_OVERFLOW = 0x2, // Value would underflow. + RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). +}; + +// Helper function for coercing an int back to a RangeContraint. +inline RangeConstraint GetRangeConstraint(int integer_range_constraint) { + DCHECK(integer_range_constraint >= RANGE_VALID && + integer_range_constraint <= RANGE_INVALID); + return static_cast<RangeConstraint>(integer_range_constraint); +} + +// This function creates a RangeConstraint from an upper and lower bound +// check by taking advantage of the fact that only NaN can be out of range in +// both directions at once. +inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound, + bool is_in_lower_bound) { + return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) | + (is_in_lower_bound ? 0 : RANGE_UNDERFLOW)); +} + +template < + typename Dst, + typename Src, + IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::numeric_limits<Src>::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + NumericRangeRepresentation DstRange = + StaticDstRangeRelationToSrcRange<Dst, Src>::value > +struct DstRangeRelationToSrcRangeImpl; + +// The following templates are for ranges that must be verified at runtime. We +// split it into checks based on signedness to avoid confusing casts and +// compiler warnings on signed an unsigned comparisons. + +// Dst range is statically determined to contain Src: Nothing to check. +template <typename Dst, + typename Src, + IntegerRepresentation DstSign, + IntegerRepresentation SrcSign> +struct DstRangeRelationToSrcRangeImpl<Dst, + Src, + DstSign, + SrcSign, + NUMERIC_RANGE_CONTAINED> { + static RangeConstraint Check(Src value) { return RANGE_VALID; } +}; + +// Signed to signed narrowing: Both the upper and lower boundaries may be +// exceeded. +template <typename Dst, typename Src> +struct DstRangeRelationToSrcRangeImpl<Dst, + Src, + INTEGER_REPRESENTATION_SIGNED, + INTEGER_REPRESENTATION_SIGNED, + NUMERIC_RANGE_NOT_CONTAINED> { + static RangeConstraint Check(Src value) { + return std::numeric_limits<Dst>::is_iec559 + ? GetRangeConstraint((value < std::numeric_limits<Dst>::max()), + (value > -std::numeric_limits<Dst>::max())) + : GetRangeConstraint((value < std::numeric_limits<Dst>::max()), + (value > std::numeric_limits<Dst>::min())); + } +}; + +// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. +template <typename Dst, typename Src> +struct DstRangeRelationToSrcRangeImpl<Dst, + Src, + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_UNSIGNED, + NUMERIC_RANGE_NOT_CONTAINED> { + static RangeConstraint Check(Src value) { + return GetRangeConstraint(value < std::numeric_limits<Dst>::max(), true); + } +}; + +// Unsigned to signed: The upper boundary may be exceeded. +template <typename Dst, typename Src> +struct DstRangeRelationToSrcRangeImpl<Dst, + Src, + INTEGER_REPRESENTATION_SIGNED, + INTEGER_REPRESENTATION_UNSIGNED, + NUMERIC_RANGE_NOT_CONTAINED> { + static RangeConstraint Check(Src value) { + return sizeof(Dst) > sizeof(Src) + ? RANGE_VALID + : GetRangeConstraint( + value < static_cast<Src>(std::numeric_limits<Dst>::max()), + true); + } +}; + +// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, +// and any negative value exceeds the lower boundary. +template <typename Dst, typename Src> +struct DstRangeRelationToSrcRangeImpl<Dst, + Src, + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED, + NUMERIC_RANGE_NOT_CONTAINED> { + static RangeConstraint Check(Src value) { + return (MaxExponent<Dst>::value >= MaxExponent<Src>::value) + ? GetRangeConstraint(true, value >= static_cast<Src>(0)) + : GetRangeConstraint( + value < static_cast<Src>(std::numeric_limits<Dst>::max()), + value >= static_cast<Src>(0)); + } +}; + +template <typename Dst, typename Src> +inline RangeConstraint DstRangeRelationToSrcRange(Src value) { + static_assert(std::numeric_limits<Src>::is_specialized, + "Argument must be numeric."); + static_assert(std::numeric_limits<Dst>::is_specialized, + "Result must be numeric."); + return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value); +} + +} // namespace internal +} // namespace base + +#endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ diff --git a/third_party/chromium/base/numerics/safe_math.h b/third_party/chromium/base/numerics/safe_math.h new file mode 100644 index 0000000..a596d4b --- /dev/null +++ b/third_party/chromium/base/numerics/safe_math.h @@ -0,0 +1,279 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_MATH_H_ +#define BASE_NUMERICS_SAFE_MATH_H_ + +#include "base/numerics/safe_math_impl.h" + +namespace base { + +namespace internal { + +// CheckedNumeric implements all the logic and operators for detecting integer +// boundary conditions such as overflow, underflow, and invalid conversions. +// The CheckedNumeric type implicitly converts from floating point and integer +// data types, and contains overloads for basic arithmetic operations (i.e.: +, +// -, *, /, %). +// +// The following methods convert from CheckedNumeric to standard numeric values: +// IsValid() - Returns true if the underlying numeric value is valid (i.e. has +// has not wrapped and is not the result of an invalid conversion). +// ValueOrDie() - Returns the underlying value. If the state is not valid this +// call will crash on a CHECK. +// ValueOrDefault() - Returns the current value, or the supplied default if the +// state is not valid. +// ValueFloating() - Returns the underlying floating point value (valid only +// only for floating point CheckedNumeric types). +// +// Bitwise operations are explicitly not supported, because correct +// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison +// operations are explicitly not supported because they could result in a crash +// on a CHECK condition. You should use patterns like the following for these +// operations: +// Bitwise operation: +// CheckedNumeric<int> checked_int = untrusted_input_value; +// int x = checked_int.ValueOrDefault(0) | kFlagValues; +// Comparison: +// CheckedNumeric<size_t> checked_size; +// CheckedNumeric<int> checked_size = untrusted_input_value; +// checked_size = checked_size + HEADER LENGTH; +// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) +// Do stuff... +template <typename T> +class CheckedNumeric { + public: + typedef T type; + + CheckedNumeric() {} + + // Copy constructor. + template <typename Src> + CheckedNumeric(const CheckedNumeric<Src>& rhs) + : state_(rhs.ValueUnsafe(), rhs.validity()) {} + + template <typename Src> + CheckedNumeric(Src value, RangeConstraint validity) + : state_(value, validity) {} + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to CheckedNumerics to make them easier to use. + template <typename Src> + CheckedNumeric(Src value) + : state_(value) { + static_assert(std::numeric_limits<Src>::is_specialized, + "Argument must be numeric."); + } + + // This is not an explicit constructor because we want a seamless conversion + // from StrictNumeric types. + template <typename Src> + CheckedNumeric(StrictNumeric<Src> value) + : state_(static_cast<Src>(value)) { + } + + // IsValid() is the public API to test if a CheckedNumeric is currently valid. + bool IsValid() const { return validity() == RANGE_VALID; } + + // ValueOrDie() The primary accessor for the underlying value. If the current + // state is not valid it will CHECK and crash. + T ValueOrDie() const { + CHECK(IsValid()); + return state_.value(); + } + + // ValueOrDefault(T default_value) A convenience method that returns the + // current value if the state is valid, and the supplied default_value for + // any other state. + T ValueOrDefault(T default_value) const { + return IsValid() ? state_.value() : default_value; + } + + // ValueFloating() - Since floating point values include their validity state, + // we provide an easy method for extracting them directly, without a risk of + // crashing on a CHECK. + T ValueFloating() const { + static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float."); + return CheckedNumeric<T>::cast(*this).ValueUnsafe(); + } + + // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for + // tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: current validity state (i.e. valid, overflow, underflow, nan). + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + RangeConstraint validity() const { return state_.validity(); } + + // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now + // for tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: the raw numeric value, regardless of the current state. + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + T ValueUnsafe() const { return state_.value(); } + + // Prototypes for the supported arithmetic operator overloads. + template <typename Src> CheckedNumeric& operator+=(Src rhs); + template <typename Src> CheckedNumeric& operator-=(Src rhs); + template <typename Src> CheckedNumeric& operator*=(Src rhs); + template <typename Src> CheckedNumeric& operator/=(Src rhs); + template <typename Src> CheckedNumeric& operator%=(Src rhs); + + CheckedNumeric operator-() const { + RangeConstraint validity; + T value = CheckedNeg(state_.value(), &validity); + // Negation is always valid for floating point. + if (std::numeric_limits<T>::is_iec559) + return CheckedNumeric<T>(value); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric<T>(value, validity); + } + + CheckedNumeric Abs() const { + RangeConstraint validity; + T value = CheckedAbs(state_.value(), &validity); + // Absolute value is always valid for floating point. + if (std::numeric_limits<T>::is_iec559) + return CheckedNumeric<T>(value); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric<T>(value, validity); + } + + CheckedNumeric& operator++() { + *this += 1; + return *this; + } + + CheckedNumeric operator++(int) { + CheckedNumeric value = *this; + *this += 1; + return value; + } + + CheckedNumeric& operator--() { + *this -= 1; + return *this; + } + + CheckedNumeric operator--(int) { + CheckedNumeric value = *this; + *this -= 1; + return value; + } + + // These static methods behave like a convenience cast operator targeting + // the desired CheckedNumeric type. As an optimization, a reference is + // returned when Src is the same type as T. + template <typename Src> + static CheckedNumeric<T> cast( + Src u, + typename std::enable_if<std::numeric_limits<Src>::is_specialized, + int>::type = 0) { + return u; + } + + template <typename Src> + static CheckedNumeric<T> cast( + const CheckedNumeric<Src>& u, + typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) { + return u; + } + + static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; } + + private: + CheckedNumericState<T> state_; +}; + +// This is the boilerplate for the standard arithmetic operator overloads. A +// macro isn't the prettiest solution, but it beats rewriting these five times. +// Some details worth noting are: +// * We apply the standard arithmetic promotions. +// * We skip range checks for floating points. +// * We skip range checks for destination integers with sufficient range. +// TODO(jschuh): extract these out into templates. +#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ + /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ + template <typename T> \ + CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \ + const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) { \ + typedef typename ArithmeticPromotion<T>::type Promotion; \ + /* Floating point always takes the fast path */ \ + if (std::numeric_limits<T>::is_iec559) \ + return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ + if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \ + return CheckedNumeric<Promotion>( \ + lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + RangeConstraint validity = RANGE_VALID; \ + T result = static_cast<T>(Checked##NAME( \ + static_cast<Promotion>(lhs.ValueUnsafe()), \ + static_cast<Promotion>(rhs.ValueUnsafe()), \ + &validity)); \ + return CheckedNumeric<Promotion>( \ + result, \ + GetRangeConstraint(validity | lhs.validity() | rhs.validity())); \ + } \ + /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ + template <typename T> \ + template <typename Src> \ + CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \ + *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \ + return *this; \ + } \ + /* Binary arithmetic operator for CheckedNumeric of different type. */ \ + template <typename T, typename Src> \ + CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ + const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) { \ + typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ + if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ + return CheckedNumeric<Promotion>( \ + lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + return CheckedNumeric<Promotion>::cast(lhs) \ + OP CheckedNumeric<Promotion>::cast(rhs); \ + } \ + /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ + template <typename T, typename Src> \ + CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ + const CheckedNumeric<T>& lhs, Src rhs) { \ + typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ + if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ + return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs, \ + lhs.validity()); \ + return CheckedNumeric<Promotion>::cast(lhs) \ + OP CheckedNumeric<Promotion>::cast(rhs); \ + } \ + /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \ + template <typename T, typename Src> \ + CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ + Src lhs, const CheckedNumeric<T>& rhs) { \ + typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ + if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ + return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \ + rhs.validity()); \ + return CheckedNumeric<Promotion>::cast(lhs) \ + OP CheckedNumeric<Promotion>::cast(rhs); \ + } + +BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) + +#undef BASE_NUMERIC_ARITHMETIC_OPERATORS + +} // namespace internal + +using internal::CheckedNumeric; + +} // namespace base + +#endif // BASE_NUMERICS_SAFE_MATH_H_ diff --git a/third_party/chromium/base/numerics/safe_math_impl.h b/third_party/chromium/base/numerics/safe_math_impl.h new file mode 100644 index 0000000..0ae1dfe --- /dev/null +++ b/third_party/chromium/base/numerics/safe_math_impl.h @@ -0,0 +1,502 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ +#define BASE_NUMERICS_SAFE_MATH_IMPL_H_ + +#include <stdint.h> + +#include <cmath> +#include <cstdlib> +#include <limits> + +#include "base/numerics/safe_conversions.h" + +namespace base { +namespace internal { + +// Everything from here up to the floating point operations is portable C++, +// but it may not be fast. This code could be split based on +// platform/architecture and replaced with potentially faster implementations. + +// Integer promotion templates used by the portable checked integer arithmetic. +template <size_t Size, bool IsSigned> +struct IntegerForSizeAndSign; +template <> +struct IntegerForSizeAndSign<1, true> { + typedef int8_t type; +}; +template <> +struct IntegerForSizeAndSign<1, false> { + typedef uint8_t type; +}; +template <> +struct IntegerForSizeAndSign<2, true> { + typedef int16_t type; +}; +template <> +struct IntegerForSizeAndSign<2, false> { + typedef uint16_t type; +}; +template <> +struct IntegerForSizeAndSign<4, true> { + typedef int32_t type; +}; +template <> +struct IntegerForSizeAndSign<4, false> { + typedef uint32_t type; +}; +template <> +struct IntegerForSizeAndSign<8, true> { + typedef int64_t type; +}; +template <> +struct IntegerForSizeAndSign<8, false> { + typedef uint64_t type; +}; + +// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to +// support 128-bit math, then the ArithmeticPromotion template below will need +// to be updated (or more likely replaced with a decltype expression). + +template <typename Integer> +struct UnsignedIntegerForSize { + typedef typename std::enable_if< + std::numeric_limits<Integer>::is_integer, + typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type; +}; + +template <typename Integer> +struct SignedIntegerForSize { + typedef typename std::enable_if< + std::numeric_limits<Integer>::is_integer, + typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type; +}; + +template <typename Integer> +struct TwiceWiderInteger { + typedef typename std::enable_if< + std::numeric_limits<Integer>::is_integer, + typename IntegerForSizeAndSign< + sizeof(Integer) * 2, + std::numeric_limits<Integer>::is_signed>::type>::type type; +}; + +template <typename Integer> +struct PositionOfSignBit { + static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, + size_t>::type value = 8 * sizeof(Integer) - 1; +}; + +// Helper templates for integer manipulations. + +template <typename T> +bool HasSignBit(T x) { + // Cast to unsigned since right shift on signed is undefined. + return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> + PositionOfSignBit<T>::value); +} + +// This wrapper undoes the standard integer promotions. +template <typename T> +T BinaryComplement(T x) { + return ~x; +} + +// Here are the actual portable checked integer math implementations. +// TODO(jschuh): Break this code out from the enable_if pattern and find a clean +// way to coalesce things into the CheckedNumericState specializations below. + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type +CheckedAdd(T x, T y, RangeConstraint* validity) { + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; + UnsignedDst ux = static_cast<UnsignedDst>(x); + UnsignedDst uy = static_cast<UnsignedDst>(y); + UnsignedDst uresult = ux + uy; + // Addition is valid if the sign of (x + y) is equal to either that of x or + // that of y. + if (std::numeric_limits<T>::is_signed) { + if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) + *validity = RANGE_VALID; + else // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + + } else { // Unsigned is either valid or overflow. + *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; + } + return static_cast<T>(uresult); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type +CheckedSub(T x, T y, RangeConstraint* validity) { + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; + UnsignedDst ux = static_cast<UnsignedDst>(x); + UnsignedDst uy = static_cast<UnsignedDst>(y); + UnsignedDst uresult = ux - uy; + // Subtraction is valid if either x and y have same sign, or (x-y) and x have + // the same sign. + if (std::numeric_limits<T>::is_signed) { + if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) + *validity = RANGE_VALID; + else // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + + } else { // Unsigned is either valid or underflow. + *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; + } + return static_cast<T>(uresult); +} + +// Integer multiplication is a bit complicated. In the fast case we just +// we just promote to a twice wider type, and range check the result. In the +// slow case we need to manually check that the result won't be truncated by +// checking with division against the appropriate bound. +template <typename T> +typename std::enable_if< + std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + typedef typename TwiceWiderInteger<T>::type IntermediateType; + IntermediateType tmp = + static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); + *validity = DstRangeRelationToSrcRange<T>(tmp); + return static_cast<T>(tmp); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && + std::numeric_limits<T>::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + // If either side is zero then the result will be zero. + if (!x || !y) { + return RANGE_VALID; + + } else if (x > 0) { + if (y > 0) + *validity = + x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; + else + *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID + : RANGE_UNDERFLOW; + + } else { + if (y > 0) + *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID + : RANGE_UNDERFLOW; + else + *validity = + y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; + } + + return x * y; +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && + !std::numeric_limits<T>::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint* validity) { + *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) + ? RANGE_VALID + : RANGE_OVERFLOW; + return x * y; +} + +// Division just requires a check for an invalid negation on signed min/-1. +template <typename T> +T CheckedDiv(T x, + T y, + RangeConstraint* validity, + typename std::enable_if<std::numeric_limits<T>::is_integer, + int>::type = 0) { + if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && + y == static_cast<T>(-1)) { + *validity = RANGE_OVERFLOW; + return std::numeric_limits<T>::min(); + } + + *validity = RANGE_VALID; + return x / y; +} + +template <typename T> +typename std::enable_if< + std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint* validity) { + *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; + return x % y; +} + +template <typename T> +typename std::enable_if< + std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint* validity) { + *validity = RANGE_VALID; + return x % y; +} + +template <typename T> +typename std::enable_if< + std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint* validity) { + *validity = + value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; + // The negation of signed min is min, so catch that one. + return -value; +} + +template <typename T> +typename std::enable_if< + std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint* validity) { + // The only legal unsigned negation is zero. + *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; + return static_cast<T>( + -static_cast<typename SignedIntegerForSize<T>::type>(value)); +} + +template <typename T> +typename std::enable_if< + std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint* validity) { + *validity = + value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; + return static_cast<T>(std::abs(value)); +} + +template <typename T> +typename std::enable_if< + std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint* validity) { + // Absolute value of a positive is just its identiy. + *validity = RANGE_VALID; + return value; +} + +// These are the floating point stubs that the compiler needs to see. Only the +// negation operation is ever called. +#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ + template <typename T> \ + typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ + Checked##NAME(T, T, RangeConstraint*) { \ + NOTREACHED(); \ + return 0; \ + } + +BASE_FLOAT_ARITHMETIC_STUBS(Add) +BASE_FLOAT_ARITHMETIC_STUBS(Sub) +BASE_FLOAT_ARITHMETIC_STUBS(Mul) +BASE_FLOAT_ARITHMETIC_STUBS(Div) +BASE_FLOAT_ARITHMETIC_STUBS(Mod) + +#undef BASE_FLOAT_ARITHMETIC_STUBS + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( + T value, + RangeConstraint*) { + return -value; +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( + T value, + RangeConstraint*) { + return std::abs(value); +} + +// Floats carry around their validity state with them, but integers do not. So, +// we wrap the underlying value in a specialization in order to hide that detail +// and expose an interface via accessors. +enum NumericRepresentation { + NUMERIC_INTEGER, + NUMERIC_FLOATING, + NUMERIC_UNKNOWN +}; + +template <typename NumericType> +struct GetNumericRepresentation { + static const NumericRepresentation value = + std::numeric_limits<NumericType>::is_integer + ? NUMERIC_INTEGER + : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING + : NUMERIC_UNKNOWN); +}; + +template <typename T, NumericRepresentation type = + GetNumericRepresentation<T>::value> +class CheckedNumericState {}; + +// Integrals require quite a bit of additional housekeeping to manage state. +template <typename T> +class CheckedNumericState<T, NUMERIC_INTEGER> { + private: + T value_; + RangeConstraint validity_; + + public: + template <typename Src, NumericRepresentation type> + friend class CheckedNumericState; + + CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} + + template <typename Src> + CheckedNumericState(Src value, RangeConstraint validity) + : value_(static_cast<T>(value)), + validity_(GetRangeConstraint(validity | + DstRangeRelationToSrcRange<T>(value))) { + static_assert(std::numeric_limits<Src>::is_specialized, + "Argument must be numeric."); + } + + // Copy constructor. + template <typename Src> + CheckedNumericState(const CheckedNumericState<Src>& rhs) + : value_(static_cast<T>(rhs.value())), + validity_(GetRangeConstraint( + rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} + + template <typename Src> + explicit CheckedNumericState( + Src value, + typename std::enable_if<std::numeric_limits<Src>::is_specialized, + int>::type = 0) + : value_(static_cast<T>(value)), + validity_(DstRangeRelationToSrcRange<T>(value)) {} + + RangeConstraint validity() const { return validity_; } + T value() const { return value_; } +}; + +// Floating points maintain their own validity, but need translation wrappers. +template <typename T> +class CheckedNumericState<T, NUMERIC_FLOATING> { + private: + T value_; + + public: + template <typename Src, NumericRepresentation type> + friend class CheckedNumericState; + + CheckedNumericState() : value_(0.0) {} + + template <typename Src> + CheckedNumericState( + Src value, + RangeConstraint validity, + typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type = + 0) { + switch (DstRangeRelationToSrcRange<T>(value)) { + case RANGE_VALID: + value_ = static_cast<T>(value); + break; + + case RANGE_UNDERFLOW: + value_ = -std::numeric_limits<T>::infinity(); + break; + + case RANGE_OVERFLOW: + value_ = std::numeric_limits<T>::infinity(); + break; + + case RANGE_INVALID: + value_ = std::numeric_limits<T>::quiet_NaN(); + break; + + default: + NOTREACHED(); + } + } + + template <typename Src> + explicit CheckedNumericState( + Src value, + typename std::enable_if<std::numeric_limits<Src>::is_specialized, + int>::type = 0) + : value_(static_cast<T>(value)) {} + + // Copy constructor. + template <typename Src> + CheckedNumericState(const CheckedNumericState<Src>& rhs) + : value_(static_cast<T>(rhs.value())) {} + + RangeConstraint validity() const { + return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), + value_ >= -std::numeric_limits<T>::max()); + } + T value() const { return value_; } +}; + +// For integers less than 128-bit and floats 32-bit or larger, we can distil +// C/C++ arithmetic promotions down to two simple rules: +// 1. The type with the larger maximum exponent always takes precedence. +// 2. The resulting type must be promoted to at least an int. +// The following template specializations implement that promotion logic. +enum ArithmeticPromotionCategory { + LEFT_PROMOTION, + RIGHT_PROMOTION, + DEFAULT_PROMOTION +}; + +template <typename Lhs, + typename Rhs = Lhs, + ArithmeticPromotionCategory Promotion = + (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) + ? (MaxExponent<Lhs>::value > MaxExponent<int>::value + ? LEFT_PROMOTION + : DEFAULT_PROMOTION) + : (MaxExponent<Rhs>::value > MaxExponent<int>::value + ? RIGHT_PROMOTION + : DEFAULT_PROMOTION) > +struct ArithmeticPromotion; + +template <typename Lhs, typename Rhs> +struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { + typedef Lhs type; +}; + +template <typename Lhs, typename Rhs> +struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { + typedef Rhs type; +}; + +template <typename Lhs, typename Rhs> +struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> { + typedef int type; +}; + +// We can statically check if operations on the provided types can wrap, so we +// can skip the checked operations if they're not needed. So, for an integer we +// care if the destination type preserves the sign and is twice the width of +// the source. +template <typename T, typename Lhs, typename Rhs> +struct IsIntegerArithmeticSafe { + static const bool value = !std::numeric_limits<T>::is_iec559 && + StaticDstRangeRelationToSrcRange<T, Lhs>::value == + NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Lhs)) && + StaticDstRangeRelationToSrcRange<T, Rhs>::value != + NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Rhs)); +}; + +} // namespace internal +} // namespace base + +#endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ diff --git a/third_party/chromium/base/numerics/safe_numerics_unittest.cc b/third_party/chromium/base/numerics/safe_numerics_unittest.cc new file mode 100644 index 0000000..96b579a --- /dev/null +++ b/third_party/chromium/base/numerics/safe_numerics_unittest.cc @@ -0,0 +1,603 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS) +#include <mmintrin.h> +#endif +#include <stdint.h> + +#include <limits> + +#include <gtest/gtest.h> + +#include "base/compiler_specific.h" +#include "base/numerics/safe_conversions.h" +#include "base/numerics/safe_math.h" +#include "base/template_util.h" + +using std::numeric_limits; +using base::CheckedNumeric; +using base::checked_cast; +using base::SizeT; +using base::StrictNumeric; +using base::saturated_cast; +using base::strict_cast; +using base::internal::MaxExponent; +using base::internal::RANGE_VALID; +using base::internal::RANGE_INVALID; +using base::internal::RANGE_OVERFLOW; +using base::internal::RANGE_UNDERFLOW; +using std::enable_if; + +// These tests deliberately cause arithmetic overflows. If the compiler is +// aggressive enough, it can const fold these overflows. Disable warnings about +// overflows for const expressions. +#if defined(OS_WIN) +#pragma warning(disable:4756) +#endif + +// Helper macros to wrap displaying the conversion types and line numbers. +#define TEST_EXPECTED_VALIDITY(expected, actual) \ + EXPECT_EQ(expected, CheckedNumeric<Dst>(actual).validity()) \ + << "Result test: Value " << +(actual).ValueUnsafe() << " as " << dst \ + << " on line " << line; + +#define TEST_EXPECTED_VALUE(expected, actual) \ + EXPECT_EQ(static_cast<Dst>(expected), \ + CheckedNumeric<Dst>(actual).ValueUnsafe()) \ + << "Result test: Value " << +((actual).ValueUnsafe()) << " as " << dst \ + << " on line " << line; + +// Signed integer arithmetic. +template <typename Dst> +static void TestSpecializedArithmetic( + const char* dst, + int line, + typename enable_if< + numeric_limits<Dst>::is_integer&& numeric_limits<Dst>::is_signed, + int>::type = 0) { + typedef numeric_limits<Dst> DstLimits; + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, + -CheckedNumeric<Dst>(DstLimits::min())); + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, + CheckedNumeric<Dst>(DstLimits::min()).Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs()); + + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric<Dst>(DstLimits::max()) + -1); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric<Dst>(DstLimits::min()) + -1); + TEST_EXPECTED_VALIDITY( + RANGE_UNDERFLOW, + CheckedNumeric<Dst>(-DstLimits::max()) + -DstLimits::max()); + + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric<Dst>(DstLimits::min()) - 1); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric<Dst>(DstLimits::min()) - -1); + TEST_EXPECTED_VALIDITY( + RANGE_OVERFLOW, + CheckedNumeric<Dst>(DstLimits::max()) - -DstLimits::max()); + TEST_EXPECTED_VALIDITY( + RANGE_UNDERFLOW, + CheckedNumeric<Dst>(-DstLimits::max()) - DstLimits::max()); + + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric<Dst>(DstLimits::min()) * 2); + + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, + CheckedNumeric<Dst>(DstLimits::min()) / -1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) / 2); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); + TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % 2); + TEST_EXPECTED_VALIDITY(RANGE_INVALID, CheckedNumeric<Dst>(-1) % -2); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); + CheckedNumeric<Dst> checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); +} + +// Unsigned integer arithmetic. +template <typename Dst> +static void TestSpecializedArithmetic( + const char* dst, + int line, + typename enable_if< + numeric_limits<Dst>::is_integer && !numeric_limits<Dst>::is_signed, + int>::type = 0) { + typedef numeric_limits<Dst> DstLimits; + TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min())); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric<Dst>(DstLimits::min()).Abs()); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric<Dst>(DstLimits::min()) + -1); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, + CheckedNumeric<Dst>(DstLimits::min()) - 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) * 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) % 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); + CheckedNumeric<Dst> checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); +} + +// Floating point arithmetic. +template <typename Dst> +void TestSpecializedArithmetic( + const char* dst, + int line, + typename enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) { + typedef numeric_limits<Dst> DstLimits; + TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min())); + + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric<Dst>(DstLimits::min()).Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs()); + + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric<Dst>(DstLimits::min()) + -1); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric<Dst>(DstLimits::max()) + 1); + TEST_EXPECTED_VALIDITY( + RANGE_UNDERFLOW, + CheckedNumeric<Dst>(-DstLimits::max()) + -DstLimits::max()); + + TEST_EXPECTED_VALIDITY( + RANGE_OVERFLOW, + CheckedNumeric<Dst>(DstLimits::max()) - -DstLimits::max()); + TEST_EXPECTED_VALIDITY( + RANGE_UNDERFLOW, + CheckedNumeric<Dst>(-DstLimits::max()) - DstLimits::max()); + + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric<Dst>(DstLimits::min()) * 2); + + TEST_EXPECTED_VALUE(-0.5, CheckedNumeric<Dst>(-1.0) / 2); + EXPECT_EQ(static_cast<Dst>(1.0), CheckedNumeric<Dst>(1.0).ValueFloating()); +} + +// Generic arithmetic tests. +template <typename Dst> +static void TestArithmetic(const char* dst, int line) { + typedef numeric_limits<Dst> DstLimits; + + EXPECT_EQ(true, CheckedNumeric<Dst>().IsValid()); + EXPECT_EQ(false, + CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) * + DstLimits::max()).IsValid()); + EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDie()); + EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDefault(1)); + EXPECT_EQ(static_cast<Dst>(1), + CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) * + DstLimits::max()).ValueOrDefault(1)); + + // Test the operator combinations. + TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(2, 1 + CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, 1 - CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, 1 * CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, 1 / CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1); + CheckedNumeric<Dst> checked_dst = 1; + TEST_EXPECTED_VALUE(2, checked_dst += 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst -= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst *= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst /= 1); + + // Generic negation. + TEST_EXPECTED_VALUE(0, -CheckedNumeric<Dst>()); + TEST_EXPECTED_VALUE(-1, -CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, -CheckedNumeric<Dst>(-1)); + TEST_EXPECTED_VALUE(static_cast<Dst>(DstLimits::max() * -1), + -CheckedNumeric<Dst>(DstLimits::max())); + + // Generic absolute value. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>().Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).Abs()); + TEST_EXPECTED_VALUE(DstLimits::max(), + CheckedNumeric<Dst>(DstLimits::max()).Abs()); + + // Generic addition. + TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>() + 1)); + TEST_EXPECTED_VALUE(2, (CheckedNumeric<Dst>(1) + 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) + 1)); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric<Dst>(DstLimits::min()) + 1); + TEST_EXPECTED_VALIDITY( + RANGE_OVERFLOW, CheckedNumeric<Dst>(DstLimits::max()) + DstLimits::max()); + + // Generic subtraction. + TEST_EXPECTED_VALUE(-1, (CheckedNumeric<Dst>() - 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(1) - 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) - 1)); + TEST_EXPECTED_VALIDITY(RANGE_VALID, + CheckedNumeric<Dst>(DstLimits::max()) - 1); + + // Generic multiplication. + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>() * 1)); + TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>(1) * 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) * 2)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * -1)); + TEST_EXPECTED_VALIDITY( + RANGE_OVERFLOW, CheckedNumeric<Dst>(DstLimits::max()) * DstLimits::max()); + + // Generic division. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() / 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1); + TEST_EXPECTED_VALUE(DstLimits::min() / 2, + CheckedNumeric<Dst>(DstLimits::min()) / 2); + TEST_EXPECTED_VALUE(DstLimits::max() / 2, + CheckedNumeric<Dst>(DstLimits::max()) / 2); + + TestSpecializedArithmetic<Dst>(dst, line); +} + +// Helper macro to wrap displaying the conversion types and line numbers. +#define TEST_ARITHMETIC(Dst) TestArithmetic<Dst>(#Dst, __LINE__) + +TEST(SafeNumerics, SignedIntegerMath) { + TEST_ARITHMETIC(int8_t); + TEST_ARITHMETIC(int); + TEST_ARITHMETIC(intptr_t); + TEST_ARITHMETIC(intmax_t); +} + +TEST(SafeNumerics, UnsignedIntegerMath) { + TEST_ARITHMETIC(uint8_t); + TEST_ARITHMETIC(unsigned int); + TEST_ARITHMETIC(uintptr_t); + TEST_ARITHMETIC(uintmax_t); +} + +TEST(SafeNumerics, FloatingPointMath) { + TEST_ARITHMETIC(float); + TEST_ARITHMETIC(double); +} + +// Enumerates the five different conversions types we need to test. +enum NumericConversionType { + SIGN_PRESERVING_VALUE_PRESERVING, + SIGN_PRESERVING_NARROW, + SIGN_TO_UNSIGN_WIDEN_OR_EQUAL, + SIGN_TO_UNSIGN_NARROW, + UNSIGN_TO_SIGN_NARROW_OR_EQUAL, +}; + +// Template covering the different conversion tests. +template <typename Dst, typename Src, NumericConversionType conversion> +struct TestNumericConversion {}; + +// EXPECT_EQ wrappers providing specific detail on test failures. +#define TEST_EXPECTED_RANGE(expected, actual) \ + EXPECT_EQ(expected, base::internal::DstRangeRelationToSrcRange<Dst>(actual)) \ + << "Conversion test: " << src << " value " << actual << " to " << dst \ + << " on line " << line; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> { + static void Test(const char *dst, const char *src, int line) { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + // Integral to floating. + static_assert((DstLimits::is_iec559 && SrcLimits::is_integer) || + // Not floating to integral and... + (!(DstLimits::is_integer && SrcLimits::is_iec559) && + // Same sign, same numeric, source is narrower or same. + ((SrcLimits::is_signed == DstLimits::is_signed && + sizeof(Dst) >= sizeof(Src)) || + // Or signed destination and source is smaller + (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))), + "Comparison must be sign preserving and value preserving"); + + const CheckedNumeric<Dst> checked_dst = SrcLimits::max(); + ; + TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst); + if (MaxExponent<Dst>::value > MaxExponent<Src>::value) { + if (MaxExponent<Dst>::value >= MaxExponent<Src>::value * 2 - 1) { + // At least twice larger type. + TEST_EXPECTED_VALIDITY(RANGE_VALID, SrcLimits::max() * checked_dst); + + } else { // Larger, but not at least twice as large. + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, SrcLimits::max() * checked_dst); + TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst + 1); + } + } else { // Same width type. + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + 1); + } + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + if (SrcLimits::is_iec559) { + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max() * static_cast<Src>(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + } else if (numeric_limits<Src>::is_signed) { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + } +}; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> { + static void Test(const char *dst, const char *src, int line) { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + static_assert(SrcLimits::is_signed == DstLimits::is_signed, + "Destination and source sign must be the same"); + static_assert(sizeof(Dst) < sizeof(Src) || + (DstLimits::is_integer && SrcLimits::is_iec559), + "Destination must be narrower than source"); + + const CheckedNumeric<Dst> checked_dst; + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst - SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + if (SrcLimits::is_iec559) { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + } else if (SrcLimits::is_signed) { + TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); + } else { + TEST_EXPECTED_VALIDITY(RANGE_INVALID, checked_dst - static_cast<Src>(1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + } +}; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> { + static void Test(const char *dst, const char *src, int line) { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + static_assert(sizeof(Dst) >= sizeof(Src), + "Destination must be equal or wider than source."); + static_assert(SrcLimits::is_signed, "Source must be signed"); + static_assert(!DstLimits::is_signed, "Destination must be unsigned"); + + const CheckedNumeric<Dst> checked_dst; + TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + static_cast<Src>(-1)); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1)); + } +}; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> { + static void Test(const char *dst, const char *src, int line) { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + static_assert((DstLimits::is_integer && SrcLimits::is_iec559) || + (sizeof(Dst) < sizeof(Src)), + "Destination must be narrower than source."); + static_assert(SrcLimits::is_signed, "Source must be signed."); + static_assert(!DstLimits::is_signed, "Destination must be unsigned."); + + const CheckedNumeric<Dst> checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + static_cast<Src>(-1)); + TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1)); + if (SrcLimits::is_iec559) { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + } else { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + } + } +}; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> { + static void Test(const char *dst, const char *src, int line) { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + static_assert(sizeof(Dst) <= sizeof(Src), + "Destination must be narrower or equal to source."); + static_assert(!SrcLimits::is_signed, "Source must be unsigned."); + static_assert(DstLimits::is_signed, "Destination must be signed."); + + const CheckedNumeric<Dst> checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); + TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(SrcLimits::min(), checked_dst + SrcLimits::min()); + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + } +}; + +// Helper macro to wrap displaying the conversion types and line numbers +#define TEST_NUMERIC_CONVERSION(d, s, t) \ + TestNumericConversion<d, s, t>::Test(#d, #s, __LINE__) + +TEST(SafeNumerics, IntMinOperations) { + TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int8_t, float, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, float, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, IntOperations) { + TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, unsigned int, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, uint8_t, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int, float, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int, double, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, float, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, double, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, IntMaxOperations) { + TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, unsigned int, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(intmax_t, float, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(intmax_t, double, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(uintmax_t, float, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uintmax_t, double, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, FloatOperations) { + TEST_NUMERIC_CONVERSION(float, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, uintmax_t, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, unsigned int, + SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(float, double, SIGN_PRESERVING_NARROW); +} + +TEST(SafeNumerics, DoubleOperations) { + TEST_NUMERIC_CONVERSION(double, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, uintmax_t, + SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, unsigned int, + SIGN_PRESERVING_VALUE_PRESERVING); +} + +TEST(SafeNumerics, SizeTOperations) { + TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, CastTests) { +// MSVC catches and warns that we're forcing saturation in these tests. +// Since that's intentional, we need to shut this warning off. +#if defined(COMPILER_MSVC) +#pragma warning(disable : 4756) +#endif + + int small_positive = 1; + int small_negative = -1; + double double_small = 1.0; + double double_large = numeric_limits<double>::max(); + double double_infinity = numeric_limits<float>::infinity(); + double double_large_int = numeric_limits<int>::max(); + double double_small_int = numeric_limits<int>::min(); + + // Just test that the casts compile, since the other tests cover logic. + EXPECT_EQ(0, checked_cast<int>(static_cast<size_t>(0))); + EXPECT_EQ(0, strict_cast<int>(static_cast<char>(0))); + EXPECT_EQ(0, strict_cast<int>(static_cast<unsigned char>(0))); + EXPECT_EQ(0U, strict_cast<unsigned>(static_cast<unsigned char>(0))); + EXPECT_EQ(1ULL, static_cast<uint64_t>(StrictNumeric<size_t>(1U))); + EXPECT_EQ(1ULL, static_cast<uint64_t>(SizeT(1U))); + EXPECT_EQ(1U, static_cast<size_t>(StrictNumeric<unsigned>(1U))); + + EXPECT_TRUE(CheckedNumeric<uint64_t>(StrictNumeric<unsigned>(1U)).IsValid()); + EXPECT_TRUE(CheckedNumeric<int>(StrictNumeric<unsigned>(1U)).IsValid()); + EXPECT_FALSE(CheckedNumeric<unsigned>(StrictNumeric<int>(-1)).IsValid()); + + // These casts and coercions will fail to compile: + // EXPECT_EQ(0, strict_cast<int>(static_cast<size_t>(0))); + // EXPECT_EQ(0, strict_cast<size_t>(static_cast<int>(0))); + // EXPECT_EQ(1ULL, StrictNumeric<size_t>(1)); + // EXPECT_EQ(1, StrictNumeric<size_t>(1U)); + + // Test various saturation corner cases. + EXPECT_EQ(saturated_cast<int>(small_negative), + static_cast<int>(small_negative)); + EXPECT_EQ(saturated_cast<int>(small_positive), + static_cast<int>(small_positive)); + EXPECT_EQ(saturated_cast<unsigned>(small_negative), + static_cast<unsigned>(0)); + EXPECT_EQ(saturated_cast<int>(double_small), + static_cast<int>(double_small)); + EXPECT_EQ(saturated_cast<int>(double_large), numeric_limits<int>::max()); + EXPECT_EQ(saturated_cast<float>(double_large), double_infinity); + EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity); + EXPECT_EQ(numeric_limits<int>::min(), saturated_cast<int>(double_small_int)); + EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int)); +} + diff --git a/third_party/chromium/base/observer_list.h b/third_party/chromium/base/observer_list.h new file mode 100644 index 0000000..3baf910 --- /dev/null +++ b/third_party/chromium/base/observer_list.h @@ -0,0 +1,242 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_OBSERVER_LIST_H_ +#define BASE_OBSERVER_LIST_H_ + +#include <algorithm> +#include <limits> +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/memory/weak_ptr.h" + +/////////////////////////////////////////////////////////////////////////////// +// +// OVERVIEW: +// +// A container for a list of observers. Unlike a normal STL vector or list, +// this container can be modified during iteration without invalidating the +// iterator. So, it safely handles the case of an observer removing itself +// or other observers from the list while observers are being notified. +// +// TYPICAL USAGE: +// +// class MyWidget { +// public: +// ... +// +// class Observer { +// public: +// virtual void OnFoo(MyWidget* w) = 0; +// virtual void OnBar(MyWidget* w, int x, int y) = 0; +// }; +// +// void AddObserver(Observer* obs) { +// observer_list_.AddObserver(obs); +// } +// +// void RemoveObserver(Observer* obs) { +// observer_list_.RemoveObserver(obs); +// } +// +// void NotifyFoo() { +// FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this)); +// } +// +// void NotifyBar(int x, int y) { +// FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y)); +// } +// +// private: +// base::ObserverList<Observer> observer_list_; +// }; +// +// +/////////////////////////////////////////////////////////////////////////////// + +namespace base { + +template <class ObserverType> +class ObserverListBase + : public SupportsWeakPtr<ObserverListBase<ObserverType>> { + public: + // Enumeration of which observers are notified. + enum NotificationType { + // Specifies that any observers added during notification are notified. + // This is the default type if non type is provided to the constructor. + NOTIFY_ALL, + + // Specifies that observers added while sending out notification are not + // notified. + NOTIFY_EXISTING_ONLY + }; + + // An iterator class that can be used to access the list of observers. See + // also the FOR_EACH_OBSERVER macro defined below. + class Iterator { + public: + explicit Iterator(ObserverListBase<ObserverType>* list); + ~Iterator(); + ObserverType* GetNext(); + + private: + WeakPtr<ObserverListBase<ObserverType>> list_; + size_t index_; + size_t max_index_; + }; + + ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {} + explicit ObserverListBase(NotificationType type) + : notify_depth_(0), type_(type) {} + + // Add an observer to the list. An observer should not be added to + // the same list more than once. + void AddObserver(ObserverType* obs); + + // Remove an observer from the list if it is in the list. + void RemoveObserver(ObserverType* obs); + + // Determine whether a particular observer is in the list. + bool HasObserver(const ObserverType* observer) const; + + void Clear(); + + protected: + size_t size() const { return observers_.size(); } + + void Compact(); + + private: + typedef std::vector<ObserverType*> ListType; + + ListType observers_; + int notify_depth_; + NotificationType type_; + + friend class ObserverListBase::Iterator; + + DISALLOW_COPY_AND_ASSIGN(ObserverListBase); +}; + +template <class ObserverType> +ObserverListBase<ObserverType>::Iterator::Iterator( + ObserverListBase<ObserverType>* list) + : list_(list->AsWeakPtr()), + index_(0), + max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max() + : list->observers_.size()) { + ++list_->notify_depth_; +} + +template <class ObserverType> +ObserverListBase<ObserverType>::Iterator::~Iterator() { + if (list_.get() && --list_->notify_depth_ == 0) + list_->Compact(); +} + +template <class ObserverType> +ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() { + if (!list_.get()) + return nullptr; + ListType& observers = list_->observers_; + // Advance if the current element is null + size_t max_index = std::min(max_index_, observers.size()); + while (index_ < max_index && !observers[index_]) + ++index_; + return index_ < max_index ? observers[index_++] : nullptr; +} + +template <class ObserverType> +void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) { + DCHECK(obs); + if (std::find(observers_.begin(), observers_.end(), obs) + != observers_.end()) { + NOTREACHED() << "Observers can only be added once!"; + return; + } + observers_.push_back(obs); +} + +template <class ObserverType> +void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) { + DCHECK(obs); + typename ListType::iterator it = + std::find(observers_.begin(), observers_.end(), obs); + if (it != observers_.end()) { + if (notify_depth_) { + *it = nullptr; + } else { + observers_.erase(it); + } + } +} + +template <class ObserverType> +bool ObserverListBase<ObserverType>::HasObserver( + const ObserverType* observer) const { + for (size_t i = 0; i < observers_.size(); ++i) { + if (observers_[i] == observer) + return true; + } + return false; +} + +template <class ObserverType> +void ObserverListBase<ObserverType>::Clear() { + if (notify_depth_) { + for (typename ListType::iterator it = observers_.begin(); + it != observers_.end(); ++it) { + *it = nullptr; + } + } else { + observers_.clear(); + } +} + +template <class ObserverType> +void ObserverListBase<ObserverType>::Compact() { + observers_.erase( + std::remove(observers_.begin(), observers_.end(), nullptr), + observers_.end()); +} + +template <class ObserverType, bool check_empty = false> +class ObserverList : public ObserverListBase<ObserverType> { + public: + typedef typename ObserverListBase<ObserverType>::NotificationType + NotificationType; + + ObserverList() {} + explicit ObserverList(NotificationType type) + : ObserverListBase<ObserverType>(type) {} + + ~ObserverList() { + // When check_empty is true, assert that the list is empty on destruction. + if (check_empty) { + ObserverListBase<ObserverType>::Compact(); + DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U); + } + } + + bool might_have_observers() const { + return ObserverListBase<ObserverType>::size() != 0; + } +}; + +#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \ + do { \ + if ((observer_list).might_have_observers()) { \ + base::ObserverListBase<ObserverType>::Iterator it_inside_observer_macro( \ + &observer_list); \ + ObserverType* obs; \ + while ((obs = it_inside_observer_macro.GetNext()) != nullptr) \ + obs->func; \ + } \ + } while (0) + +} // namespace base + +#endif // BASE_OBSERVER_LIST_H_ diff --git a/third_party/chromium/base/observer_list_unittest.cc b/third_party/chromium/base/observer_list_unittest.cc new file mode 100644 index 0000000..8af999a --- /dev/null +++ b/third_party/chromium/base/observer_list_unittest.cc @@ -0,0 +1,188 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/observer_list.h" + +#include <vector> + +#include <gtest/gtest.h> + +#include "base/compiler_specific.h" +#include "base/location.h" +#include "base/memory/weak_ptr.h" + +namespace base { +namespace { + +class Foo { + public: + virtual void Observe(int x) = 0; + virtual ~Foo() {} +}; + +class Adder : public Foo { + public: + explicit Adder(int scaler) : total(0), scaler_(scaler) {} + void Observe(int x) override { total += x * scaler_; } + ~Adder() override {} + int total; + + private: + int scaler_; +}; + +class Disrupter : public Foo { + public: + Disrupter(ObserverList<Foo>* list, Foo* doomed) + : list_(list), + doomed_(doomed) { + } + ~Disrupter() override {} + void Observe(int x) override { list_->RemoveObserver(doomed_); } + + private: + ObserverList<Foo>* list_; + Foo* doomed_; +}; + +template <typename ObserverListType> +class AddInObserve : public Foo { + public: + explicit AddInObserve(ObserverListType* observer_list) + : added(false), + observer_list(observer_list), + adder(1) { + } + + void Observe(int x) override { + if (!added) { + added = true; + observer_list->AddObserver(&adder); + } + } + + bool added; + ObserverListType* observer_list; + Adder adder; +}; + + +TEST(ObserverListTest, BasicTest) { + ObserverList<Foo> observer_list; + Adder a(1), b(-1), c(1), d(-1), e(-1); + Disrupter evil(&observer_list, &c); + + observer_list.AddObserver(&a); + observer_list.AddObserver(&b); + + EXPECT_TRUE(observer_list.HasObserver(&a)); + EXPECT_FALSE(observer_list.HasObserver(&c)); + + FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); + + observer_list.AddObserver(&evil); + observer_list.AddObserver(&c); + observer_list.AddObserver(&d); + + // Removing an observer not in the list should do nothing. + observer_list.RemoveObserver(&e); + + FOR_EACH_OBSERVER(Foo, observer_list, Observe(10)); + + EXPECT_EQ(20, a.total); + EXPECT_EQ(-20, b.total); + EXPECT_EQ(0, c.total); + EXPECT_EQ(-10, d.total); + EXPECT_EQ(0, e.total); +} + +TEST(ObserverListTest, Existing) { + ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); + Adder a(1); + AddInObserve<ObserverList<Foo> > b(&observer_list); + + observer_list.AddObserver(&a); + observer_list.AddObserver(&b); + + FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); + + EXPECT_TRUE(b.added); + // B's adder should not have been notified because it was added during + // notification. + EXPECT_EQ(0, b.adder.total); + + // Notify again to make sure b's adder is notified. + FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); + EXPECT_EQ(1, b.adder.total); +} + +class AddInClearObserve : public Foo { + public: + explicit AddInClearObserve(ObserverList<Foo>* list) + : list_(list), added_(false), adder_(1) {} + + void Observe(int /* x */) override { + list_->Clear(); + list_->AddObserver(&adder_); + added_ = true; + } + + bool added() const { return added_; } + const Adder& adder() const { return adder_; } + + private: + ObserverList<Foo>* const list_; + + bool added_; + Adder adder_; +}; + +TEST(ObserverListTest, ClearNotifyAll) { + ObserverList<Foo> observer_list; + AddInClearObserve a(&observer_list); + + observer_list.AddObserver(&a); + + FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); + EXPECT_TRUE(a.added()); + EXPECT_EQ(1, a.adder().total) + << "Adder should observe once and have sum of 1."; +} + +TEST(ObserverListTest, ClearNotifyExistingOnly) { + ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); + AddInClearObserve a(&observer_list); + + observer_list.AddObserver(&a); + + FOR_EACH_OBSERVER(Foo, observer_list, Observe(1)); + EXPECT_TRUE(a.added()); + EXPECT_EQ(0, a.adder().total) + << "Adder should not observe, so sum should still be 0."; +} + +class ListDestructor : public Foo { + public: + explicit ListDestructor(ObserverList<Foo>* list) : list_(list) {} + ~ListDestructor() override {} + + void Observe(int x) override { delete list_; } + + private: + ObserverList<Foo>* list_; +}; + + +TEST(ObserverListTest, IteratorOutlivesList) { + ObserverList<Foo>* observer_list = new ObserverList<Foo>; + ListDestructor a(observer_list); + observer_list->AddObserver(&a); + + FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0)); + // If this test fails, there'll be Valgrind errors when this function goes out + // of scope. +} + +} // namespace +} // namespace base diff --git a/third_party/chromium/base/posix/eintr_wrapper.h b/third_party/chromium/base/posix/eintr_wrapper.h new file mode 100644 index 0000000..27de8fc --- /dev/null +++ b/third_party/chromium/base/posix/eintr_wrapper.h @@ -0,0 +1,67 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This provides a wrapper around system calls which may be interrupted by a +// signal and return EINTR. See man 7 signal. +// To prevent long-lasting loops (which would likely be a bug, such as a signal +// that should be masked) to go unnoticed, there is a limit after which the +// caller will nonetheless see an EINTR in Debug builds. +// +// On Windows, this wrapper macro does nothing. +// +// Don't wrap close calls in HANDLE_EINTR. Use IGNORE_EINTR if the return +// value of close is significant. See http://crbug.com/269623. + +#ifndef BASE_POSIX_EINTR_WRAPPER_H_ +#define BASE_POSIX_EINTR_WRAPPER_H_ + +#include "base/build/build_config.h" + +#if defined(OS_POSIX) + +#include <errno.h> + +#if defined(NDEBUG) + +#define HANDLE_EINTR(x) ({ \ + decltype(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + } while (eintr_wrapper_result == -1 && errno == EINTR); \ + eintr_wrapper_result; \ +}) + +#else + +#define HANDLE_EINTR(x) ({ \ + int eintr_wrapper_counter = 0; \ + decltype(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + } while (eintr_wrapper_result == -1 && errno == EINTR && \ + eintr_wrapper_counter++ < 100); \ + eintr_wrapper_result; \ +}) + +#endif // NDEBUG + +#define IGNORE_EINTR(x) ({ \ + decltype(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + if (eintr_wrapper_result == -1 && errno == EINTR) { \ + eintr_wrapper_result = 0; \ + } \ + } while (0); \ + eintr_wrapper_result; \ +}) + +#else + +#define HANDLE_EINTR(x) (x) +#define IGNORE_EINTR(x) (x) + +#endif // OS_POSIX + +#endif // BASE_POSIX_EINTR_WRAPPER_H_ diff --git a/third_party/chromium/base/rand_util.cc b/third_party/chromium/base/rand_util.cc new file mode 100644 index 0000000..a55cdbd --- /dev/null +++ b/third_party/chromium/base/rand_util.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/rand_util.h" + +#include <math.h> +#include <stdint.h> + +#include <algorithm> +#include <limits> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/strings/string_util.h" + +namespace base { + +int RandInt(int min, int max) { + DCHECK_LE(min, max); + + uint64 range = static_cast<uint64>(max) - min + 1; + int result = min + static_cast<int>(base::RandGenerator(range)); + DCHECK_GE(result, min); + DCHECK_LE(result, max); + return result; +} + +double RandDouble() { + return BitsToOpenEndedUnitInterval(base::RandUint64()); +} + +double BitsToOpenEndedUnitInterval(uint64 bits) { + // We try to get maximum precision by masking out as many bits as will fit + // in the target type's mantissa, and raising it to an appropriate power to + // produce output in the range [0, 1). For IEEE 754 doubles, the mantissa + // is expected to accommodate 53 bits. + + COMPILE_ASSERT(std::numeric_limits<double>::radix == 2, otherwise_use_scalbn); + static const int kBits = std::numeric_limits<double>::digits; + uint64 random_bits = bits & ((UINT64_C(1) << kBits) - 1); + double result = ldexp(static_cast<double>(random_bits), -1 * kBits); + DCHECK_GE(result, 0.0); + DCHECK_LT(result, 1.0); + return result; +} + +uint64 RandGenerator(uint64 range) { + DCHECK_GT(range, 0u); + // We must discard random results above this number, as they would + // make the random generator non-uniform (consider e.g. if + // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice + // as likely as a result of 3 or 4). + uint64 max_acceptable_value = + (std::numeric_limits<uint64>::max() / range) * range - 1; + + uint64 value; + do { + value = base::RandUint64(); + } while (value > max_acceptable_value); + + return value % range; +} + +std::string RandBytesAsString(size_t length) { + DCHECK_GT(length, 0u); + std::string result(length, ' '); + RandBytes(&result[0], length); + return result; +} + +} // namespace base diff --git a/third_party/chromium/base/rand_util.h b/third_party/chromium/base/rand_util.h new file mode 100644 index 0000000..e29a9ce --- /dev/null +++ b/third_party/chromium/base/rand_util.h @@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_RAND_UTIL_H_ +#define BASE_RAND_UTIL_H_ + +#include <string> + +#include "base/base_export.h" +#include "base/basictypes.h" + +namespace base { + +// Returns a random number in range [0, kuint64max]. Thread-safe. +uint64 RandUint64(); + +// Returns a random number between min and max (inclusive). Thread-safe. +int RandInt(int min, int max); + +// Returns a random number in range [0, range). Thread-safe. +// +// Note that this can be used as an adapter for std::random_shuffle(): +// Given a pre-populated |std::vector<int> myvector|, shuffle it as +// std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator); +uint64 RandGenerator(uint64 range); + +// Returns a random double in range [0, 1). Thread-safe. +double RandDouble(); + +// Given input |bits|, convert with maximum precision to a double in +// the range [0, 1). Thread-safe. +double BitsToOpenEndedUnitInterval(uint64 bits); + +// Fills |output_length| bytes of |output| with random data. +// +// WARNING: +// Do not use for security-sensitive purposes. +// See crypto/ for cryptographically secure random number generation APIs. +void RandBytes(void* output, size_t output_length); + +// Fills a string of length |length| with random data and returns it. +// |length| should be nonzero. +// +// Note that this is a variation of |RandBytes| with a different return type. +// The returned string is likely not ASCII/UTF-8. Use with care. +// +// WARNING: +// Do not use for security-sensitive purposes. +// See crypto/ for cryptographically secure random number generation APIs. +std::string RandBytesAsString(size_t length); + +} // namespace base + +#endif // BASE_RAND_UTIL_H_ diff --git a/third_party/chromium/base/rand_util_posix.cc b/third_party/chromium/base/rand_util_posix.cc new file mode 100644 index 0000000..76a5dab --- /dev/null +++ b/third_party/chromium/base/rand_util_posix.cc @@ -0,0 +1,60 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/rand_util.h" + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" + +namespace { + +class URandomFd { + public: + URandomFd() : fd_(open("/dev/urandom", O_RDONLY)) { + DCHECK_GE(fd_, 0) << "Cannot open /dev/urandom: " << errno; + } + + ~URandomFd() { close(fd_); } + + int fd() const { return fd_; } + + private: + const int fd_; +}; + +bool ReadFromFD(int fd, char* buffer, size_t bytes) { + size_t total_read = 0; + while (total_read < bytes) { + ssize_t bytes_read = + HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read)); + if (bytes_read <= 0) + break; + total_read += bytes_read; + } + return total_read == bytes; +} + +} // namespace + +namespace base { + +// NOTE: This function must be cryptographically secure. http://crbug.com/140076 +uint64 RandUint64() { + uint64 number; + RandBytes(&number, sizeof(number)); + return number; +} + +void RandBytes(void* output, size_t output_length) { + URandomFd urandom_fd; + const bool success = + ReadFromFD(urandom_fd.fd(), static_cast<char*>(output), output_length); + CHECK(success); +} + +} // namespace base diff --git a/third_party/chromium/base/rand_util_unittest.cc b/third_party/chromium/base/rand_util_unittest.cc new file mode 100644 index 0000000..384125b --- /dev/null +++ b/third_party/chromium/base/rand_util_unittest.cc @@ -0,0 +1,126 @@ +// 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/rand_util.h" + +#include <algorithm> +#include <limits> + +#include <gtest/gtest.h> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" + +namespace { + +const int kIntMin = std::numeric_limits<int>::min(); +const int kIntMax = std::numeric_limits<int>::max(); + +} // namespace + +TEST(RandUtilTest, SameMinAndMax) { + EXPECT_EQ(base::RandInt(0, 0), 0); + EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin); + EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax); +} + +TEST(RandUtilTest, RandDouble) { + // Force 64-bit precision, making sure we're not in a 80-bit FPU register. + volatile double number = base::RandDouble(); + EXPECT_GT(1.0, number); + EXPECT_LE(0.0, number); +} + +TEST(RandUtilTest, RandBytes) { + const size_t buffer_size = 50; + char buffer[buffer_size]; + memset(buffer, 0, buffer_size); + base::RandBytes(buffer, buffer_size); + std::sort(buffer, buffer + buffer_size); + // Probability of occurrence of less than 25 unique bytes in 50 random bytes + // is below 10^-25. + EXPECT_GT(std::unique(buffer, buffer + buffer_size) - buffer, 25); +} + +TEST(RandUtilTest, RandBytesAsString) { + std::string random_string = base::RandBytesAsString(1); + EXPECT_EQ(1U, random_string.size()); + random_string = base::RandBytesAsString(145); + EXPECT_EQ(145U, random_string.size()); + char accumulator = 0; + for (size_t i = 0; i < random_string.size(); ++i) + accumulator |= random_string[i]; + // In theory this test can fail, but it won't before the universe dies of + // heat death. + EXPECT_NE(0, accumulator); +} + +// Make sure that it is still appropriate to use RandGenerator in conjunction +// with std::random_shuffle(). +TEST(RandUtilTest, RandGeneratorForRandomShuffle) { + EXPECT_EQ(base::RandGenerator(1), 0U); + EXPECT_LE(std::numeric_limits<ptrdiff_t>::max(), + std::numeric_limits<int64>::max()); +} + +TEST(RandUtilTest, RandGeneratorIsUniform) { + // Verify that RandGenerator has a uniform distribution. This is a + // regression test that consistently failed when RandGenerator was + // implemented this way: + // + // return base::RandUint64() % max; + // + // A degenerate case for such an implementation is e.g. a top of + // range that is 2/3rds of the way to MAX_UINT64, in which case the + // bottom half of the range would be twice as likely to occur as the + // top half. A bit of calculus care of jar@ shows that the largest + // measurable delta is when the top of the range is 3/4ths of the + // way, so that's what we use in the test. + const uint64 kTopOfRange = (std::numeric_limits<uint64>::max() / 4ULL) * 3ULL; + const uint64 kExpectedAverage = kTopOfRange / 2ULL; + const uint64 kAllowedVariance = kExpectedAverage / 50ULL; // +/- 2% + const int kMinAttempts = 1000; + const int kMaxAttempts = 1000000; + + double cumulative_average = 0.0; + int count = 0; + while (count < kMaxAttempts) { + uint64 value = base::RandGenerator(kTopOfRange); + cumulative_average = (count * cumulative_average + value) / (count + 1); + + // Don't quit too quickly for things to start converging, or we may have + // a false positive. + if (count > kMinAttempts && + kExpectedAverage - kAllowedVariance < cumulative_average && + cumulative_average < kExpectedAverage + kAllowedVariance) { + break; + } + + ++count; + } + + ASSERT_LT(count, kMaxAttempts) << "Expected average was " << + kExpectedAverage << ", average ended at " << cumulative_average; +} + +TEST(RandUtilTest, RandUint64ProducesBothValuesOfAllBits) { + // This tests to see that our underlying random generator is good + // enough, for some value of good enough. + uint64 kAllZeros = 0ULL; + uint64 kAllOnes = ~kAllZeros; + uint64 found_ones = kAllZeros; + uint64 found_zeros = kAllOnes; + + for (size_t i = 0; i < 1000; ++i) { + uint64 value = base::RandUint64(); + found_ones |= value; + found_zeros &= value; + + if (found_zeros == kAllZeros && found_ones == kAllOnes) + return; + } + + FAIL() << "Didn't achieve all bit values in maximum number of tries."; +} diff --git a/third_party/chromium/base/scoped_clear_errno.h b/third_party/chromium/base/scoped_clear_errno.h new file mode 100644 index 0000000..7b972fc --- /dev/null +++ b/third_party/chromium/base/scoped_clear_errno.h @@ -0,0 +1,34 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_SCOPED_CLEAR_ERRNO_H_ +#define BASE_SCOPED_CLEAR_ERRNO_H_ + +#include <errno.h> + +#include "base/basictypes.h" + +namespace base { + +// Simple scoper that saves the current value of errno, resets it to 0, and on +// destruction puts the old value back. +class ScopedClearErrno { + public: + ScopedClearErrno() : old_errno_(errno) { + errno = 0; + } + ~ScopedClearErrno() { + if (errno == 0) + errno = old_errno_; + } + + private: + const int old_errno_; + + DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno); +}; + +} // namespace base + +#endif // BASE_SCOPED_CLEAR_ERRNO_H_ diff --git a/third_party/chromium/base/scoped_clear_errno_unittest.cc b/third_party/chromium/base/scoped_clear_errno_unittest.cc new file mode 100644 index 0000000..1666d7a --- /dev/null +++ b/third_party/chromium/base/scoped_clear_errno_unittest.cc @@ -0,0 +1,31 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <errno.h> + +#include <gtest/gtest.h> + +#include "base/scoped_clear_errno.h" + +namespace base { + +TEST(ScopedClearErrno, TestNoError) { + errno = 1; + { + ScopedClearErrno clear_error; + EXPECT_EQ(0, errno); + } + EXPECT_EQ(1, errno); +} + +TEST(ScopedClearErrno, TestError) { + errno = 1; + { + ScopedClearErrno clear_error; + errno = 2; + } + EXPECT_EQ(2, errno); +} + +} // namespace base diff --git a/third_party/chromium/base/scoped_observer.h b/third_party/chromium/base/scoped_observer.h new file mode 100644 index 0000000..422701b --- /dev/null +++ b/third_party/chromium/base/scoped_observer.h @@ -0,0 +1,61 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_SCOPED_OBSERVER_H_ +#define BASE_SCOPED_OBSERVER_H_ + +#include <algorithm> +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.h" + +// ScopedObserver is used to keep track of the set of sources an object has +// attached itself to as an observer. When ScopedObserver is destroyed it +// removes the object as an observer from all sources it has been added to. +template <class Source, class Observer> +class ScopedObserver { + public: + explicit ScopedObserver(Observer* observer) : observer_(observer) {} + + ~ScopedObserver() { + RemoveAll(); + } + + // Adds the object passed to the constructor as an observer on |source|. + void Add(Source* source) { + sources_.push_back(source); + source->AddObserver(observer_); + } + + // Remove the object passed to the constructor as an observer from |source|. + void Remove(Source* source) { + auto it = std::find(sources_.begin(), sources_.end(), source); + DCHECK(it != sources_.end()); + sources_.erase(it); + source->RemoveObserver(observer_); + } + + void RemoveAll() { + for (size_t i = 0; i < sources_.size(); ++i) + sources_[i]->RemoveObserver(observer_); + sources_.clear(); + } + + bool IsObserving(Source* source) const { + return std::find(sources_.begin(), sources_.end(), source) != + sources_.end(); + } + + bool IsObservingSources() const { return !sources_.empty(); } + + private: + Observer* observer_; + + std::vector<Source*> sources_; + + DISALLOW_COPY_AND_ASSIGN(ScopedObserver); +}; + +#endif // BASE_SCOPED_OBSERVER_H_ diff --git a/third_party/chromium/base/strings/string_number_conversions.cc b/third_party/chromium/base/strings/string_number_conversions.cc new file mode 100644 index 0000000..b5463fb --- /dev/null +++ b/third_party/chromium/base/strings/string_number_conversions.cc @@ -0,0 +1,466 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/string_number_conversions.h" + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <wctype.h> + +#include <limits> + +#include "base/logging.h" +#include "base/scoped_clear_errno.h" +#include "base/third_party/dmg_fp/dmg_fp.h" + +namespace base { + +namespace { + +template <typename STR, typename INT, typename UINT, bool NEG> +struct IntToStringT { + // This is to avoid a compiler warning about unary minus on unsigned type. + // For example, say you had the following code: + // template <typename INT> + // INT abs(INT value) { return value < 0 ? -value : value; } + // Even though if INT is unsigned, it's impossible for value < 0, so the + // unary minus will never be taken, the compiler will still generate a + // warning. We do a little specialization dance... + template <typename INT2, typename UINT2, bool NEG2> + struct ToUnsignedT {}; + + template <typename INT2, typename UINT2> + struct ToUnsignedT<INT2, UINT2, false> { + static UINT2 ToUnsigned(INT2 value) { + return static_cast<UINT2>(value); + } + }; + + template <typename INT2, typename UINT2> + struct ToUnsignedT<INT2, UINT2, true> { + static UINT2 ToUnsigned(INT2 value) { + return static_cast<UINT2>(value < 0 ? -value : value); + } + }; + + // This set of templates is very similar to the above templates, but + // for testing whether an integer is negative. + template <typename INT2, bool NEG2> + struct TestNegT {}; + template <typename INT2> + struct TestNegT<INT2, false> { + static bool TestNeg(INT2 value) { + // value is unsigned, and can never be negative. + return false; + } + }; + template <typename INT2> + struct TestNegT<INT2, true> { + static bool TestNeg(INT2 value) { + return value < 0; + } + }; + + static STR IntToString(INT value) { + // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4. + // So round up to allocate 3 output characters per byte, plus 1 for '-'. + const int kOutputBufSize = 3 * sizeof(INT) + 1; + + // Allocate the whole string right away, we will right back to front, and + // then return the substr of what we ended up using. + STR outbuf(kOutputBufSize, 0); + + bool is_neg = TestNegT<INT, NEG>::TestNeg(value); + // Even though is_neg will never be true when INT is parameterized as + // unsigned, even the presence of the unary operation causes a warning. + UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value); + + typename STR::iterator it(outbuf.end()); + do { + --it; + DCHECK(it != outbuf.begin()); + *it = static_cast<typename STR::value_type>((res % 10) + '0'); + res /= 10; + } while (res != 0); + if (is_neg) { + --it; + DCHECK(it != outbuf.begin()); + *it = static_cast<typename STR::value_type>('-'); + } + return STR(it, outbuf.end()); + } +}; + +// Utility to convert a character to a digit in a given base +template<typename CHAR, int BASE, bool BASE_LTE_10> class BaseCharToDigit { +}; + +// Faster specialization for bases <= 10 +template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> { + public: + static bool Convert(CHAR c, uint8* digit) { + if (c >= '0' && c < '0' + BASE) { + *digit = static_cast<uint8>(c - '0'); + return true; + } + return false; + } +}; + +// Specialization for bases where 10 < base <= 36 +template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> { + public: + static bool Convert(CHAR c, uint8* digit) { + if (c >= '0' && c <= '9') { + *digit = c - '0'; + } else if (c >= 'a' && c < 'a' + BASE - 10) { + *digit = c - 'a' + 10; + } else if (c >= 'A' && c < 'A' + BASE - 10) { + *digit = c - 'A' + 10; + } else { + return false; + } + return true; + } +}; + +template<int BASE, typename CHAR> bool CharToDigit(CHAR c, uint8* digit) { + return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit); +} + +// There is an IsWhitespace for wchars defined in string_util.h, but it is +// locale independent, whereas the functions we are replacing were +// locale-dependent. TBD what is desired, but for the moment let's not introduce +// a change in behaviour. +template<typename CHAR> class WhitespaceHelper { +}; + +template<> class WhitespaceHelper<char> { + public: + static bool Invoke(char c) { + return 0 != isspace(static_cast<unsigned char>(c)); + } +}; + +template<typename CHAR> bool LocalIsWhitespace(CHAR c) { + return WhitespaceHelper<CHAR>::Invoke(c); +} + +// IteratorRangeToNumberTraits should provide: +// - a typedef for iterator_type, the iterator type used as input. +// - a typedef for value_type, the target numeric type. +// - static functions min, max (returning the minimum and maximum permitted +// values) +// - constant kBase, the base in which to interpret the input +template<typename IteratorRangeToNumberTraits> +class IteratorRangeToNumber { + public: + typedef IteratorRangeToNumberTraits traits; + typedef typename traits::iterator_type const_iterator; + typedef typename traits::value_type value_type; + + // Generalized iterator-range-to-number conversion. + // + static bool Invoke(const_iterator begin, + const_iterator end, + value_type* output) { + bool valid = true; + + while (begin != end && LocalIsWhitespace(*begin)) { + valid = false; + ++begin; + } + + if (begin != end && *begin == '-') { + if (!std::numeric_limits<value_type>::is_signed) { + valid = false; + } else if (!Negative::Invoke(begin + 1, end, output)) { + valid = false; + } + } else { + if (begin != end && *begin == '+') { + ++begin; + } + if (!Positive::Invoke(begin, end, output)) { + valid = false; + } + } + + return valid; + } + + private: + // Sign provides: + // - a static function, CheckBounds, that determines whether the next digit + // causes an overflow/underflow + // - a static function, Increment, that appends the next digit appropriately + // according to the sign of the number being parsed. + template<typename Sign> + class Base { + public: + static bool Invoke(const_iterator begin, const_iterator end, + typename traits::value_type* output) { + *output = 0; + + if (begin == end) { + return false; + } + + // Note: no performance difference was found when using template + // specialization to remove this check in bases other than 16 + if (traits::kBase == 16 && end - begin > 2 && *begin == '0' && + (*(begin + 1) == 'x' || *(begin + 1) == 'X')) { + begin += 2; + } + + for (const_iterator current = begin; current != end; ++current) { + uint8 new_digit = 0; + + if (!CharToDigit<traits::kBase>(*current, &new_digit)) { + return false; + } + + if (current != begin) { + if (!Sign::CheckBounds(output, new_digit)) { + return false; + } + *output *= traits::kBase; + } + + Sign::Increment(new_digit, output); + } + return true; + } + }; + + class Positive : public Base<Positive> { + public: + static bool CheckBounds(value_type* output, uint8 new_digit) { + if (*output > static_cast<value_type>(traits::max() / traits::kBase) || + (*output == static_cast<value_type>(traits::max() / traits::kBase) && + new_digit > traits::max() % traits::kBase)) { + *output = traits::max(); + return false; + } + return true; + } + static void Increment(uint8 increment, value_type* output) { + *output += increment; + } + }; + + class Negative : public Base<Negative> { + public: + static bool CheckBounds(value_type* output, uint8 new_digit) { + if (*output < traits::min() / traits::kBase || + (*output == traits::min() / traits::kBase && + new_digit > 0 - traits::min() % traits::kBase)) { + *output = traits::min(); + return false; + } + return true; + } + static void Increment(uint8 increment, value_type* output) { + *output -= increment; + } + }; +}; + +template<typename ITERATOR, typename VALUE, int BASE> +class BaseIteratorRangeToNumberTraits { + public: + typedef ITERATOR iterator_type; + typedef VALUE value_type; + static value_type min() { + return std::numeric_limits<value_type>::min(); + } + static value_type max() { + return std::numeric_limits<value_type>::max(); + } + static const int kBase = BASE; +}; + +template<typename ITERATOR> +class BaseHexIteratorRangeToIntTraits + : public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> { +}; + +template<typename ITERATOR> +class BaseHexIteratorRangeToUIntTraits + : public BaseIteratorRangeToNumberTraits<ITERATOR, uint32, 16> { +}; + +template<typename ITERATOR> +class BaseHexIteratorRangeToInt64Traits + : public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> { +}; + +template<typename ITERATOR> +class BaseHexIteratorRangeToUInt64Traits + : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64, 16> { +}; + +typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator> + HexIteratorRangeToIntTraits; + +typedef BaseHexIteratorRangeToUIntTraits<StringPiece::const_iterator> + HexIteratorRangeToUIntTraits; + +typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator> + HexIteratorRangeToInt64Traits; + +typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator> + HexIteratorRangeToUInt64Traits; + +template<typename STR> +bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) { + DCHECK_EQ(output->size(), 0u); + size_t count = input.size(); + if (count == 0 || (count % 2) != 0) + return false; + for (uintptr_t i = 0; i < count / 2; ++i) { + uint8 msb = 0; // most significant 4 bits + uint8 lsb = 0; // least significant 4 bits + if (!CharToDigit<16>(input[i * 2], &msb) || + !CharToDigit<16>(input[i * 2 + 1], &lsb)) + return false; + output->push_back((msb << 4) | lsb); + } + return true; +} + +template <typename VALUE, int BASE> +class StringPieceToNumberTraits + : public BaseIteratorRangeToNumberTraits<StringPiece::const_iterator, + VALUE, + BASE> { +}; + +template <typename VALUE> +bool StringToIntImpl(const StringPiece& input, VALUE* output) { + return IteratorRangeToNumber<StringPieceToNumberTraits<VALUE, 10> >::Invoke( + input.begin(), input.end(), output); +} + +} // namespace + +std::string IntToString(int value) { + return IntToStringT<std::string, int, unsigned int, true>:: + IntToString(value); +} + +std::string UintToString(unsigned int value) { + return IntToStringT<std::string, unsigned int, unsigned int, false>:: + IntToString(value); +} + +std::string Int64ToString(int64 value) { + return IntToStringT<std::string, int64, uint64, true>::IntToString(value); +} + +std::string Uint64ToString(uint64 value) { + return IntToStringT<std::string, uint64, uint64, false>::IntToString(value); +} + +std::string SizeTToString(size_t value) { + return IntToStringT<std::string, size_t, size_t, false>::IntToString(value); +} + +std::string DoubleToString(double value) { + // According to g_fmt.cc, it is sufficient to declare a buffer of size 32. + char buffer[32]; + dmg_fp::g_fmt(buffer, value); + return std::string(buffer); +} + +bool StringToInt(const StringPiece& input, int* output) { + return StringToIntImpl(input, output); +} + +bool StringToUint(const StringPiece& input, unsigned* output) { + return StringToIntImpl(input, output); +} + +bool StringToInt64(const StringPiece& input, int64* output) { + return StringToIntImpl(input, output); +} + +bool StringToUint64(const StringPiece& input, uint64* output) { + return StringToIntImpl(input, output); +} + +bool StringToSizeT(const StringPiece& input, size_t* output) { + return StringToIntImpl(input, output); +} + +bool StringToDouble(const std::string& input, double* output) { + // Thread-safe? It is on at least Mac, Linux, and Windows. + ScopedClearErrno clear_errno; + + char* endptr = NULL; + *output = dmg_fp::strtod(input.c_str(), &endptr); + + // Cases to return false: + // - If errno is ERANGE, there was an overflow or underflow. + // - If the input string is empty, there was nothing to parse. + // - If endptr does not point to the end of the string, there are either + // characters remaining in the string after a parsed number, or the string + // does not begin with a parseable number. endptr is compared to the + // expected end given the string's stated length to correctly catch cases + // where the string contains embedded NUL characters. + // - If the first character is a space, there was leading whitespace + return errno == 0 && + !input.empty() && + input.c_str() + input.length() == endptr && + !isspace(input[0]); +} + +// Note: if you need to add String16ToDouble, first ask yourself if it's +// really necessary. If it is, probably the best implementation here is to +// convert to 8-bit and then use the 8-bit version. + +// Note: if you need to add an iterator range version of StringToDouble, first +// ask yourself if it's really necessary. If it is, probably the best +// implementation here is to instantiate a string and use the string version. + +std::string HexEncode(const void* bytes, size_t size) { + static const char kHexChars[] = "0123456789ABCDEF"; + + // Each input byte creates two output hex characters. + std::string ret(size * 2, '\0'); + + for (size_t i = 0; i < size; ++i) { + char b = reinterpret_cast<const char*>(bytes)[i]; + ret[(i * 2)] = kHexChars[(b >> 4) & 0xf]; + ret[(i * 2) + 1] = kHexChars[b & 0xf]; + } + return ret; +} + +bool HexStringToInt(const StringPiece& input, int* output) { + return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke( + input.begin(), input.end(), output); +} + +bool HexStringToUInt(const StringPiece& input, uint32* output) { + return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke( + input.begin(), input.end(), output); +} + +bool HexStringToInt64(const StringPiece& input, int64* output) { + return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke( + input.begin(), input.end(), output); +} + +bool HexStringToUInt64(const StringPiece& input, uint64* output) { + return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke( + input.begin(), input.end(), output); +} + +bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) { + return HexStringToBytesT(input, output); +} + +} // namespace base diff --git a/third_party/chromium/base/strings/string_number_conversions.h b/third_party/chromium/base/strings/string_number_conversions.h new file mode 100644 index 0000000..c68d0af --- /dev/null +++ b/third_party/chromium/base/strings/string_number_conversions.h @@ -0,0 +1,119 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_ +#define BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_ + +#include <string> +#include <vector> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/strings/string_piece.h" + +// ---------------------------------------------------------------------------- +// IMPORTANT MESSAGE FROM YOUR SPONSOR +// +// This file contains no "wstring" variants. New code should use string16. If +// you need to make old code work, use the UTF8 version and convert. Please do +// not add wstring variants. +// +// Please do not add "convenience" functions for converting strings to integers +// that return the value and ignore success/failure. That encourages people to +// write code that doesn't properly handle the error conditions. +// ---------------------------------------------------------------------------- + +namespace base { + +// Number -> string conversions ------------------------------------------------ + +std::string IntToString(int value); + +std::string UintToString(unsigned value); + +std::string Int64ToString(int64 value); + +std::string Uint64ToString(uint64 value); + +std::string SizeTToString(size_t value); + +// DoubleToString converts the double to a string format that ignores the +// locale. If you want to use locale specific formatting, use ICU. +std::string DoubleToString(double value); + +// String -> number conversions ------------------------------------------------ + +// Perform a best-effort conversion of the input string to a numeric type, +// setting |*output| to the result of the conversion. Returns true for +// "perfect" conversions; returns false in the following cases: +// - Overflow. |*output| will be set to the maximum value supported +// by the data type. +// - Underflow. |*output| will be set to the minimum value supported +// by the data type. +// - Trailing characters in the string after parsing the number. |*output| +// will be set to the value of the number that was parsed. +// - Leading whitespace in the string before parsing the number. |*output| will +// be set to the value of the number that was parsed. +// - No characters parseable as a number at the beginning of the string. +// |*output| will be set to 0. +// - Empty string. |*output| will be set to 0. +bool StringToInt(const StringPiece& input, int* output); + +bool StringToUint(const StringPiece& input, unsigned* output); + +bool StringToInt64(const StringPiece& input, int64* output); + +bool StringToUint64(const StringPiece& input, uint64* output); + +bool StringToSizeT(const StringPiece& input, size_t* output); + +// For floating-point conversions, only conversions of input strings in decimal +// form are defined to work. Behavior with strings representing floating-point +// numbers in hexadecimal, and strings representing non-fininte values (such as +// NaN and inf) is undefined. Otherwise, these behave the same as the integral +// variants. This expects the input string to NOT be specific to the locale. +// If your input is locale specific, use ICU to read the number. +bool StringToDouble(const std::string& input, double* output); + +// Hex encoding ---------------------------------------------------------------- + +// Returns a hex string representation of a binary buffer. The returned hex +// string will be in upper case. This function does not check if |size| is +// within reasonable limits since it's written with trusted data in mind. If +// you suspect that the data you want to format might be large, the absolute +// max size for |size| should be is +// std::numeric_limits<size_t>::max() / 2 +std::string HexEncode(const void* bytes, size_t size); + +// Best effort conversion, see StringToInt above for restrictions. +// Will only successful parse hex values that will fit into |output|, i.e. +// -0x80000000 < |input| < 0x7FFFFFFF. +bool HexStringToInt(const StringPiece& input, int* output); + +// Best effort conversion, see StringToInt above for restrictions. +// Will only successful parse hex values that will fit into |output|, i.e. +// 0x00000000 < |input| < 0xFFFFFFFF. +// The string is not required to start with 0x. +bool HexStringToUInt(const StringPiece& input, uint32* output); + +// Best effort conversion, see StringToInt above for restrictions. +// Will only successful parse hex values that will fit into |output|, i.e. +// -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF. +bool HexStringToInt64(const StringPiece& input, int64* output); + +// Best effort conversion, see StringToInt above for restrictions. +// Will only successful parse hex values that will fit into |output|, i.e. +// 0x0000000000000000 < |input| < 0xFFFFFFFFFFFFFFFF. +// The string is not required to start with 0x. +bool HexStringToUInt64(const StringPiece& input, uint64* output); + +// Similar to the previous functions, except that output is a vector of bytes. +// |*output| will contain as many bytes as were successfully parsed prior to the +// error. There is no overflow, but input.size() must be evenly divisible by 2. +// Leading 0x or +/- are not allowed. +bool HexStringToBytes(const std::string& input, std::vector<uint8>* output); + +} // namespace base + +#endif // BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_ diff --git a/third_party/chromium/base/strings/string_number_conversions_unittest.cc b/third_party/chromium/base/strings/string_number_conversions_unittest.cc new file mode 100644 index 0000000..80d1471 --- /dev/null +++ b/third_party/chromium/base/strings/string_number_conversions_unittest.cc @@ -0,0 +1,732 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/string_number_conversions.h" + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> + +#include <cmath> +#include <limits> + +#include <gtest/gtest.h> + +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversion_utils.h" + +namespace base { + +namespace { + +template <typename INT> +struct IntToStringTest { + INT num; + const char* sexpected; + const char* uexpected; +}; + +} // namespace + +TEST(StringNumberConversionsTest, IntToString) { + static const IntToStringTest<int> int_tests[] = { + { 0, "0", "0" }, + { -1, "-1", "4294967295" }, + { std::numeric_limits<int>::max(), "2147483647", "2147483647" }, + { std::numeric_limits<int>::min(), "-2147483648", "2147483648" }, + }; + static const IntToStringTest<int64> int64_tests[] = { + { 0, "0", "0" }, + { -1, "-1", "18446744073709551615" }, + { std::numeric_limits<int64>::max(), + "9223372036854775807", + "9223372036854775807", }, + { std::numeric_limits<int64>::min(), + "-9223372036854775808", + "9223372036854775808" }, + }; + + for (size_t i = 0; i < arraysize(int_tests); ++i) { + const IntToStringTest<int>* test = &int_tests[i]; + EXPECT_EQ(IntToString(test->num), test->sexpected); + EXPECT_EQ(UintToString(test->num), test->uexpected); + } + for (size_t i = 0; i < arraysize(int64_tests); ++i) { + const IntToStringTest<int64>* test = &int64_tests[i]; + EXPECT_EQ(Int64ToString(test->num), test->sexpected); + EXPECT_EQ(Uint64ToString(test->num), test->uexpected); + } +} + +TEST(StringNumberConversionsTest, Uint64ToString) { + static const struct { + uint64 input; + std::string output; + } cases[] = { + {0, "0"}, + {42, "42"}, + {INT_MAX, "2147483647"}, + {kuint64max, "18446744073709551615"}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) + EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input)); +} + +TEST(StringNumberConversionsTest, SizeTToString) { + size_t size_t_max = std::numeric_limits<size_t>::max(); + std::string size_t_max_string = std::to_string(size_t_max); + + static const struct { + size_t input; + std::string output; + } cases[] = { + {0, "0"}, + {9, "9"}, + {42, "42"}, + {INT_MAX, "2147483647"}, + {2147483648U, "2147483648"}, +#if SIZE_MAX > 4294967295U + {99999999999U, "99999999999"}, +#endif + {size_t_max, size_t_max_string}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) + EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input)); +} + +TEST(StringNumberConversionsTest, StringToInt) { + static const struct { + std::string input; + int output; + bool success; + } cases[] = { + {"0", 0, true}, + {"42", 42, true}, + {"42\x99", 42, false}, + {"\x99" "42\x99", 0, false}, + {"-2147483648", INT_MIN, true}, + {"2147483647", INT_MAX, true}, + {"", 0, false}, + {" 42", 42, false}, + {"42 ", 42, false}, + {"\t\n\v\f\r 42", 42, false}, + {"blah42", 0, false}, + {"42blah", 42, false}, + {"blah42blah", 0, false}, + {"-273.15", -273, false}, + {"+98.6", 98, false}, + {"--123", 0, false}, + {"++123", 0, false}, + {"-+123", 0, false}, + {"+-123", 0, false}, + {"-", 0, false}, + {"-2147483649", INT_MIN, false}, + {"-99999999999", INT_MIN, false}, + {"2147483648", INT_MAX, false}, + {"99999999999", INT_MAX, false}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + int output = 0; + EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output)); + EXPECT_EQ(cases[i].output, output); + } + + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "6\06"; + std::string input_string(input, arraysize(input) - 1); + int output; + EXPECT_FALSE(StringToInt(input_string, &output)); + EXPECT_EQ(6, output); +} + +TEST(StringNumberConversionsTest, StringToUint) { + static const struct { + std::string input; + unsigned output; + bool success; + } cases[] = { + {"0", 0, true}, + {"42", 42, true}, + {"42\x99", 42, false}, + {"\x99" "42\x99", 0, false}, + {"-2147483648", 0, false}, + {"2147483647", INT_MAX, true}, + {"", 0, false}, + {" 42", 42, false}, + {"42 ", 42, false}, + {"\t\n\v\f\r 42", 42, false}, + {"blah42", 0, false}, + {"42blah", 42, false}, + {"blah42blah", 0, false}, + {"-273.15", 0, false}, + {"+98.6", 98, false}, + {"--123", 0, false}, + {"++123", 0, false}, + {"-+123", 0, false}, + {"+-123", 0, false}, + {"-", 0, false}, + {"-2147483649", 0, false}, + {"-99999999999", 0, false}, + {"4294967295", UINT_MAX, true}, + {"4294967296", UINT_MAX, false}, + {"99999999999", UINT_MAX, false}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + unsigned output = 0; + EXPECT_EQ(cases[i].success, StringToUint(cases[i].input, &output)); + EXPECT_EQ(cases[i].output, output); + } + + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "6\06"; + std::string input_string(input, arraysize(input) - 1); + unsigned output; + EXPECT_FALSE(StringToUint(input_string, &output)); + EXPECT_EQ(6U, output); +} + +TEST(StringNumberConversionsTest, StringToInt64) { + static const struct { + std::string input; + int64 output; + bool success; + } cases[] = { + {"0", 0, true}, + {"42", 42, true}, + {"-2147483648", INT_MIN, true}, + {"2147483647", INT_MAX, true}, + {"-2147483649", INT64_C(-2147483649), true}, + {"-99999999999", INT64_C(-99999999999), true}, + {"2147483648", INT64_C(2147483648), true}, + {"99999999999", INT64_C(99999999999), true}, + {"9223372036854775807", kint64max, true}, + {"-9223372036854775808", kint64min, true}, + {"09", 9, true}, + {"-09", -9, true}, + {"", 0, false}, + {" 42", 42, false}, + {"42 ", 42, false}, + {"0x42", 0, false}, + {"\t\n\v\f\r 42", 42, false}, + {"blah42", 0, false}, + {"42blah", 42, false}, + {"blah42blah", 0, false}, + {"-273.15", -273, false}, + {"+98.6", 98, false}, + {"--123", 0, false}, + {"++123", 0, false}, + {"-+123", 0, false}, + {"+-123", 0, false}, + {"-", 0, false}, + {"-9223372036854775809", kint64min, false}, + {"-99999999999999999999", kint64min, false}, + {"9223372036854775808", kint64max, false}, + {"99999999999999999999", kint64max, false}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + int64 output = 0; + EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output)); + EXPECT_EQ(cases[i].output, output); + } + + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "6\06"; + std::string input_string(input, arraysize(input) - 1); + int64 output; + EXPECT_FALSE(StringToInt64(input_string, &output)); + EXPECT_EQ(6, output); +} + +TEST(StringNumberConversionsTest, StringToUint64) { + static const struct { + std::string input; + uint64 output; + bool success; + } cases[] = { + {"0", 0, true}, + {"42", 42, true}, + {"-2147483648", 0, false}, + {"2147483647", INT_MAX, true}, + {"-2147483649", 0, false}, + {"-99999999999", 0, false}, + {"2147483648", UINT64_C(2147483648), true}, + {"99999999999", UINT64_C(99999999999), true}, + {"9223372036854775807", kint64max, true}, + {"-9223372036854775808", 0, false}, + {"09", 9, true}, + {"-09", 0, false}, + {"", 0, false}, + {" 42", 42, false}, + {"42 ", 42, false}, + {"0x42", 0, false}, + {"\t\n\v\f\r 42", 42, false}, + {"blah42", 0, false}, + {"42blah", 42, false}, + {"blah42blah", 0, false}, + {"-273.15", 0, false}, + {"+98.6", 98, false}, + {"--123", 0, false}, + {"++123", 0, false}, + {"-+123", 0, false}, + {"+-123", 0, false}, + {"-", 0, false}, + {"-9223372036854775809", 0, false}, + {"-99999999999999999999", 0, false}, + {"9223372036854775808", UINT64_C(9223372036854775808), true}, + {"99999999999999999999", kuint64max, false}, + {"18446744073709551615", kuint64max, true}, + {"18446744073709551616", kuint64max, false}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + uint64 output = 0; + EXPECT_EQ(cases[i].success, StringToUint64(cases[i].input, &output)); + EXPECT_EQ(cases[i].output, output); + } + + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "6\06"; + std::string input_string(input, arraysize(input) - 1); + uint64 output; + EXPECT_FALSE(StringToUint64(input_string, &output)); + EXPECT_EQ(6U, output); +} + +TEST(StringNumberConversionsTest, StringToSizeT) { + size_t size_t_max = std::numeric_limits<size_t>::max(); + std::string size_t_max_string = std::to_string(size_t_max); + + static const struct { + std::string input; + size_t output; + bool success; + } cases[] = { + {"0", 0, true}, + {"42", 42, true}, + {"-2147483648", 0, false}, + {"2147483647", INT_MAX, true}, + {"-2147483649", 0, false}, + {"-99999999999", 0, false}, + {"2147483648", 2147483648U, true}, +#if SIZE_MAX > 4294967295U + {"99999999999", 99999999999U, true}, +#endif + {"-9223372036854775808", 0, false}, + {"09", 9, true}, + {"-09", 0, false}, + {"", 0, false}, + {" 42", 42, false}, + {"42 ", 42, false}, + {"0x42", 0, false}, + {"\t\n\v\f\r 42", 42, false}, + {"blah42", 0, false}, + {"42blah", 42, false}, + {"blah42blah", 0, false}, + {"-273.15", 0, false}, + {"+98.6", 98, false}, + {"--123", 0, false}, + {"++123", 0, false}, + {"-+123", 0, false}, + {"+-123", 0, false}, + {"-", 0, false}, + {"-9223372036854775809", 0, false}, + {"-99999999999999999999", 0, false}, + {"999999999999999999999999", size_t_max, false}, + {size_t_max_string, size_t_max, true}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + size_t output = 0; + EXPECT_EQ(cases[i].success, StringToSizeT(cases[i].input, &output)); + EXPECT_EQ(cases[i].output, output); + } + + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "6\06"; + std::string input_string(input, arraysize(input) - 1); + size_t output; + EXPECT_FALSE(StringToSizeT(input_string, &output)); + EXPECT_EQ(6U, output); +} + +TEST(StringNumberConversionsTest, HexStringToInt) { + static const struct { + std::string input; + int64 output; + bool success; + } cases[] = { + {"0", 0, true}, + {"42", 66, true}, + {"-42", -66, true}, + {"+42", 66, true}, + {"7fffffff", INT_MAX, true}, + {"-80000000", INT_MIN, true}, + {"80000000", INT_MAX, false}, // Overflow test. + {"-80000001", INT_MIN, false}, // Underflow test. + {"0x42", 66, true}, + {"-0x42", -66, true}, + {"+0x42", 66, true}, + {"0x7fffffff", INT_MAX, true}, + {"-0x80000000", INT_MIN, true}, + {"-80000000", INT_MIN, true}, + {"80000000", INT_MAX, false}, // Overflow test. + {"-80000001", INT_MIN, false}, // Underflow test. + {"0x0f", 15, true}, + {"0f", 15, true}, + {" 45", 0x45, false}, + {"\t\n\v\f\r 0x45", 0x45, false}, + {" 45", 0x45, false}, + {"45 ", 0x45, false}, + {"45:", 0x45, false}, + {"efgh", 0xef, false}, + {"0xefgh", 0xef, false}, + {"hgfe", 0, false}, + {"-", 0, false}, + {"", 0, false}, + {"0x", 0, false}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + int output = 0; + EXPECT_EQ(cases[i].success, HexStringToInt(cases[i].input, &output)); + EXPECT_EQ(cases[i].output, output); + } + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "0xc0ffee\0" "9"; + std::string input_string(input, arraysize(input) - 1); + int output; + EXPECT_FALSE(HexStringToInt(input_string, &output)); + EXPECT_EQ(0xc0ffee, output); +} + +TEST(StringNumberConversionsTest, HexStringToUInt) { + static const struct { + std::string input; + uint32 output; + bool success; + } cases[] = { + {"0", 0, true}, + {"42", 0x42, true}, + {"-42", 0, false}, + {"+42", 0x42, true}, + {"7fffffff", INT_MAX, true}, + {"-80000000", 0, false}, + {"ffffffff", 0xffffffff, true}, + {"DeadBeef", 0xdeadbeef, true}, + {"0x42", 0x42, true}, + {"-0x42", 0, false}, + {"+0x42", 0x42, true}, + {"0x7fffffff", INT_MAX, true}, + {"-0x80000000", 0, false}, + {"0xffffffff", kuint32max, true}, + {"0XDeadBeef", 0xdeadbeef, true}, + {"0x7fffffffffffffff", kuint32max, false}, // Overflow test. + {"-0x8000000000000000", 0, false}, + {"0x8000000000000000", kuint32max, false}, // Overflow test. + {"-0x8000000000000001", 0, false}, + {"0xFFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test. + {"FFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test. + {"0x0000000000000000", 0, true}, + {"0000000000000000", 0, true}, + {"1FFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test. + {"0x0f", 0x0f, true}, + {"0f", 0x0f, true}, + {" 45", 0x45, false}, + {"\t\n\v\f\r 0x45", 0x45, false}, + {" 45", 0x45, false}, + {"45 ", 0x45, false}, + {"45:", 0x45, false}, + {"efgh", 0xef, false}, + {"0xefgh", 0xef, false}, + {"hgfe", 0, false}, + {"-", 0, false}, + {"", 0, false}, + {"0x", 0, false}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + uint32 output = 0; + EXPECT_EQ(cases[i].success, HexStringToUInt(cases[i].input, &output)); + EXPECT_EQ(cases[i].output, output); + } + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "0xc0ffee\0" "9"; + std::string input_string(input, arraysize(input) - 1); + uint32 output; + EXPECT_FALSE(HexStringToUInt(input_string, &output)); + EXPECT_EQ(0xc0ffeeU, output); +} + +TEST(StringNumberConversionsTest, HexStringToInt64) { + static const struct { + std::string input; + int64 output; + bool success; + } cases[] = { + {"0", 0, true}, + {"42", 66, true}, + {"-42", -66, true}, + {"+42", 66, true}, + {"40acd88557b", INT64_C(4444444448123), true}, + {"7fffffff", INT_MAX, true}, + {"-80000000", INT_MIN, true}, + {"ffffffff", 0xffffffff, true}, + {"DeadBeef", 0xdeadbeef, true}, + {"0x42", 66, true}, + {"-0x42", -66, true}, + {"+0x42", 66, true}, + {"0x40acd88557b", INT64_C(4444444448123), true}, + {"0x7fffffff", INT_MAX, true}, + {"-0x80000000", INT_MIN, true}, + {"0xffffffff", 0xffffffff, true}, + {"0XDeadBeef", 0xdeadbeef, true}, + {"0x7fffffffffffffff", kint64max, true}, + {"-0x8000000000000000", kint64min, true}, + {"0x8000000000000000", kint64max, false}, // Overflow test. + {"-0x8000000000000001", kint64min, false}, // Underflow test. + {"0x0f", 15, true}, + {"0f", 15, true}, + {" 45", 0x45, false}, + {"\t\n\v\f\r 0x45", 0x45, false}, + {" 45", 0x45, false}, + {"45 ", 0x45, false}, + {"45:", 0x45, false}, + {"efgh", 0xef, false}, + {"0xefgh", 0xef, false}, + {"hgfe", 0, false}, + {"-", 0, false}, + {"", 0, false}, + {"0x", 0, false}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + int64 output = 0; + EXPECT_EQ(cases[i].success, HexStringToInt64(cases[i].input, &output)); + EXPECT_EQ(cases[i].output, output); + } + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "0xc0ffee\0" "9"; + std::string input_string(input, arraysize(input) - 1); + int64 output; + EXPECT_FALSE(HexStringToInt64(input_string, &output)); + EXPECT_EQ(0xc0ffee, output); +} + +TEST(StringNumberConversionsTest, HexStringToUInt64) { + static const struct { + std::string input; + uint64 output; + bool success; + } cases[] = { + {"0", 0, true}, + {"42", 66, true}, + {"-42", 0, false}, + {"+42", 66, true}, + {"40acd88557b", INT64_C(4444444448123), true}, + {"7fffffff", INT_MAX, true}, + {"-80000000", 0, false}, + {"ffffffff", 0xffffffff, true}, + {"DeadBeef", 0xdeadbeef, true}, + {"0x42", 66, true}, + {"-0x42", 0, false}, + {"+0x42", 66, true}, + {"0x40acd88557b", INT64_C(4444444448123), true}, + {"0x7fffffff", INT_MAX, true}, + {"-0x80000000", 0, false}, + {"0xffffffff", 0xffffffff, true}, + {"0XDeadBeef", 0xdeadbeef, true}, + {"0x7fffffffffffffff", kint64max, true}, + {"-0x8000000000000000", 0, false}, + {"0x8000000000000000", UINT64_C(0x8000000000000000), true}, + {"-0x8000000000000001", 0, false}, + {"0xFFFFFFFFFFFFFFFF", kuint64max, true}, + {"FFFFFFFFFFFFFFFF", kuint64max, true}, + {"0x0000000000000000", 0, true}, + {"0000000000000000", 0, true}, + {"1FFFFFFFFFFFFFFFF", kuint64max, false}, // Overflow test. + {"0x0f", 15, true}, + {"0f", 15, true}, + {" 45", 0x45, false}, + {"\t\n\v\f\r 0x45", 0x45, false}, + {" 45", 0x45, false}, + {"45 ", 0x45, false}, + {"45:", 0x45, false}, + {"efgh", 0xef, false}, + {"0xefgh", 0xef, false}, + {"hgfe", 0, false}, + {"-", 0, false}, + {"", 0, false}, + {"0x", 0, false}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + uint64 output = 0; + EXPECT_EQ(cases[i].success, HexStringToUInt64(cases[i].input, &output)); + EXPECT_EQ(cases[i].output, output); + } + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "0xc0ffee\0" "9"; + std::string input_string(input, arraysize(input) - 1); + uint64 output; + EXPECT_FALSE(HexStringToUInt64(input_string, &output)); + EXPECT_EQ(0xc0ffeeU, output); +} + +TEST(StringNumberConversionsTest, HexStringToBytes) { + static const struct { + const std::string input; + const char* output; + size_t output_len; + bool success; + } cases[] = { + {"0", "", 0, false}, // odd number of characters fails + {"00", "\0", 1, true}, + {"42", "\x42", 1, true}, + {"-42", "", 0, false}, // any non-hex value fails + {"+42", "", 0, false}, + {"7fffffff", "\x7f\xff\xff\xff", 4, true}, + {"80000000", "\x80\0\0\0", 4, true}, + {"deadbeef", "\xde\xad\xbe\xef", 4, true}, + {"DeadBeef", "\xde\xad\xbe\xef", 4, true}, + {"0x42", "", 0, false}, // leading 0x fails (x is not hex) + {"0f", "\xf", 1, true}, + {"45 ", "\x45", 1, false}, + {"efgh", "\xef", 1, false}, + {"", "", 0, false}, + {"0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8, true}, + {"0123456789ABCDEF012345", + "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45", 11, true}, + }; + + + for (size_t i = 0; i < arraysize(cases); ++i) { + std::vector<uint8> output; + std::vector<uint8> compare; + EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) << + i << ": " << cases[i].input; + for (size_t j = 0; j < cases[i].output_len; ++j) + compare.push_back(static_cast<uint8>(cases[i].output[j])); + ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input; + EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) << + i << ": " << cases[i].input; + } +} + +TEST(StringNumberConversionsTest, StringToDouble) { + static const struct { + std::string input; + double output; + bool success; + } cases[] = { + {"0", 0.0, true}, + {"42", 42.0, true}, + {"-42", -42.0, true}, + {"123.45", 123.45, true}, + {"-123.45", -123.45, true}, + {"+123.45", 123.45, true}, + {"2.99792458e8", 299792458.0, true}, + {"149597870.691E+3", 149597870691.0, true}, + {"6.", 6.0, true}, + {"9e99999999999999999999", HUGE_VAL, false}, + {"-9e99999999999999999999", -HUGE_VAL, false}, + {"1e-2", 0.01, true}, + {"42 ", 42.0, false}, + {" 1e-2", 0.01, false}, + {"1e-2 ", 0.01, false}, + {"-1E-7", -0.0000001, true}, + {"01e02", 100, true}, + {"2.3e15", 2.3e15, true}, + {"\t\n\v\f\r -123.45e2", -12345.0, false}, + {"+123 e4", 123.0, false}, + {"123e ", 123.0, false}, + {"123e", 123.0, false}, + {" 2.99", 2.99, false}, + {"1e3.4", 1000.0, false}, + {"nothing", 0.0, false}, + {"-", 0.0, false}, + {"+", 0.0, false}, + {"", 0.0, false}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + double output; + errno = 1; + EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output)); + if (cases[i].success) + EXPECT_EQ(1, errno) << i; // confirm that errno is unchanged. + EXPECT_DOUBLE_EQ(cases[i].output, output); + } + + // One additional test to verify that conversion of numbers in strings with + // embedded NUL characters. The NUL and extra data after it should be + // interpreted as junk after the number. + const char input[] = "3.14\0" "159"; + std::string input_string(input, arraysize(input) - 1); + double output; + EXPECT_FALSE(StringToDouble(input_string, &output)); + EXPECT_DOUBLE_EQ(3.14, output); +} + +TEST(StringNumberConversionsTest, DoubleToString) { + static const struct { + double input; + const char* expected; + } cases[] = { + {0.0, "0"}, + {1.25, "1.25"}, + {1.33518e+012, "1.33518e+12"}, + {1.33489e+012, "1.33489e+12"}, + {1.33505e+012, "1.33505e+12"}, + {1.33545e+009, "1335450000"}, + {1.33503e+009, "1335030000"}, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + EXPECT_EQ(cases[i].expected, DoubleToString(cases[i].input)); + } + + // The following two values were seen in crashes in the wild. + const char input_bytes[8] = {0, 0, 0, 0, '\xee', '\x6d', '\x73', '\x42'}; + double input = 0; + memcpy(&input, input_bytes, arraysize(input_bytes)); + EXPECT_EQ("1335179083776", DoubleToString(input)); + const char input_bytes2[8] = + {0, 0, 0, '\xa0', '\xda', '\x6c', '\x73', '\x42'}; + input = 0; + memcpy(&input, input_bytes2, arraysize(input_bytes2)); + EXPECT_EQ("1334890332160", DoubleToString(input)); +} + +TEST(StringNumberConversionsTest, HexEncode) { + std::string hex(HexEncode(NULL, 0)); + EXPECT_EQ(hex.length(), 0U); + unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81}; + hex = HexEncode(bytes, sizeof(bytes)); + EXPECT_EQ(hex.compare("01FF02FE038081"), 0); +} + +} // namespace base diff --git a/third_party/chromium/base/strings/string_piece.cc b/third_party/chromium/base/strings/string_piece.cc new file mode 100644 index 0000000..aa0695d --- /dev/null +++ b/third_party/chromium/base/strings/string_piece.cc @@ -0,0 +1,316 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Copied from strings/stringpiece.cc with modifications + +#include "base/strings/string_piece.h" + +#include <algorithm> +#include <ostream> + +namespace base { +namespace { + +// For each character in characters_wanted, sets the index corresponding +// to the ASCII code of that character to 1 in table. This is used by +// the find_.*_of methods below to tell whether or not a character is in +// the lookup table in constant time. +// The argument `table' must be an array that is large enough to hold all +// the possible values of an unsigned char. Thus it should be be declared +// as follows: +// bool table[UCHAR_MAX + 1] +inline void BuildLookupTable(const StringPiece& characters_wanted, + bool* table) { + const size_t length = characters_wanted.length(); + const char* const data = characters_wanted.data(); + for (size_t i = 0; i < length; ++i) { + table[static_cast<unsigned char>(data[i])] = true; + } +} + +} // namespace + +// MSVC doesn't like complex extern templates and DLLs. +#if !defined(COMPILER_MSVC) +template class BasicStringPiece<std::string>; +#endif + +bool operator==(const StringPiece& x, const StringPiece& y) { + if (x.size() != y.size()) + return false; + + return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0; +} + +std::ostream& operator<<(std::ostream& o, const StringPiece& piece) { + o.write(piece.data(), static_cast<std::streamsize>(piece.size())); + return o; +} + +namespace internal { + +template<typename STR> +void CopyToStringT(const BasicStringPiece<STR>& self, STR* target) { + if (self.empty()) + target->clear(); + else + target->assign(self.data(), self.size()); +} + +void CopyToString(const StringPiece& self, std::string* target) { + CopyToStringT(self, target); +} + +template<typename STR> +void AppendToStringT(const BasicStringPiece<STR>& self, STR* target) { + if (!self.empty()) + target->append(self.data(), self.size()); +} + +void AppendToString(const StringPiece& self, std::string* target) { + AppendToStringT(self, target); +} + +template<typename STR> +size_t copyT(const BasicStringPiece<STR>& self, + typename STR::value_type* buf, + size_t n, + size_t pos) { + size_t ret = std::min(self.size() - pos, n); + memcpy(buf, self.data() + pos, ret * sizeof(typename STR::value_type)); + return ret; +} + +size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos) { + return copyT(self, buf, n, pos); +} + +template<typename STR> +size_t findT(const BasicStringPiece<STR>& self, + const BasicStringPiece<STR>& s, + size_t pos) { + if (pos > self.size()) + return BasicStringPiece<STR>::npos; + + typename BasicStringPiece<STR>::const_iterator result = + std::search(self.begin() + pos, self.end(), s.begin(), s.end()); + const size_t xpos = + static_cast<size_t>(result - self.begin()); + return xpos + s.size() <= self.size() ? xpos : BasicStringPiece<STR>::npos; +} + +size_t find(const StringPiece& self, const StringPiece& s, size_t pos) { + return findT(self, s, pos); +} + +template<typename STR> +size_t findT(const BasicStringPiece<STR>& self, + typename STR::value_type c, + size_t pos) { + if (pos >= self.size()) + return BasicStringPiece<STR>::npos; + + typename BasicStringPiece<STR>::const_iterator result = + std::find(self.begin() + pos, self.end(), c); + return result != self.end() ? + static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos; +} + +size_t find(const StringPiece& self, char c, size_t pos) { + return findT(self, c, pos); +} + +template<typename STR> +size_t rfindT(const BasicStringPiece<STR>& self, + const BasicStringPiece<STR>& s, + size_t pos) { + if (self.size() < s.size()) + return BasicStringPiece<STR>::npos; + + if (s.empty()) + return std::min(self.size(), pos); + + typename BasicStringPiece<STR>::const_iterator last = + self.begin() + std::min(self.size() - s.size(), pos) + s.size(); + typename BasicStringPiece<STR>::const_iterator result = + std::find_end(self.begin(), last, s.begin(), s.end()); + return result != last ? + static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos; +} + +size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos) { + return rfindT(self, s, pos); +} + +template<typename STR> +size_t rfindT(const BasicStringPiece<STR>& self, + typename STR::value_type c, + size_t pos) { + if (self.size() == 0) + return BasicStringPiece<STR>::npos; + + for (size_t i = std::min(pos, self.size() - 1); ; + --i) { + if (self.data()[i] == c) + return i; + if (i == 0) + break; + } + return BasicStringPiece<STR>::npos; +} + +size_t rfind(const StringPiece& self, char c, size_t pos) { + return rfindT(self, c, pos); +} + +// 8-bit version using lookup table. +size_t find_first_of(const StringPiece& self, + const StringPiece& s, + size_t pos) { + if (self.size() == 0 || s.size() == 0) + return StringPiece::npos; + + // Avoid the cost of BuildLookupTable() for a single-character search. + if (s.size() == 1) + return find(self, s.data()[0], pos); + + bool lookup[UCHAR_MAX + 1] = { false }; + BuildLookupTable(s, lookup); + for (size_t i = pos; i < self.size(); ++i) { + if (lookup[static_cast<unsigned char>(self.data()[i])]) { + return i; + } + } + return StringPiece::npos; +} + +// 8-bit version using lookup table. +size_t find_first_not_of(const StringPiece& self, + const StringPiece& s, + size_t pos) { + if (self.size() == 0) + return StringPiece::npos; + + if (s.size() == 0) + return 0; + + // Avoid the cost of BuildLookupTable() for a single-character search. + if (s.size() == 1) + return find_first_not_of(self, s.data()[0], pos); + + bool lookup[UCHAR_MAX + 1] = { false }; + BuildLookupTable(s, lookup); + for (size_t i = pos; i < self.size(); ++i) { + if (!lookup[static_cast<unsigned char>(self.data()[i])]) { + return i; + } + } + return StringPiece::npos; +} + +template<typename STR> +size_t find_first_not_ofT(const BasicStringPiece<STR>& self, + typename STR::value_type c, + size_t pos) { + if (self.size() == 0) + return BasicStringPiece<STR>::npos; + + for (; pos < self.size(); ++pos) { + if (self.data()[pos] != c) { + return pos; + } + } + return BasicStringPiece<STR>::npos; +} + +size_t find_first_not_of(const StringPiece& self, + char c, + size_t pos) { + return find_first_not_ofT(self, c, pos); +} + +// 8-bit version using lookup table. +size_t find_last_of(const StringPiece& self, const StringPiece& s, size_t pos) { + if (self.size() == 0 || s.size() == 0) + return StringPiece::npos; + + // Avoid the cost of BuildLookupTable() for a single-character search. + if (s.size() == 1) + return rfind(self, s.data()[0], pos); + + bool lookup[UCHAR_MAX + 1] = { false }; + BuildLookupTable(s, lookup); + for (size_t i = std::min(pos, self.size() - 1); ; --i) { + if (lookup[static_cast<unsigned char>(self.data()[i])]) + return i; + if (i == 0) + break; + } + return StringPiece::npos; +} + +// 8-bit version using lookup table. +size_t find_last_not_of(const StringPiece& self, + const StringPiece& s, + size_t pos) { + if (self.size() == 0) + return StringPiece::npos; + + size_t i = std::min(pos, self.size() - 1); + if (s.size() == 0) + return i; + + // Avoid the cost of BuildLookupTable() for a single-character search. + if (s.size() == 1) + return find_last_not_of(self, s.data()[0], pos); + + bool lookup[UCHAR_MAX + 1] = { false }; + BuildLookupTable(s, lookup); + for (; ; --i) { + if (!lookup[static_cast<unsigned char>(self.data()[i])]) + return i; + if (i == 0) + break; + } + return StringPiece::npos; +} + +template<typename STR> +size_t find_last_not_ofT(const BasicStringPiece<STR>& self, + typename STR::value_type c, + size_t pos) { + if (self.size() == 0) + return BasicStringPiece<STR>::npos; + + for (size_t i = std::min(pos, self.size() - 1); ; --i) { + if (self.data()[i] != c) + return i; + if (i == 0) + break; + } + return BasicStringPiece<STR>::npos; +} + +size_t find_last_not_of(const StringPiece& self, + char c, + size_t pos) { + return find_last_not_ofT(self, c, pos); +} + +template<typename STR> +BasicStringPiece<STR> substrT(const BasicStringPiece<STR>& self, + size_t pos, + size_t n) { + if (pos > self.size()) pos = self.size(); + if (n > self.size() - pos) n = self.size() - pos; + return BasicStringPiece<STR>(self.data() + pos, n); +} + +StringPiece substr(const StringPiece& self, + size_t pos, + size_t n) { + return substrT(self, pos, n); +} + +} // namespace internal +} // namespace base diff --git a/third_party/chromium/base/strings/string_piece.h b/third_party/chromium/base/strings/string_piece.h new file mode 100644 index 0000000..14ee635 --- /dev/null +++ b/third_party/chromium/base/strings/string_piece.h @@ -0,0 +1,319 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Copied from strings/stringpiece.h with modifications +// +// A string-like object that points to a sized piece of memory. +// +// You can use StringPiece as a function or method parameter. A StringPiece +// parameter can receive a double-quoted string literal argument, a "const +// char*" argument, a string argument, or a StringPiece argument with no data +// copying. Systematic use of StringPiece for arguments reduces data +// copies and strlen() calls. +// +// Prefer passing StringPieces by value: +// void MyFunction(StringPiece arg); +// If circumstances require, you may also pass by const reference: +// void MyFunction(const StringPiece& arg); // not preferred +// Both of these have the same lifetime semantics. Passing by value +// generates slightly smaller code. For more discussion, Googlers can see +// the thread go/stringpiecebyvalue on c-users. + +#ifndef BASE_STRINGS_STRING_PIECE_H_ +#define BASE_STRINGS_STRING_PIECE_H_ + +#include <stddef.h> + +#include <iosfwd> +#include <string> + +#include "base/base_export.h" +#include "base/basictypes.h" + +namespace base { + +template <typename STRING_TYPE> class BasicStringPiece; +typedef BasicStringPiece<std::string> StringPiece; + +// internal -------------------------------------------------------------------- + +// Many of the StringPiece functions use different implementations for the +// 8-bit and 16-bit versions, and we don't want lots of template expansions in +// this (very common) header that will slow down compilation. +// +// So here we define overloaded functions called by the StringPiece template. +// For those that share an implementation, the two versions will expand to a +// template internal to the .cc file. +namespace internal { + +void CopyToString(const StringPiece& self, std::string* target); + +void AppendToString(const StringPiece& self, std::string* target); + +size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos); + +size_t find(const StringPiece& self, const StringPiece& s, size_t pos); +size_t find(const StringPiece& self, char c, size_t pos); + +size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos); +size_t rfind(const StringPiece& self, char c, size_t pos); + +size_t find_first_of(const StringPiece& self, const StringPiece& s, size_t pos); + +size_t find_first_not_of(const StringPiece& self, + const StringPiece& s, + size_t pos); +size_t find_first_not_of(const StringPiece& self, char c, size_t pos); + +size_t find_last_of(const StringPiece& self, const StringPiece& s, size_t pos); +size_t find_last_of(const StringPiece& self, char c, size_t pos); + +size_t find_last_not_of(const StringPiece& self, + const StringPiece& s, + size_t pos); +size_t find_last_not_of(const StringPiece& self, char c, size_t pos); + +StringPiece substr(const StringPiece& self, size_t pos, size_t n); + +} // namespace internal + +// BasicStringPiece ------------------------------------------------------------ + +// Defines the types, methods, operators, and data members common to both +// StringPiece and StringPiece16. Do not refer to this class directly, but +// rather to BasicStringPiece, StringPiece, or StringPiece16. +// +// This is templatized by string class type rather than character type, so +// BasicStringPiece<std::string> or BasicStringPiece<base::string16>. +template <typename STRING_TYPE> class BasicStringPiece { + public: + // Standard STL container boilerplate. + typedef size_t size_type; + typedef typename STRING_TYPE::value_type value_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef const value_type& const_reference; + typedef ptrdiff_t difference_type; + typedef const value_type* const_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + static const size_type npos; + + public: + // We provide non-explicit singleton constructors so users can pass + // in a "const char*" or a "string" wherever a "StringPiece" is + // expected (likewise for char16, string16, StringPiece16). + BasicStringPiece() : ptr_(NULL), length_(0) {} + BasicStringPiece(const value_type* str) + : ptr_(str), + length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {} + BasicStringPiece(const STRING_TYPE& str) + : ptr_(str.data()), length_(str.size()) {} + BasicStringPiece(const value_type* offset, size_type len) + : ptr_(offset), length_(len) {} + BasicStringPiece(const typename STRING_TYPE::const_iterator& begin, + const typename STRING_TYPE::const_iterator& end) + : ptr_((end > begin) ? &(*begin) : NULL), + length_((end > begin) ? (size_type)(end - begin) : 0) {} + + // data() may return a pointer to a buffer with embedded NULs, and the + // returned buffer may or may not be null terminated. Therefore it is + // typically a mistake to pass data() to a routine that expects a NUL + // terminated string. + const value_type* data() const { return ptr_; } + size_type size() const { return length_; } + size_type length() const { return length_; } + bool empty() const { return length_ == 0; } + + void clear() { + ptr_ = NULL; + length_ = 0; + } + void set(const value_type* data, size_type len) { + ptr_ = data; + length_ = len; + } + void set(const value_type* str) { + ptr_ = str; + length_ = str ? STRING_TYPE::traits_type::length(str) : 0; + } + + value_type operator[](size_type i) const { return ptr_[i]; } + + void remove_prefix(size_type n) { + ptr_ += n; + length_ -= n; + } + + void remove_suffix(size_type n) { + length_ -= n; + } + + int compare(const BasicStringPiece<STRING_TYPE>& x) const { + int r = wordmemcmp( + ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_)); + if (r == 0) { + if (length_ < x.length_) r = -1; + else if (length_ > x.length_) r = +1; + } + return r; + } + + STRING_TYPE as_string() const { + // std::string doesn't like to take a NULL pointer even with a 0 size. + return empty() ? STRING_TYPE() : STRING_TYPE(data(), size()); + } + + const_iterator begin() const { return ptr_; } + const_iterator end() const { return ptr_ + length_; } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(ptr_ + length_); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(ptr_); + } + + size_type max_size() const { return length_; } + size_type capacity() const { return length_; } + + static int wordmemcmp(const value_type* p, + const value_type* p2, + size_type N) { + return STRING_TYPE::traits_type::compare(p, p2, N); + } + + // Sets the value of the given string target type to be the current string. + // This saves a temporary over doing |a = b.as_string()| + void CopyToString(STRING_TYPE* target) const { + internal::CopyToString(*this, target); + } + + void AppendToString(STRING_TYPE* target) const { + internal::AppendToString(*this, target); + } + + size_type copy(value_type* buf, size_type n, size_type pos = 0) const { + return internal::copy(*this, buf, n, pos); + } + + // Does "this" start with "x" + bool starts_with(const BasicStringPiece& x) const { + return ((this->length_ >= x.length_) && + (wordmemcmp(this->ptr_, x.ptr_, x.length_) == 0)); + } + + // Does "this" end with "x" + bool ends_with(const BasicStringPiece& x) const { + return ((this->length_ >= x.length_) && + (wordmemcmp(this->ptr_ + (this->length_-x.length_), + x.ptr_, x.length_) == 0)); + } + + // find: Search for a character or substring at a given offset. + size_type find(const BasicStringPiece<STRING_TYPE>& s, + size_type pos = 0) const { + return internal::find(*this, s, pos); + } + size_type find(value_type c, size_type pos = 0) const { + return internal::find(*this, c, pos); + } + + // rfind: Reverse find. + size_type rfind(const BasicStringPiece& s, + size_type pos = BasicStringPiece::npos) const { + return internal::rfind(*this, s, pos); + } + size_type rfind(value_type c, size_type pos = BasicStringPiece::npos) const { + return internal::rfind(*this, c, pos); + } + + // find_first_of: Find the first occurence of one of a set of characters. + size_type find_first_of(const BasicStringPiece& s, + size_type pos = 0) const { + return internal::find_first_of(*this, s, pos); + } + size_type find_first_of(value_type c, size_type pos = 0) const { + return find(c, pos); + } + + // find_first_not_of: Find the first occurence not of a set of characters. + size_type find_first_not_of(const BasicStringPiece& s, + size_type pos = 0) const { + return internal::find_first_not_of(*this, s, pos); + } + size_type find_first_not_of(value_type c, size_type pos = 0) const { + return internal::find_first_not_of(*this, c, pos); + } + + // find_last_of: Find the last occurence of one of a set of characters. + size_type find_last_of(const BasicStringPiece& s, + size_type pos = BasicStringPiece::npos) const { + return internal::find_last_of(*this, s, pos); + } + size_type find_last_of(value_type c, + size_type pos = BasicStringPiece::npos) const { + return rfind(c, pos); + } + + // find_last_not_of: Find the last occurence not of a set of characters. + size_type find_last_not_of(const BasicStringPiece& s, + size_type pos = BasicStringPiece::npos) const { + return internal::find_last_not_of(*this, s, pos); + } + size_type find_last_not_of(value_type c, + size_type pos = BasicStringPiece::npos) const { + return internal::find_last_not_of(*this, c, pos); + } + + // substr. + BasicStringPiece substr(size_type pos, + size_type n = BasicStringPiece::npos) const { + return internal::substr(*this, pos, n); + } + + protected: + const value_type* ptr_; + size_type length_; +}; + +template <typename STRING_TYPE> +const typename BasicStringPiece<STRING_TYPE>::size_type +BasicStringPiece<STRING_TYPE>::npos = + typename BasicStringPiece<STRING_TYPE>::size_type(-1); + +// MSVC doesn't like complex extern templates and DLLs. +#if !defined(COMPILER_MSVC) +extern template class BasicStringPiece<std::string>; +#endif + +// StingPiece operators -------------------------------------------------------- + +bool operator==(const StringPiece& x, const StringPiece& y); + +inline bool operator!=(const StringPiece& x, const StringPiece& y) { + return !(x == y); +} + +inline bool operator<(const StringPiece& x, const StringPiece& y) { + const int r = StringPiece::wordmemcmp( + x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size())); + return ((r < 0) || ((r == 0) && (x.size() < y.size()))); +} + +inline bool operator>(const StringPiece& x, const StringPiece& y) { + return y < x; +} + +inline bool operator<=(const StringPiece& x, const StringPiece& y) { + return !(x > y); +} + +inline bool operator>=(const StringPiece& x, const StringPiece& y) { + return !(x < y); +} + +std::ostream& operator<<(std::ostream& o, const StringPiece& piece); + +} // namespace base + +#endif // BASE_STRINGS_STRING_PIECE_H_ diff --git a/third_party/chromium/base/strings/string_piece_unittest.cc b/third_party/chromium/base/strings/string_piece_unittest.cc new file mode 100644 index 0000000..2c2b0a6 --- /dev/null +++ b/third_party/chromium/base/strings/string_piece_unittest.cc @@ -0,0 +1,652 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> + +#include <gtest/gtest.h> + +#include "base/strings/string_piece.h" +#include "base/strings/utf_string_conversion_utils.h" + +namespace base { + +template <typename T> +class CommonStringPieceTest : public ::testing::Test { + public: + static const T as_string(const char* input) { + return T(input); + } + static const T& as_string(const T& input) { + return input; + } +}; + +typedef ::testing::Types<std::string> SupportedStringTypes; + +TYPED_TEST_CASE(CommonStringPieceTest, SupportedStringTypes); + +TYPED_TEST(CommonStringPieceTest, CheckComparisonOperators) { +#define CMP_Y(op, x, y) \ + { \ + TypeParam lhs(TestFixture::as_string(x)); \ + TypeParam rhs(TestFixture::as_string(y)); \ + ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())) op \ + BasicStringPiece<TypeParam>((rhs.c_str())))); \ + ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare( \ + BasicStringPiece<TypeParam>((rhs.c_str()))) op 0)); \ + } + +#define CMP_N(op, x, y) \ + { \ + TypeParam lhs(TestFixture::as_string(x)); \ + TypeParam rhs(TestFixture::as_string(y)); \ + ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())) op \ + BasicStringPiece<TypeParam>((rhs.c_str())))); \ + ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare( \ + BasicStringPiece<TypeParam>((rhs.c_str()))) op 0)); \ + } + + CMP_Y(==, "", ""); + CMP_Y(==, "a", "a"); + CMP_Y(==, "aa", "aa"); + CMP_N(==, "a", ""); + CMP_N(==, "", "a"); + CMP_N(==, "a", "b"); + CMP_N(==, "a", "aa"); + CMP_N(==, "aa", "a"); + + CMP_N(!=, "", ""); + CMP_N(!=, "a", "a"); + CMP_N(!=, "aa", "aa"); + CMP_Y(!=, "a", ""); + CMP_Y(!=, "", "a"); + CMP_Y(!=, "a", "b"); + CMP_Y(!=, "a", "aa"); + CMP_Y(!=, "aa", "a"); + + CMP_Y(<, "a", "b"); + CMP_Y(<, "a", "aa"); + CMP_Y(<, "aa", "b"); + CMP_Y(<, "aa", "bb"); + CMP_N(<, "a", "a"); + CMP_N(<, "b", "a"); + CMP_N(<, "aa", "a"); + CMP_N(<, "b", "aa"); + CMP_N(<, "bb", "aa"); + + CMP_Y(<=, "a", "a"); + CMP_Y(<=, "a", "b"); + CMP_Y(<=, "a", "aa"); + CMP_Y(<=, "aa", "b"); + CMP_Y(<=, "aa", "bb"); + CMP_N(<=, "b", "a"); + CMP_N(<=, "aa", "a"); + CMP_N(<=, "b", "aa"); + CMP_N(<=, "bb", "aa"); + + CMP_N(>=, "a", "b"); + CMP_N(>=, "a", "aa"); + CMP_N(>=, "aa", "b"); + CMP_N(>=, "aa", "bb"); + CMP_Y(>=, "a", "a"); + CMP_Y(>=, "b", "a"); + CMP_Y(>=, "aa", "a"); + CMP_Y(>=, "b", "aa"); + CMP_Y(>=, "bb", "aa"); + + CMP_N(>, "a", "a"); + CMP_N(>, "a", "b"); + CMP_N(>, "a", "aa"); + CMP_N(>, "aa", "b"); + CMP_N(>, "aa", "bb"); + CMP_Y(>, "b", "a"); + CMP_Y(>, "aa", "a"); + CMP_Y(>, "b", "aa"); + CMP_Y(>, "bb", "aa"); + + std::string x; + for (int i = 0; i < 256; i++) { + x += 'a'; + std::string y = x; + CMP_Y(==, x, y); + for (int j = 0; j < i; j++) { + std::string z = x; + z[j] = 'b'; // Differs in position 'j' + CMP_N(==, x, z); + } + } + +#undef CMP_Y +#undef CMP_N +} + +TYPED_TEST(CommonStringPieceTest, CheckSTL) { + TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); + TypeParam abc(TestFixture::as_string("abc")); + TypeParam xyz(TestFixture::as_string("xyz")); + TypeParam foobar(TestFixture::as_string("foobar")); + + BasicStringPiece<TypeParam> a(alphabet); + BasicStringPiece<TypeParam> b(abc); + BasicStringPiece<TypeParam> c(xyz); + BasicStringPiece<TypeParam> d(foobar); + BasicStringPiece<TypeParam> e; + TypeParam temp(TestFixture::as_string("123")); + temp += static_cast<typename TypeParam::value_type>(0); + temp += TestFixture::as_string("456"); + BasicStringPiece<TypeParam> f(temp); + + ASSERT_EQ(a[6], static_cast<typename TypeParam::value_type>('g')); + ASSERT_EQ(b[0], static_cast<typename TypeParam::value_type>('a')); + ASSERT_EQ(c[2], static_cast<typename TypeParam::value_type>('z')); + ASSERT_EQ(f[3], static_cast<typename TypeParam::value_type>('\0')); + ASSERT_EQ(f[5], static_cast<typename TypeParam::value_type>('5')); + + ASSERT_EQ(*d.data(), static_cast<typename TypeParam::value_type>('f')); + ASSERT_EQ(d.data()[5], static_cast<typename TypeParam::value_type>('r')); + ASSERT_TRUE(e.data() == NULL); + + ASSERT_EQ(*a.begin(), static_cast<typename TypeParam::value_type>('a')); + ASSERT_EQ(*(b.begin() + 2), static_cast<typename TypeParam::value_type>('c')); + ASSERT_EQ(*(c.end() - 1), static_cast<typename TypeParam::value_type>('z')); + + ASSERT_EQ(*a.rbegin(), static_cast<typename TypeParam::value_type>('z')); + ASSERT_EQ(*(b.rbegin() + 2), + static_cast<typename TypeParam::value_type>('a')); + ASSERT_EQ(*(c.rend() - 1), static_cast<typename TypeParam::value_type>('x')); + ASSERT_TRUE(a.rbegin() + 26 == a.rend()); + + ASSERT_EQ(a.size(), 26U); + ASSERT_EQ(b.size(), 3U); + ASSERT_EQ(c.size(), 3U); + ASSERT_EQ(d.size(), 6U); + ASSERT_EQ(e.size(), 0U); + ASSERT_EQ(f.size(), 7U); + + ASSERT_TRUE(!d.empty()); + ASSERT_TRUE(d.begin() != d.end()); + ASSERT_TRUE(d.begin() + 6 == d.end()); + + ASSERT_TRUE(e.empty()); + ASSERT_TRUE(e.begin() == e.end()); + + d.clear(); + ASSERT_EQ(d.size(), 0U); + ASSERT_TRUE(d.empty()); + ASSERT_TRUE(d.data() == NULL); + ASSERT_TRUE(d.begin() == d.end()); + + ASSERT_GE(a.max_size(), a.capacity()); + ASSERT_GE(a.capacity(), a.size()); +} + +TYPED_TEST(CommonStringPieceTest, CheckFind) { + typedef BasicStringPiece<TypeParam> Piece; + + TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); + TypeParam abc(TestFixture::as_string("abc")); + TypeParam xyz(TestFixture::as_string("xyz")); + TypeParam foobar(TestFixture::as_string("foobar")); + + BasicStringPiece<TypeParam> a(alphabet); + BasicStringPiece<TypeParam> b(abc); + BasicStringPiece<TypeParam> c(xyz); + BasicStringPiece<TypeParam> d(foobar); + + d.clear(); + Piece e; + TypeParam temp(TestFixture::as_string("123")); + temp.push_back('\0'); + temp += TestFixture::as_string("456"); + Piece f(temp); + + typename TypeParam::value_type buf[4] = { '%', '%', '%', '%' }; + ASSERT_EQ(a.copy(buf, 4), 4U); + ASSERT_EQ(buf[0], a[0]); + ASSERT_EQ(buf[1], a[1]); + ASSERT_EQ(buf[2], a[2]); + ASSERT_EQ(buf[3], a[3]); + ASSERT_EQ(a.copy(buf, 3, 7), 3U); + ASSERT_EQ(buf[0], a[7]); + ASSERT_EQ(buf[1], a[8]); + ASSERT_EQ(buf[2], a[9]); + ASSERT_EQ(buf[3], a[3]); + ASSERT_EQ(c.copy(buf, 99), 3U); + ASSERT_EQ(buf[0], c[0]); + ASSERT_EQ(buf[1], c[1]); + ASSERT_EQ(buf[2], c[2]); + ASSERT_EQ(buf[3], a[3]); + + ASSERT_EQ(Piece::npos, TypeParam::npos); + + ASSERT_EQ(a.find(b), 0U); + ASSERT_EQ(a.find(b, 1), Piece::npos); + ASSERT_EQ(a.find(c), 23U); + ASSERT_EQ(a.find(c, 9), 23U); + ASSERT_EQ(a.find(c, Piece::npos), Piece::npos); + ASSERT_EQ(b.find(c), Piece::npos); + ASSERT_EQ(b.find(c, Piece::npos), Piece::npos); + ASSERT_EQ(a.find(d), 0U); + ASSERT_EQ(a.find(e), 0U); + ASSERT_EQ(a.find(d, 12), 12U); + ASSERT_EQ(a.find(e, 17), 17U); + TypeParam not_found(TestFixture::as_string("xx not found bb")); + Piece g(not_found); + ASSERT_EQ(a.find(g), Piece::npos); + // empty string nonsense + ASSERT_EQ(d.find(b), Piece::npos); + ASSERT_EQ(e.find(b), Piece::npos); + ASSERT_EQ(d.find(b, 4), Piece::npos); + ASSERT_EQ(e.find(b, 7), Piece::npos); + + size_t empty_search_pos = TypeParam().find(TypeParam()); + ASSERT_EQ(d.find(d), empty_search_pos); + ASSERT_EQ(d.find(e), empty_search_pos); + ASSERT_EQ(e.find(d), empty_search_pos); + ASSERT_EQ(e.find(e), empty_search_pos); + ASSERT_EQ(d.find(d, 4), std::string().find(std::string(), 4)); + ASSERT_EQ(d.find(e, 4), std::string().find(std::string(), 4)); + ASSERT_EQ(e.find(d, 4), std::string().find(std::string(), 4)); + ASSERT_EQ(e.find(e, 4), std::string().find(std::string(), 4)); + + ASSERT_EQ(a.find('a'), 0U); + ASSERT_EQ(a.find('c'), 2U); + ASSERT_EQ(a.find('z'), 25U); + ASSERT_EQ(a.find('$'), Piece::npos); + ASSERT_EQ(a.find('\0'), Piece::npos); + ASSERT_EQ(f.find('\0'), 3U); + ASSERT_EQ(f.find('3'), 2U); + ASSERT_EQ(f.find('5'), 5U); + ASSERT_EQ(g.find('o'), 4U); + ASSERT_EQ(g.find('o', 4), 4U); + ASSERT_EQ(g.find('o', 5), 8U); + ASSERT_EQ(a.find('b', 5), Piece::npos); + // empty string nonsense + ASSERT_EQ(d.find('\0'), Piece::npos); + ASSERT_EQ(e.find('\0'), Piece::npos); + ASSERT_EQ(d.find('\0', 4), Piece::npos); + ASSERT_EQ(e.find('\0', 7), Piece::npos); + ASSERT_EQ(d.find('x'), Piece::npos); + ASSERT_EQ(e.find('x'), Piece::npos); + ASSERT_EQ(d.find('x', 4), Piece::npos); + ASSERT_EQ(e.find('x', 7), Piece::npos); + + ASSERT_EQ(a.rfind(b), 0U); + ASSERT_EQ(a.rfind(b, 1), 0U); + ASSERT_EQ(a.rfind(c), 23U); + ASSERT_EQ(a.rfind(c, 22U), Piece::npos); + ASSERT_EQ(a.rfind(c, 1U), Piece::npos); + ASSERT_EQ(a.rfind(c, 0U), Piece::npos); + ASSERT_EQ(b.rfind(c), Piece::npos); + ASSERT_EQ(b.rfind(c, 0U), Piece::npos); + ASSERT_EQ(a.rfind(d), static_cast<size_t>(a.as_string().rfind(TypeParam()))); + ASSERT_EQ(a.rfind(e), a.as_string().rfind(TypeParam())); + ASSERT_EQ(a.rfind(d, 12), 12U); + ASSERT_EQ(a.rfind(e, 17), 17U); + ASSERT_EQ(a.rfind(g), Piece::npos); + ASSERT_EQ(d.rfind(b), Piece::npos); + ASSERT_EQ(e.rfind(b), Piece::npos); + ASSERT_EQ(d.rfind(b, 4), Piece::npos); + ASSERT_EQ(e.rfind(b, 7), Piece::npos); + // empty string nonsense + ASSERT_EQ(d.rfind(d, 4), std::string().rfind(std::string())); + ASSERT_EQ(e.rfind(d, 7), std::string().rfind(std::string())); + ASSERT_EQ(d.rfind(e, 4), std::string().rfind(std::string())); + ASSERT_EQ(e.rfind(e, 7), std::string().rfind(std::string())); + ASSERT_EQ(d.rfind(d), std::string().rfind(std::string())); + ASSERT_EQ(e.rfind(d), std::string().rfind(std::string())); + ASSERT_EQ(d.rfind(e), std::string().rfind(std::string())); + ASSERT_EQ(e.rfind(e), std::string().rfind(std::string())); + + ASSERT_EQ(g.rfind('o'), 8U); + ASSERT_EQ(g.rfind('q'), Piece::npos); + ASSERT_EQ(g.rfind('o', 8), 8U); + ASSERT_EQ(g.rfind('o', 7), 4U); + ASSERT_EQ(g.rfind('o', 3), Piece::npos); + ASSERT_EQ(f.rfind('\0'), 3U); + ASSERT_EQ(f.rfind('\0', 12), 3U); + ASSERT_EQ(f.rfind('3'), 2U); + ASSERT_EQ(f.rfind('5'), 5U); + // empty string nonsense + ASSERT_EQ(d.rfind('o'), Piece::npos); + ASSERT_EQ(e.rfind('o'), Piece::npos); + ASSERT_EQ(d.rfind('o', 4), Piece::npos); + ASSERT_EQ(e.rfind('o', 7), Piece::npos); + + TypeParam one_two_three_four(TestFixture::as_string("one,two:three;four")); + TypeParam comma_colon(TestFixture::as_string(",:")); + ASSERT_EQ(3U, Piece(one_two_three_four).find_first_of(comma_colon)); + ASSERT_EQ(a.find_first_of(b), 0U); + ASSERT_EQ(a.find_first_of(b, 0), 0U); + ASSERT_EQ(a.find_first_of(b, 1), 1U); + ASSERT_EQ(a.find_first_of(b, 2), 2U); + ASSERT_EQ(a.find_first_of(b, 3), Piece::npos); + ASSERT_EQ(a.find_first_of(c), 23U); + ASSERT_EQ(a.find_first_of(c, 23), 23U); + ASSERT_EQ(a.find_first_of(c, 24), 24U); + ASSERT_EQ(a.find_first_of(c, 25), 25U); + ASSERT_EQ(a.find_first_of(c, 26), Piece::npos); + ASSERT_EQ(g.find_first_of(b), 13U); + ASSERT_EQ(g.find_first_of(c), 0U); + ASSERT_EQ(a.find_first_of(f), Piece::npos); + ASSERT_EQ(f.find_first_of(a), Piece::npos); + // empty string nonsense + ASSERT_EQ(a.find_first_of(d), Piece::npos); + ASSERT_EQ(a.find_first_of(e), Piece::npos); + ASSERT_EQ(d.find_first_of(b), Piece::npos); + ASSERT_EQ(e.find_first_of(b), Piece::npos); + ASSERT_EQ(d.find_first_of(d), Piece::npos); + ASSERT_EQ(e.find_first_of(d), Piece::npos); + ASSERT_EQ(d.find_first_of(e), Piece::npos); + ASSERT_EQ(e.find_first_of(e), Piece::npos); + + ASSERT_EQ(a.find_first_not_of(b), 3U); + ASSERT_EQ(a.find_first_not_of(c), 0U); + ASSERT_EQ(b.find_first_not_of(a), Piece::npos); + ASSERT_EQ(c.find_first_not_of(a), Piece::npos); + ASSERT_EQ(f.find_first_not_of(a), 0U); + ASSERT_EQ(a.find_first_not_of(f), 0U); + ASSERT_EQ(a.find_first_not_of(d), 0U); + ASSERT_EQ(a.find_first_not_of(e), 0U); + // empty string nonsense + ASSERT_EQ(d.find_first_not_of(a), Piece::npos); + ASSERT_EQ(e.find_first_not_of(a), Piece::npos); + ASSERT_EQ(d.find_first_not_of(d), Piece::npos); + ASSERT_EQ(e.find_first_not_of(d), Piece::npos); + ASSERT_EQ(d.find_first_not_of(e), Piece::npos); + ASSERT_EQ(e.find_first_not_of(e), Piece::npos); + + TypeParam equals(TestFixture::as_string("====")); + Piece h(equals); + ASSERT_EQ(h.find_first_not_of('='), Piece::npos); + ASSERT_EQ(h.find_first_not_of('=', 3), Piece::npos); + ASSERT_EQ(h.find_first_not_of('\0'), 0U); + ASSERT_EQ(g.find_first_not_of('x'), 2U); + ASSERT_EQ(f.find_first_not_of('\0'), 0U); + ASSERT_EQ(f.find_first_not_of('\0', 3), 4U); + ASSERT_EQ(f.find_first_not_of('\0', 2), 2U); + // empty string nonsense + ASSERT_EQ(d.find_first_not_of('x'), Piece::npos); + ASSERT_EQ(e.find_first_not_of('x'), Piece::npos); + ASSERT_EQ(d.find_first_not_of('\0'), Piece::npos); + ASSERT_EQ(e.find_first_not_of('\0'), Piece::npos); + + // Piece g("xx not found bb"); + TypeParam fifty_six(TestFixture::as_string("56")); + Piece i(fifty_six); + ASSERT_EQ(h.find_last_of(a), Piece::npos); + ASSERT_EQ(g.find_last_of(a), g.size()-1); + ASSERT_EQ(a.find_last_of(b), 2U); + ASSERT_EQ(a.find_last_of(c), a.size()-1); + ASSERT_EQ(f.find_last_of(i), 6U); + ASSERT_EQ(a.find_last_of('a'), 0U); + ASSERT_EQ(a.find_last_of('b'), 1U); + ASSERT_EQ(a.find_last_of('z'), 25U); + ASSERT_EQ(a.find_last_of('a', 5), 0U); + ASSERT_EQ(a.find_last_of('b', 5), 1U); + ASSERT_EQ(a.find_last_of('b', 0), Piece::npos); + ASSERT_EQ(a.find_last_of('z', 25), 25U); + ASSERT_EQ(a.find_last_of('z', 24), Piece::npos); + ASSERT_EQ(f.find_last_of(i, 5), 5U); + ASSERT_EQ(f.find_last_of(i, 6), 6U); + ASSERT_EQ(f.find_last_of(a, 4), Piece::npos); + // empty string nonsense + ASSERT_EQ(f.find_last_of(d), Piece::npos); + ASSERT_EQ(f.find_last_of(e), Piece::npos); + ASSERT_EQ(f.find_last_of(d, 4), Piece::npos); + ASSERT_EQ(f.find_last_of(e, 4), Piece::npos); + ASSERT_EQ(d.find_last_of(d), Piece::npos); + ASSERT_EQ(d.find_last_of(e), Piece::npos); + ASSERT_EQ(e.find_last_of(d), Piece::npos); + ASSERT_EQ(e.find_last_of(e), Piece::npos); + ASSERT_EQ(d.find_last_of(f), Piece::npos); + ASSERT_EQ(e.find_last_of(f), Piece::npos); + ASSERT_EQ(d.find_last_of(d, 4), Piece::npos); + ASSERT_EQ(d.find_last_of(e, 4), Piece::npos); + ASSERT_EQ(e.find_last_of(d, 4), Piece::npos); + ASSERT_EQ(e.find_last_of(e, 4), Piece::npos); + ASSERT_EQ(d.find_last_of(f, 4), Piece::npos); + ASSERT_EQ(e.find_last_of(f, 4), Piece::npos); + + ASSERT_EQ(a.find_last_not_of(b), a.size()-1); + ASSERT_EQ(a.find_last_not_of(c), 22U); + ASSERT_EQ(b.find_last_not_of(a), Piece::npos); + ASSERT_EQ(b.find_last_not_of(b), Piece::npos); + ASSERT_EQ(f.find_last_not_of(i), 4U); + ASSERT_EQ(a.find_last_not_of(c, 24), 22U); + ASSERT_EQ(a.find_last_not_of(b, 3), 3U); + ASSERT_EQ(a.find_last_not_of(b, 2), Piece::npos); + // empty string nonsense + ASSERT_EQ(f.find_last_not_of(d), f.size()-1); + ASSERT_EQ(f.find_last_not_of(e), f.size()-1); + ASSERT_EQ(f.find_last_not_of(d, 4), 4U); + ASSERT_EQ(f.find_last_not_of(e, 4), 4U); + ASSERT_EQ(d.find_last_not_of(d), Piece::npos); + ASSERT_EQ(d.find_last_not_of(e), Piece::npos); + ASSERT_EQ(e.find_last_not_of(d), Piece::npos); + ASSERT_EQ(e.find_last_not_of(e), Piece::npos); + ASSERT_EQ(d.find_last_not_of(f), Piece::npos); + ASSERT_EQ(e.find_last_not_of(f), Piece::npos); + ASSERT_EQ(d.find_last_not_of(d, 4), Piece::npos); + ASSERT_EQ(d.find_last_not_of(e, 4), Piece::npos); + ASSERT_EQ(e.find_last_not_of(d, 4), Piece::npos); + ASSERT_EQ(e.find_last_not_of(e, 4), Piece::npos); + ASSERT_EQ(d.find_last_not_of(f, 4), Piece::npos); + ASSERT_EQ(e.find_last_not_of(f, 4), Piece::npos); + + ASSERT_EQ(h.find_last_not_of('x'), h.size() - 1); + ASSERT_EQ(h.find_last_not_of('='), Piece::npos); + ASSERT_EQ(b.find_last_not_of('c'), 1U); + ASSERT_EQ(h.find_last_not_of('x', 2), 2U); + ASSERT_EQ(h.find_last_not_of('=', 2), Piece::npos); + ASSERT_EQ(b.find_last_not_of('b', 1), 0U); + // empty string nonsense + ASSERT_EQ(d.find_last_not_of('x'), Piece::npos); + ASSERT_EQ(e.find_last_not_of('x'), Piece::npos); + ASSERT_EQ(d.find_last_not_of('\0'), Piece::npos); + ASSERT_EQ(e.find_last_not_of('\0'), Piece::npos); + + ASSERT_EQ(a.substr(0, 3), b); + ASSERT_EQ(a.substr(23), c); + ASSERT_EQ(a.substr(23, 3), c); + ASSERT_EQ(a.substr(23, 99), c); + ASSERT_EQ(a.substr(0), a); + ASSERT_EQ(a.substr(3, 2), TestFixture::as_string("de")); + // empty string nonsense + ASSERT_EQ(a.substr(99, 2), e); + ASSERT_EQ(d.substr(99), e); + ASSERT_EQ(d.substr(0, 99), e); + ASSERT_EQ(d.substr(99, 99), e); +} + +TYPED_TEST(CommonStringPieceTest, CheckCustom) { + TypeParam foobar(TestFixture::as_string("foobar")); + BasicStringPiece<TypeParam> a(foobar); + TypeParam s1(TestFixture::as_string("123")); + s1 += static_cast<typename TypeParam::value_type>('\0'); + s1 += TestFixture::as_string("456"); + BasicStringPiece<TypeParam> b(s1); + BasicStringPiece<TypeParam> e; + TypeParam s2; + + // remove_prefix + BasicStringPiece<TypeParam> c(a); + c.remove_prefix(3); + ASSERT_EQ(c, TestFixture::as_string("bar")); + c = a; + c.remove_prefix(0); + ASSERT_EQ(c, a); + c.remove_prefix(c.size()); + ASSERT_EQ(c, e); + + // remove_suffix + c = a; + c.remove_suffix(3); + ASSERT_EQ(c, TestFixture::as_string("foo")); + c = a; + c.remove_suffix(0); + ASSERT_EQ(c, a); + c.remove_suffix(c.size()); + ASSERT_EQ(c, e); + + // set + c.set(foobar.c_str()); + ASSERT_EQ(c, a); + c.set(foobar.c_str(), 6); + ASSERT_EQ(c, a); + c.set(foobar.c_str(), 0); + ASSERT_EQ(c, e); + c.set(foobar.c_str(), 7); // Note, has an embedded NULL + ASSERT_NE(c, a); + + // as_string + TypeParam s3(a.as_string().c_str(), 7); // Note, has an embedded NULL + ASSERT_TRUE(c == s3); + TypeParam s4(e.as_string()); + ASSERT_TRUE(s4.empty()); +} + +TEST(StringPieceTest, CheckCustom) { + StringPiece a("foobar"); + std::string s1("123"); + s1 += '\0'; + s1 += "456"; + StringPiece b(s1); + StringPiece e; + std::string s2; + + // CopyToString + a.CopyToString(&s2); + ASSERT_EQ(s2.size(), 6U); + ASSERT_EQ(s2, "foobar"); + b.CopyToString(&s2); + ASSERT_EQ(s2.size(), 7U); + ASSERT_EQ(s1, s2); + e.CopyToString(&s2); + ASSERT_TRUE(s2.empty()); + + // AppendToString + s2.erase(); + a.AppendToString(&s2); + ASSERT_EQ(s2.size(), 6U); + ASSERT_EQ(s2, "foobar"); + a.AppendToString(&s2); + ASSERT_EQ(s2.size(), 12U); + ASSERT_EQ(s2, "foobarfoobar"); + + // starts_with + ASSERT_TRUE(a.starts_with(a)); + ASSERT_TRUE(a.starts_with("foo")); + ASSERT_TRUE(a.starts_with(e)); + ASSERT_TRUE(b.starts_with(s1)); + ASSERT_TRUE(b.starts_with(b)); + ASSERT_TRUE(b.starts_with(e)); + ASSERT_TRUE(e.starts_with("")); + ASSERT_TRUE(!a.starts_with(b)); + ASSERT_TRUE(!b.starts_with(a)); + ASSERT_TRUE(!e.starts_with(a)); + + // ends with + ASSERT_TRUE(a.ends_with(a)); + ASSERT_TRUE(a.ends_with("bar")); + ASSERT_TRUE(a.ends_with(e)); + ASSERT_TRUE(b.ends_with(s1)); + ASSERT_TRUE(b.ends_with(b)); + ASSERT_TRUE(b.ends_with(e)); + ASSERT_TRUE(e.ends_with("")); + ASSERT_TRUE(!a.ends_with(b)); + ASSERT_TRUE(!b.ends_with(a)); + ASSERT_TRUE(!e.ends_with(a)); + + StringPiece c; + c.set("foobar", 6); + ASSERT_EQ(c, a); + c.set("foobar", 0); + ASSERT_EQ(c, e); + c.set("foobar", 7); + ASSERT_NE(c, a); +} + +TYPED_TEST(CommonStringPieceTest, CheckNULL) { + // we used to crash here, but now we don't. + BasicStringPiece<TypeParam> s(NULL); + ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL); + ASSERT_EQ(s.size(), 0U); + + s.set(NULL); + ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL); + ASSERT_EQ(s.size(), 0U); + + TypeParam str = s.as_string(); + ASSERT_EQ(str.length(), 0U); + ASSERT_EQ(str, TypeParam()); +} + +TYPED_TEST(CommonStringPieceTest, CheckComparisons2) { + TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz")); + TypeParam alphabet_z(TestFixture::as_string("abcdefghijklmnopqrstuvwxyzz")); + TypeParam alphabet_y(TestFixture::as_string("abcdefghijklmnopqrstuvwxyy")); + BasicStringPiece<TypeParam> abc(alphabet); + + // check comparison operations on strings longer than 4 bytes. + ASSERT_TRUE(abc == BasicStringPiece<TypeParam>(alphabet)); + ASSERT_EQ(abc.compare(BasicStringPiece<TypeParam>(alphabet)), 0); + + ASSERT_TRUE(abc < BasicStringPiece<TypeParam>(alphabet_z)); + ASSERT_LT(abc.compare(BasicStringPiece<TypeParam>(alphabet_z)), 0); + + ASSERT_TRUE(abc > BasicStringPiece<TypeParam>(alphabet_y)); + ASSERT_GT(abc.compare(BasicStringPiece<TypeParam>(alphabet_y)), 0); +} + +// Test operations only supported by std::string version. +TEST(StringPieceTest, CheckComparisons2) { + StringPiece abc("abcdefghijklmnopqrstuvwxyz"); + + // starts_with + ASSERT_TRUE(abc.starts_with(abc)); + ASSERT_TRUE(abc.starts_with("abcdefghijklm")); + ASSERT_TRUE(!abc.starts_with("abcdefguvwxyz")); + + // ends_with + ASSERT_TRUE(abc.ends_with(abc)); + ASSERT_TRUE(!abc.ends_with("abcdefguvwxyz")); + ASSERT_TRUE(abc.ends_with("nopqrstuvwxyz")); +} + +TYPED_TEST(CommonStringPieceTest, StringCompareNotAmbiguous) { + ASSERT_TRUE(TestFixture::as_string("hello").c_str() == + TestFixture::as_string("hello")); + ASSERT_TRUE(TestFixture::as_string("hello").c_str() < + TestFixture::as_string("world")); +} + +TYPED_TEST(CommonStringPieceTest, HeterogenousStringPieceEquals) { + TypeParam hello(TestFixture::as_string("hello")); + + ASSERT_TRUE(BasicStringPiece<TypeParam>(hello) == hello); + ASSERT_TRUE(hello.c_str() == BasicStringPiece<TypeParam>(hello)); +} + +TYPED_TEST(CommonStringPieceTest, CheckConstructors) { + TypeParam str(TestFixture::as_string("hello world")); + TypeParam empty; + + ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str)); + ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str.c_str())); + ASSERT_TRUE(TestFixture::as_string("hello") == + BasicStringPiece<TypeParam>(str.c_str(), 5)); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(str.c_str(), + static_cast<typename BasicStringPiece<TypeParam>::size_type>(0))); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL)); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL, + static_cast<typename BasicStringPiece<TypeParam>::size_type>(0))); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>()); + ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str.begin(), str.end())); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(str.begin(), str.begin())); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty)); + ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty.begin(), empty.end())); +} + +} // namespace base diff --git a/third_party/chromium/base/strings/string_util.cc b/third_party/chromium/base/strings/string_util.cc new file mode 100644 index 0000000..4042b39 --- /dev/null +++ b/third_party/chromium/base/strings/string_util.cc @@ -0,0 +1,176 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/string_util.h" + +#include "base/strings/utf_string_conversion_utils.h" +#include "base/third_party/icu/icu_utf.h" + +namespace { + +typedef uintptr_t MachineWord; +const uintptr_t kMachineWordAlignmentMask = sizeof(MachineWord) - 1; + +inline bool IsAlignedToMachineWord(const void* pointer) { + return !(reinterpret_cast<MachineWord>(pointer) & kMachineWordAlignmentMask); +} + +template<typename T> inline T* AlignToMachineWord(T* pointer) { + return reinterpret_cast<T*>(reinterpret_cast<MachineWord>(pointer) & + ~kMachineWordAlignmentMask); +} + +template<size_t size, typename CharacterType> struct NonASCIIMask; +template<> struct NonASCIIMask<4, char> { + static inline uint32_t value() { return 0x80808080U; } +}; +template<> struct NonASCIIMask<8, char> { + static inline uint64_t value() { return 0x8080808080808080ULL; } +}; + +} // namespace + +namespace base { + +template<typename STR> +bool ReplaceCharsT(const STR& input, + const STR& replace_chars, + const STR& replace_with, + STR* output) { + bool removed = false; + size_t replace_length = replace_with.length(); + + *output = input; + + size_t found = output->find_first_of(replace_chars); + while (found != STR::npos) { + removed = true; + output->replace(found, 1, replace_with); + found = output->find_first_of(replace_chars, found + replace_length); + } + + return removed; +} + +bool ReplaceChars(const std::string& input, + const base::StringPiece& replace_chars, + const std::string& replace_with, + std::string* output) { + return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output); +} + +template<typename Str> +TrimPositions TrimStringT(const Str& input, + BasicStringPiece<Str> trim_chars, + TrimPositions positions, + Str* output) { + // Find the edges of leading/trailing whitespace as desired. Need to use + // a StringPiece version of input to be able to call find* on it with the + // StringPiece version of trim_chars (normally the trim_chars will be a + // constant so avoid making a copy). + BasicStringPiece<Str> input_piece(input); + const size_t last_char = input.length() - 1; + const size_t first_good_char = (positions & TRIM_LEADING) ? + input_piece.find_first_not_of(trim_chars) : 0; + const size_t last_good_char = (positions & TRIM_TRAILING) ? + input_piece.find_last_not_of(trim_chars) : last_char; + + // When the string was all trimmed, report that we stripped off characters + // from whichever position the caller was interested in. For empty input, we + // stripped no characters, but we still need to clear |output|. + if (input.empty() || + (first_good_char == Str::npos) || (last_good_char == Str::npos)) { + bool input_was_empty = input.empty(); // in case output == &input + output->clear(); + return input_was_empty ? TRIM_NONE : positions; + } + + // Trim. + *output = + input.substr(first_good_char, last_good_char - first_good_char + 1); + + // Return where we trimmed from. + return static_cast<TrimPositions>( + ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) | + ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING)); +} + +bool TrimString(const std::string& input, + base::StringPiece trim_chars, + std::string* output) { + return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE; +} + +template<typename Str> +BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input, + BasicStringPiece<Str> trim_chars, + TrimPositions positions) { + size_t begin = (positions & TRIM_LEADING) ? + input.find_first_not_of(trim_chars) : 0; + size_t end = (positions & TRIM_TRAILING) ? + input.find_last_not_of(trim_chars) + 1 : input.size(); + return input.substr(begin, end - begin); +} + +StringPiece TrimString(StringPiece input, + const base::StringPiece& trim_chars, + TrimPositions positions) { + return TrimStringPieceT(input, trim_chars, positions); +} + +TrimPositions TrimWhitespaceASCII(const std::string& input, + TrimPositions positions, + std::string* output) { + return TrimStringT(input, StringPiece(kWhitespaceASCII), positions, output); +} + +template <class Char> +inline bool DoIsStringASCII(const Char* characters, size_t length) { + MachineWord all_char_bits = 0; + const Char* end = characters + length; + + // Prologue: align the input. + while (!IsAlignedToMachineWord(characters) && characters != end) { + all_char_bits |= *characters; + ++characters; + } + + // Compare the values of CPU word size. + const Char* word_end = AlignToMachineWord(end); + const size_t loop_increment = sizeof(MachineWord) / sizeof(Char); + while (characters < word_end) { + all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters)); + characters += loop_increment; + } + + // Process the remaining bytes. + while (characters != end) { + all_char_bits |= *characters; + ++characters; + } + + MachineWord non_ascii_bit_mask = + NonASCIIMask<sizeof(MachineWord), Char>::value(); + return !(all_char_bits & non_ascii_bit_mask); +} + +bool IsStringASCII(const StringPiece& str) { + return DoIsStringASCII(str.data(), str.length()); +} + +bool IsStringUTF8(const StringPiece& str) { + const char *src = str.data(); + int32 src_len = static_cast<int32>(str.length()); + int32 char_index = 0; + + while (char_index < src_len) { + int32 code_point; + CBU8_NEXT(src, char_index, src_len, code_point); + if (!IsValidCharacter(code_point)) + return false; + } + return true; +} + +} // namespace base diff --git a/third_party/chromium/base/strings/string_util.h b/third_party/chromium/base/strings/string_util.h new file mode 100644 index 0000000..4b41357 --- /dev/null +++ b/third_party/chromium/base/strings/string_util.h @@ -0,0 +1,133 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file defines utility functions for working with strings. + +#ifndef BASE_STRINGS_STRING_UTIL_H_ +#define BASE_STRINGS_STRING_UTIL_H_ + +#include <ctype.h> +#include <stdarg.h> // va_list + +#include <string> +#include <vector> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/strings/string_piece.h" // For implicit conversions. + +// On Android, bionic's stdio.h defines an snprintf macro when being built with +// clang. Undefine it here so it won't collide with base::snprintf(). +#undef snprintf + +namespace base { + +// C standard-library functions like "strncasecmp" and "snprintf" that aren't +// cross-platform are provided as "base::strncasecmp", and their prototypes +// are listed below. These functions are then implemented as inline calls +// to the platform-specific equivalents in the platform-specific headers. + +// Wrapper for vsnprintf that always null-terminates and always returns the +// number of characters that would be in an untruncated formatted +// string, even when truncation occurs. +int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments) + PRINTF_FORMAT(3, 0); + +// Some of these implementations need to be inlined. + +// We separate the declaration from the implementation of this inline +// function just so the PRINTF_FORMAT works. +inline int snprintf(char* buffer, size_t size, const char* format, ...) + PRINTF_FORMAT(3, 4); +inline int snprintf(char* buffer, size_t size, const char* format, ...) { + va_list arguments; + va_start(arguments, format); + int result = vsnprintf(buffer, size, format, arguments); + va_end(arguments); + return result; +} + +// Contains the set of characters representing whitespace in the corresponding +// encoding. Null-terminated. The ASCII versions are the whitespaces as defined +// by HTML5, and don't include control characters. +extern const char kWhitespaceASCII[]; + +// Replaces characters in |replace_chars| from anywhere in |input| with +// |replace_with|. Each character in |replace_chars| will be replaced with +// the |replace_with| string. Returns true if any characters were replaced. +// |replace_chars| must be null-terminated. +// NOTE: Safe to use the same variable for both |input| and |output|. +bool ReplaceChars(const std::string& input, + const base::StringPiece& replace_chars, + const std::string& replace_with, + std::string* output); + +enum TrimPositions { + TRIM_NONE = 0, + TRIM_LEADING = 1 << 0, + TRIM_TRAILING = 1 << 1, + TRIM_ALL = TRIM_LEADING | TRIM_TRAILING, +}; + +// Removes characters in |trim_chars| from the beginning and end of |input|. +// The 8-bit version only works on 8-bit characters, not UTF-8. +// +// It is safe to use the same variable for both |input| and |output| (this is +// the normal usage to trim in-place). +bool TrimString(const std::string& input, + base::StringPiece trim_chars, + std::string* output); + +// StringPiece versions of the above. The returned pieces refer to the original +// buffer. +StringPiece TrimString(StringPiece input, + const base::StringPiece& trim_chars, + TrimPositions positions); + +// Trims any whitespace from either end of the input string. Returns where +// whitespace was found. +// The non-wide version has two functions: +// * TrimWhitespaceASCII() +// This function is for ASCII strings and only looks for ASCII whitespace; +// Please choose the best one according to your usage. +// NOTE: Safe to use the same variable for both input and output. +TrimPositions TrimWhitespaceASCII(const std::string& input, + TrimPositions positions, + std::string* output); + +// Deprecated. This function is only for backward compatibility and calls +// TrimWhitespaceASCII(). +TrimPositions TrimWhitespace(const std::string& input, + TrimPositions positions, + std::string* output); + +// Returns true if the specified string matches the criteria. How can a wide +// string be 8-bit or UTF8? It contains only characters that are < 256 (in the +// first case) or characters that use only 8-bits and whose 8-bit +// representation looks like a UTF-8 string (the second case). +// +// Note that IsStringUTF8 checks not only if the input is structurally +// valid but also if it doesn't contain any non-character codepoint +// (e.g. U+FFFE). It's done on purpose because all the existing callers want +// to have the maximum 'discriminating' power from other encodings. If +// there's a use case for just checking the structural validity, we have to +// add a new function for that. +// +// IsStringASCII assumes the input is likely all ASCII, and does not leave early +// if it is not the case. +bool IsStringUTF8(const StringPiece& str); +bool IsStringASCII(const StringPiece& str); + +} // namespace base + +#if defined(OS_WIN) +#include "base/strings/string_util_win.h" +#elif defined(OS_POSIX) +#include "base/strings/string_util_posix.h" +#else +#error Define string operations appropriately for your platform +#endif + +#endif // BASE_STRINGS_STRING_UTIL_H_ diff --git a/third_party/chromium/base/strings/string_util_constants.cc b/third_party/chromium/base/strings/string_util_constants.cc new file mode 100644 index 0000000..905294c --- /dev/null +++ b/third_party/chromium/base/strings/string_util_constants.cc @@ -0,0 +1,47 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/string_util.h" + +namespace base { + +#define WHITESPACE_UNICODE \ + 0x0009, /* CHARACTER TABULATION */ \ + 0x000A, /* LINE FEED (LF) */ \ + 0x000B, /* LINE TABULATION */ \ + 0x000C, /* FORM FEED (FF) */ \ + 0x000D, /* CARRIAGE RETURN (CR) */ \ + 0x0020, /* SPACE */ \ + 0x0085, /* NEXT LINE (NEL) */ \ + 0x00A0, /* NO-BREAK SPACE */ \ + 0x1680, /* OGHAM SPACE MARK */ \ + 0x2000, /* EN QUAD */ \ + 0x2001, /* EM QUAD */ \ + 0x2002, /* EN SPACE */ \ + 0x2003, /* EM SPACE */ \ + 0x2004, /* THREE-PER-EM SPACE */ \ + 0x2005, /* FOUR-PER-EM SPACE */ \ + 0x2006, /* SIX-PER-EM SPACE */ \ + 0x2007, /* FIGURE SPACE */ \ + 0x2008, /* PUNCTUATION SPACE */ \ + 0x2009, /* THIN SPACE */ \ + 0x200A, /* HAIR SPACE */ \ + 0x2028, /* LINE SEPARATOR */ \ + 0x2029, /* PARAGRAPH SEPARATOR */ \ + 0x202F, /* NARROW NO-BREAK SPACE */ \ + 0x205F, /* MEDIUM MATHEMATICAL SPACE */ \ + 0x3000, /* IDEOGRAPHIC SPACE */ \ + 0 + +const char kWhitespaceASCII[] = { + 0x09, // CHARACTER TABULATION + 0x0A, // LINE FEED (LF) + 0x0B, // LINE TABULATION + 0x0C, // FORM FEED (FF) + 0x0D, // CARRIAGE RETURN (CR) + 0x20, // SPACE + 0 +}; + +} // namespace base diff --git a/third_party/chromium/base/strings/string_util_posix.h b/third_party/chromium/base/strings/string_util_posix.h new file mode 100644 index 0000000..ccfff10 --- /dev/null +++ b/third_party/chromium/base/strings/string_util_posix.h @@ -0,0 +1,24 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_STRINGS_STRING_UTIL_POSIX_H_ +#define BASE_STRINGS_STRING_UTIL_POSIX_H_ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <wchar.h> + +#include "base/logging.h" + +namespace base { + +inline int vsnprintf(char* buffer, size_t size, + const char* format, va_list arguments) { + return ::vsnprintf(buffer, size, format, arguments); +} + +} // namespace base + +#endif // BASE_STRINGS_STRING_UTIL_POSIX_H_ diff --git a/third_party/chromium/base/strings/string_util_unittest.cc b/third_party/chromium/base/strings/string_util_unittest.cc new file mode 100644 index 0000000..1a75218 --- /dev/null +++ b/third_party/chromium/base/strings/string_util_unittest.cc @@ -0,0 +1,148 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/string_util.h" + +#include <math.h> +#include <stdarg.h> + +#include <algorithm> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "base/basictypes.h" +#include "base/strings/utf_string_conversion_utils.h" + +using ::testing::ElementsAre; + +namespace base { + +TEST(StringUtilTest, IsStringUTF8) { + EXPECT_TRUE(IsStringUTF8("abc")); + EXPECT_TRUE(IsStringUTF8("\xc2\x81")); + EXPECT_TRUE(IsStringUTF8("\xe1\x80\xbf")); + EXPECT_TRUE(IsStringUTF8("\xf1\x80\xa0\xbf")); + EXPECT_TRUE(IsStringUTF8("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf")); + EXPECT_TRUE(IsStringUTF8("\xef\xbb\xbf" "abc")); // UTF-8 BOM + + // surrogate code points + EXPECT_FALSE(IsStringUTF8("\xed\xa0\x80\xed\xbf\xbf")); + EXPECT_FALSE(IsStringUTF8("\xed\xa0\x8f")); + EXPECT_FALSE(IsStringUTF8("\xed\xbf\xbf")); + + // overlong sequences + EXPECT_FALSE(IsStringUTF8("\xc0\x80")); // U+0000 + EXPECT_FALSE(IsStringUTF8("\xc1\x80\xc1\x81")); // "AB" + EXPECT_FALSE(IsStringUTF8("\xe0\x80\x80")); // U+0000 + EXPECT_FALSE(IsStringUTF8("\xe0\x82\x80")); // U+0080 + EXPECT_FALSE(IsStringUTF8("\xe0\x9f\xbf")); // U+07ff + EXPECT_FALSE(IsStringUTF8("\xf0\x80\x80\x8D")); // U+000D + EXPECT_FALSE(IsStringUTF8("\xf0\x80\x82\x91")); // U+0091 + EXPECT_FALSE(IsStringUTF8("\xf0\x80\xa0\x80")); // U+0800 + EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbb\xbf")); // U+FEFF (BOM) + EXPECT_FALSE(IsStringUTF8("\xf8\x80\x80\x80\xbf")); // U+003F + EXPECT_FALSE(IsStringUTF8("\xfc\x80\x80\x80\xa0\xa5")); // U+00A5 + + // Beyond U+10FFFF (the upper limit of Unicode codespace) + EXPECT_FALSE(IsStringUTF8("\xf4\x90\x80\x80")); // U+110000 + EXPECT_FALSE(IsStringUTF8("\xf8\xa0\xbf\x80\xbf")); // 5 bytes + EXPECT_FALSE(IsStringUTF8("\xfc\x9c\xbf\x80\xbf\x80")); // 6 bytes + + // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE) + EXPECT_FALSE(IsStringUTF8("\xfe\xff")); + EXPECT_FALSE(IsStringUTF8("\xff\xfe")); + EXPECT_FALSE(IsStringUTF8(std::string("\x00\x00\xfe\xff", 4))); + EXPECT_FALSE(IsStringUTF8("\xff\xfe\x00\x00")); + + // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and <FDD0,FDEF> + EXPECT_FALSE(IsStringUTF8("\xef\xbf\xbe")); // U+FFFE) + EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbf\xbe")); // U+1FFFE + EXPECT_FALSE(IsStringUTF8("\xf3\xbf\xbf\xbf")); // U+10FFFF + EXPECT_FALSE(IsStringUTF8("\xef\xb7\x90")); // U+FDD0 + EXPECT_FALSE(IsStringUTF8("\xef\xb7\xaf")); // U+FDEF + // Strings in legacy encodings. We can certainly make up strings + // in a legacy encoding that are valid in UTF-8, but in real data, + // most of them are invalid as UTF-8. + EXPECT_FALSE(IsStringUTF8("caf\xe9")); // cafe with U+00E9 in ISO-8859-1 + EXPECT_FALSE(IsStringUTF8("\xb0\xa1\xb0\xa2")); // U+AC00, U+AC001 in EUC-KR + EXPECT_FALSE(IsStringUTF8("\xa7\x41\xa6\x6e")); // U+4F60 U+597D in Big5 + // "abc" with U+201[CD] in windows-125[0-8] + EXPECT_FALSE(IsStringUTF8("\x93" "abc\x94")); + // U+0639 U+064E U+0644 U+064E in ISO-8859-6 + EXPECT_FALSE(IsStringUTF8("\xd9\xee\xe4\xee")); + // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7 + EXPECT_FALSE(IsStringUTF8("\xe3\xe5\xe9\xdC")); + + // Check that we support Embedded Nulls. The first uses the canonical UTF-8 + // representation, and the second uses a 2-byte sequence. The second version + // is invalid UTF-8 since UTF-8 states that the shortest encoding for a + // given codepoint must be used. + static const char kEmbeddedNull[] = "embedded\0null"; + EXPECT_TRUE(IsStringUTF8( + std::string(kEmbeddedNull, sizeof(kEmbeddedNull)))); + EXPECT_FALSE(IsStringUTF8("embedded\xc0\x80U+0000")); +} + +TEST(StringUtilTest, IsStringASCII) { + static char char_ascii[] = + "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"; + static std::wstring wchar_ascii( + L"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"); + + // Test a variety of the fragment start positions and lengths in order to make + // sure that bit masking in IsStringASCII works correctly. + // Also, test that a non-ASCII character will be detected regardless of its + // position inside the string. + { + const size_t string_length = arraysize(char_ascii) - 1; + for (size_t offset = 0; offset < 8; ++offset) { + for (size_t len = 0, max_len = string_length - offset; len < max_len; + ++len) { + EXPECT_TRUE(IsStringASCII(StringPiece(char_ascii + offset, len))); + for (size_t char_pos = offset; char_pos < len; ++char_pos) { + char_ascii[char_pos] |= '\x80'; + EXPECT_FALSE(IsStringASCII(StringPiece(char_ascii + offset, len))); + char_ascii[char_pos] &= ~'\x80'; + } + } + } + } +} + +TEST(StringUtilTest, ReplaceChars) { + struct TestData { + const char* input; + const char* replace_chars; + const char* replace_with; + const char* output; + bool result; + } cases[] = { + { "", "", "", "", false }, + { "test", "", "", "test", false }, + { "test", "", "!", "test", false }, + { "test", "z", "!", "test", false }, + { "test", "e", "!", "t!st", true }, + { "test", "e", "!?", "t!?st", true }, + { "test", "ez", "!", "t!st", true }, + { "test", "zed", "!?", "t!?st", true }, + { "test", "t", "!?", "!?es!?", true }, + { "test", "et", "!>", "!>!>s!>", true }, + { "test", "zest", "!", "!!!!", true }, + { "test", "szt", "!", "!e!!", true }, + { "test", "t", "test", "testestest", true }, + }; + + for (size_t i = 0; i < arraysize(cases); ++i) { + std::string output; + bool result = ReplaceChars(cases[i].input, + cases[i].replace_chars, + cases[i].replace_with, + &output); + EXPECT_EQ(cases[i].result, result); + EXPECT_EQ(cases[i].output, output); + } +} + +} // namespace base diff --git a/third_party/chromium/base/strings/stringprintf.cc b/third_party/chromium/base/strings/stringprintf.cc new file mode 100644 index 0000000..5f1ad9b --- /dev/null +++ b/third_party/chromium/base/strings/stringprintf.cc @@ -0,0 +1,139 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/stringprintf.h" + +#include <errno.h> + +#include <vector> + +#include "base/logging.h" +#include "base/scoped_clear_errno.h" +#include "base/strings/string_util.h" + +namespace base { + +namespace { + +// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter +// is the size of the buffer. These return the number of characters in the +// formatted string excluding the NUL terminator. If the buffer is not +// large enough to accommodate the formatted string without truncation, they +// return the number of characters that would be in the fully-formatted string +// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms). +inline int vsnprintfT(char* buffer, + size_t buf_size, + const char* format, + va_list argptr) { + return base::vsnprintf(buffer, buf_size, format, argptr); +} + +// Templatized backend for StringPrintF/StringAppendF. This does not finalize +// the va_list, the caller is expected to do that. +template <class StringType> +static void StringAppendVT(StringType* dst, + const typename StringType::value_type* format, + va_list ap) { + // First try with a small fixed size buffer. + // This buffer size should be kept in sync with StringUtilTest.GrowBoundary + // and StringUtilTest.StringPrintfBounds. + typename StringType::value_type stack_buf[1024]; + + va_list ap_copy; + va_copy(ap_copy, ap); + +#if !defined(OS_WIN) + ScopedClearErrno clear_errno; +#endif + int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy); + va_end(ap_copy); + + if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) { + // It fit. + dst->append(stack_buf, result); + return; + } + + // Repeatedly increase buffer size until it fits. + int mem_length = arraysize(stack_buf); + while (true) { + if (result < 0) { +#if defined(OS_WIN) + // On Windows, vsnprintfT always returns the number of characters in a + // fully-formatted string, so if we reach this point, something else is + // wrong and no amount of buffer-doubling is going to fix it. + return; +#else + if (errno != 0 && errno != EOVERFLOW) + return; + // Try doubling the buffer size. + mem_length *= 2; +#endif + } else { + // We need exactly "result + 1" characters. + mem_length = result + 1; + } + + if (mem_length > 32 * 1024 * 1024) { + // That should be plenty, don't try anything larger. This protects + // against huge allocations when using vsnprintfT implementations that + // return -1 for reasons other than overflow without setting errno. + DLOG(WARNING) << "Unable to printf the requested string due to size."; + return; + } + + std::vector<typename StringType::value_type> mem_buf(mem_length); + + // NOTE: You can only use a va_list once. Since we're in a while loop, we + // need to make a new copy each time so we don't use up the original. + va_copy(ap_copy, ap); + result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy); + va_end(ap_copy); + + if ((result >= 0) && (result < mem_length)) { + // It fit. + dst->append(&mem_buf[0], result); + return; + } + } +} + +} // namespace + +std::string StringPrintf(const char* format, ...) { + va_list ap; + va_start(ap, format); + std::string result; + StringAppendV(&result, format, ap); + va_end(ap); + return result; +} + +std::string StringPrintV(const char* format, va_list ap) { + std::string result; + StringAppendV(&result, format, ap); + return result; +} + +const std::string& SStringPrintf(std::string* dst, const char* format, ...) { + va_list ap; + va_start(ap, format); + dst->clear(); + StringAppendV(dst, format, ap); + va_end(ap); + return *dst; +} + +void StringAppendF(std::string* dst, const char* format, ...) { + va_list ap; + va_start(ap, format); + StringAppendV(dst, format, ap); + va_end(ap); +} + +void StringAppendV(std::string* dst, const char* format, va_list ap) { + StringAppendVT(dst, format, ap); +} + +} // namespace base diff --git a/third_party/chromium/base/strings/stringprintf.h b/third_party/chromium/base/strings/stringprintf.h new file mode 100644 index 0000000..06962b7 --- /dev/null +++ b/third_party/chromium/base/strings/stringprintf.h @@ -0,0 +1,40 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_STRINGS_STRINGPRINTF_H_ +#define BASE_STRINGS_STRINGPRINTF_H_ + +#include <stdarg.h> // va_list + +#include <string> + +#include "base/base_export.h" +#include "base/compiler_specific.h" + +namespace base { + +// Return a C++ string given printf-like input. +std::string StringPrintf(const char* format, ...) + PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT; + +// Return a C++ string given vprintf-like input. +std::string StringPrintV(const char* format, va_list ap) + PRINTF_FORMAT(1, 0) WARN_UNUSED_RESULT; + +// Store result into a supplied string and return it. +const std::string& SStringPrintf(std::string* dst, const char* format, ...) + PRINTF_FORMAT(2, 3); + +// Append result to a supplied string. +void StringAppendF(std::string* dst, const char* format, ...) + PRINTF_FORMAT(2, 3); + +// Lower-level routine that takes a va_list and appends to a specified +// string. All other routines are just convenience wrappers around it. +void StringAppendV(std::string* dst, const char* format, va_list ap) + PRINTF_FORMAT(2, 0); + +} // namespace base + +#endif // BASE_STRINGS_STRINGPRINTF_H_ diff --git a/third_party/chromium/base/strings/stringprintf_unittest.cc b/third_party/chromium/base/strings/stringprintf_unittest.cc new file mode 100644 index 0000000..88a9675 --- /dev/null +++ b/third_party/chromium/base/strings/stringprintf_unittest.cc @@ -0,0 +1,173 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/stringprintf.h" + +#include <errno.h> + +#include <gtest/gtest.h> + +#include "base/basictypes.h" + +namespace base { + +namespace { + +// A helper for the StringAppendV test that follows. +// +// Just forwards its args to StringAppendV. +static void StringAppendVTestHelper(std::string* out, const char* format, ...) { + va_list ap; + va_start(ap, format); + StringAppendV(out, format, ap); + va_end(ap); +} + +} // namespace + +TEST(StringPrintfTest, StringPrintfEmpty) { + EXPECT_EQ("", StringPrintf("%s", "")); +} + +TEST(StringPrintfTest, StringPrintfMisc) { + EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w')); +#if defined(OS_WIN) + EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w')); +#endif +} + +TEST(StringPrintfTest, StringAppendfEmptyString) { + std::string value("Hello"); + StringAppendF(&value, "%s", ""); + EXPECT_EQ("Hello", value); + +#if defined(OS_WIN) + std::wstring valuew(L"Hello"); + StringAppendF(&valuew, L"%ls", L""); + EXPECT_EQ(L"Hello", valuew); +#endif +} + +TEST(StringPrintfTest, StringAppendfString) { + std::string value("Hello"); + StringAppendF(&value, " %s", "World"); + EXPECT_EQ("Hello World", value); + +#if defined(OS_WIN) + std::wstring valuew(L"Hello"); + StringAppendF(&valuew, L" %ls", L"World"); + EXPECT_EQ(L"Hello World", valuew); +#endif +} + +TEST(StringPrintfTest, StringAppendfInt) { + std::string value("Hello"); + StringAppendF(&value, " %d", 123); + EXPECT_EQ("Hello 123", value); + +#if defined(OS_WIN) + std::wstring valuew(L"Hello"); + StringAppendF(&valuew, L" %d", 123); + EXPECT_EQ(L"Hello 123", valuew); +#endif +} + +// Make sure that lengths exactly around the initial buffer size are handled +// correctly. +TEST(StringPrintfTest, StringPrintfBounds) { + const int kSrcLen = 1026; + char src[kSrcLen]; + for (size_t i = 0; i < arraysize(src); i++) + src[i] = 'A'; + + for (int i = 1; i < 3; i++) { + src[kSrcLen - i] = 0; + std::string out; + SStringPrintf(&out, "%s", src); + EXPECT_STREQ(src, out.c_str()); + +#if defined(OS_WIN) + srcw[kSrcLen - i] = 0; + std::wstring outw; + SStringPrintf(&outw, L"%ls", srcw); + EXPECT_STREQ(srcw, outw.c_str()); +#endif + } +} + +// Test very large sprintfs that will cause the buffer to grow. +TEST(StringPrintfTest, Grow) { + char src[1026]; + for (size_t i = 0; i < arraysize(src); i++) + src[i] = 'A'; + src[1025] = 0; + + const char fmt[] = "%sB%sB%sB%sB%sB%sB%s"; + + std::string out; + SStringPrintf(&out, fmt, src, src, src, src, src, src, src); + + const int kRefSize = 320000; + char* ref = new char[kRefSize]; +#if defined(OS_WIN) + sprintf_s(ref, kRefSize, fmt, src, src, src, src, src, src, src); +#elif defined(OS_POSIX) + snprintf(ref, kRefSize, fmt, src, src, src, src, src, src, src); +#endif + + EXPECT_STREQ(ref, out.c_str()); + delete[] ref; +} + +TEST(StringPrintfTest, StringAppendV) { + std::string out; + StringAppendVTestHelper(&out, "%d foo %s", 1, "bar"); + EXPECT_EQ("1 foo bar", out); +} + +// Test the boundary condition for the size of the string_util's +// internal buffer. +TEST(StringPrintfTest, GrowBoundary) { + const int kStringUtilBufLen = 1024; + // Our buffer should be one larger than the size of StringAppendVT's stack + // buffer. + // And need extra one for NULL-terminator. + const int kBufLen = kStringUtilBufLen + 1 + 1; + char src[kBufLen]; + for (int i = 0; i < kBufLen - 1; ++i) + src[i] = 'a'; + src[kBufLen - 1] = 0; + + std::string out; + SStringPrintf(&out, "%s", src); + + EXPECT_STREQ(src, out.c_str()); +} + +// TODO(evanm): what's the proper cross-platform test here? +#if defined(OS_WIN) +// sprintf in Visual Studio fails when given U+FFFF. This tests that the +// failure case is gracefuly handled. +TEST(StringPrintfTest, Invalid) { + wchar_t invalid[2]; + invalid[0] = 0xffff; + invalid[1] = 0; + + std::wstring out; + SStringPrintf(&out, L"%ls", invalid); + EXPECT_STREQ(L"", out.c_str()); +} +#endif + +// Test that StringPrintf and StringAppendV do not change errno. +TEST(StringPrintfTest, StringPrintfErrno) { + errno = 1; + EXPECT_EQ("", StringPrintf("%s", "")); + EXPECT_EQ(1, errno); + std::string out; + StringAppendVTestHelper(&out, "%d foo %s", 1, "bar"); + EXPECT_EQ(1, errno); +} + +} // namespace base diff --git a/third_party/chromium/base/strings/utf_string_conversion_utils.cc b/third_party/chromium/base/strings/utf_string_conversion_utils.cc new file mode 100644 index 0000000..05bd122 --- /dev/null +++ b/third_party/chromium/base/strings/utf_string_conversion_utils.cc @@ -0,0 +1,90 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/strings/utf_string_conversion_utils.h" + +#include "base/third_party/icu/icu_utf.h" + +namespace base { + +// ReadUnicodeCharacter -------------------------------------------------------- + +bool ReadUnicodeCharacter(const char* src, + int32 src_len, + int32* char_index, + uint32* code_point_out) { + // U8_NEXT expects to be able to use -1 to signal an error, so we must + // use a signed type for code_point. But this function returns false + // on error anyway, so code_point_out is unsigned. + int32 code_point; + CBU8_NEXT(src, *char_index, src_len, code_point); + *code_point_out = static_cast<uint32>(code_point); + + // The ICU macro above moves to the next char, we want to point to the last + // char consumed. + (*char_index)--; + + // Validate the decoded value. + return IsValidCodepoint(code_point); +} + +// WriteUnicodeCharacter ------------------------------------------------------- + +size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) { + if (code_point <= 0x7f) { + // Fast path the common case of one byte. + output->push_back(static_cast<char>(code_point)); + return 1; + } + + + // CBU8_APPEND_UNSAFE can append up to 4 bytes. + size_t char_offset = output->length(); + size_t original_char_offset = char_offset; + output->resize(char_offset + CBU8_MAX_LENGTH); + + CBU8_APPEND_UNSAFE(&(*output)[0], char_offset, code_point); + + // CBU8_APPEND_UNSAFE will advance our pointer past the inserted character, so + // it will represent the new length of the string. + output->resize(char_offset); + return char_offset - original_char_offset; +} + +// Generalized Unicode converter ----------------------------------------------- + +template<typename CHAR> +void PrepareForUTF8Output(const CHAR* src, + size_t src_len, + std::string* output) { + output->clear(); + if (src_len == 0) + return; + if (src[0] < 0x80) { + // Assume that the entire input will be ASCII. + output->reserve(src_len); + } else { + // Assume that the entire input is non-ASCII and will have 3 bytes per char. + output->reserve(src_len * 3); + } +} + +template<typename STRING> +void PrepareForUTF16Or32Output(const char* src, + size_t src_len, + STRING* output) { + output->clear(); + if (src_len == 0) + return; + if (static_cast<unsigned char>(src[0]) < 0x80) { + // Assume the input is all ASCII, which means 1:1 correspondence. + output->reserve(src_len); + } else { + // Otherwise assume that the UTF-8 sequences will have 2 bytes for each + // character. + output->reserve(src_len / 2); + } +} + +} // namespace base diff --git a/third_party/chromium/base/strings/utf_string_conversion_utils.h b/third_party/chromium/base/strings/utf_string_conversion_utils.h new file mode 100644 index 0000000..d932d9f --- /dev/null +++ b/third_party/chromium/base/strings/utf_string_conversion_utils.h @@ -0,0 +1,88 @@ +// 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_STRINGS_UTF_STRING_CONVERSION_UTILS_H_ +#define BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_ + +#include <string> + +// This should only be used by the various UTF string conversion files. + +#include "base/base_export.h" +#include "base/basictypes.h" + +namespace base { + +inline bool IsValidCodepoint(uint32 code_point) { + // Excludes the surrogate code points ([0xD800, 0xDFFF]) and + // codepoints larger than 0x10FFFF (the highest codepoint allowed). + // Non-characters and unassigned codepoints are allowed. + return code_point < 0xD800u || + (code_point >= 0xE000u && code_point <= 0x10FFFFu); +} + +inline bool IsValidCharacter(uint32 code_point) { + // Excludes non-characters (U+FDD0..U+FDEF, and all codepoints ending in + // 0xFFFE or 0xFFFF) from the set of valid code points. + return code_point < 0xD800u || (code_point >= 0xE000u && + code_point < 0xFDD0u) || (code_point > 0xFDEFu && + code_point <= 0x10FFFFu && (code_point & 0xFFFEu) != 0xFFFEu); +} + +// ReadUnicodeCharacter -------------------------------------------------------- + +// Reads a UTF-8 stream, placing the next code point into the given output +// |*code_point|. |src| represents the entire string to read, and |*char_index| +// is the character offset within the string to start reading at. |*char_index| +// will be updated to index the last character read, such that incrementing it +// (as in a for loop) will take the reader to the next character. +// +// Returns true on success. On false, |*code_point| will be invalid. +bool ReadUnicodeCharacter(const char* src, + int32 src_len, + int32* char_index, + uint32* code_point_out); + +#if defined(WCHAR_T_IS_UTF32) +// Reads UTF-32 character. The usage is the same as the 8-bit version above. +bool ReadUnicodeCharacter(const wchar_t* src, + int32 src_len, + int32* char_index, + uint32* code_point); +#endif // defined(WCHAR_T_IS_UTF32) + +// WriteUnicodeCharacter ------------------------------------------------------- + +// Appends a UTF-8 character to the given 8-bit string. Returns the number of +// bytes written. +// TODO(brettw) Bug 79631: This function should not be exposed. +size_t WriteUnicodeCharacter(uint32 code_point, std::string* output); + +#if defined(WCHAR_T_IS_UTF32) +// Appends the given UTF-32 character to the given 32-bit string. Returns the +// number of 32-bit values written. +inline size_t WriteUnicodeCharacter(uint32 code_point, std::wstring* output) { + // This is the easy case, just append the character. + output->push_back(code_point); + return 1; +} +#endif // defined(WCHAR_T_IS_UTF32) + +// Generalized Unicode converter ----------------------------------------------- + +// Guesses the length of the output in UTF-8 in bytes, clears that output +// string, and reserves that amount of space. We assume that the input +// character types are unsigned, which will be true for UTF-16 and -32 on our +// systems. +template<typename CHAR> +void PrepareForUTF8Output(const CHAR* src, size_t src_len, std::string* output); + +// Prepares an output buffer (containing either UTF-16 or -32 data) given some +// UTF-8 input that will be converted to it. See PrepareForUTF8Output(). +template<typename STRING> +void PrepareForUTF16Or32Output(const char* src, size_t src_len, STRING* output); + +} // namespace base + +#endif // BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_ diff --git a/third_party/chromium/base/template_util.h b/third_party/chromium/base/template_util.h new file mode 100644 index 0000000..f8f507b --- /dev/null +++ b/third_party/chromium/base/template_util.h @@ -0,0 +1,33 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_TEMPLATE_UTIL_H_ +#define BASE_TEMPLATE_UTIL_H_ + +#include <cstddef> // For size_t. +#include <type_traits> + +#include "base/build/build_config.h" + +namespace base { + +template <class T> struct is_non_const_reference : std::false_type {}; +template <class T> struct is_non_const_reference<T&> : std::true_type {}; +template <class T> struct is_non_const_reference<const T&> : std::false_type {}; + +namespace internal { + +// Types YesType and NoType are guaranteed such that sizeof(YesType) < +// sizeof(NoType). +typedef char YesType; + +struct NoType { + YesType dummy[2]; +}; + +} // namespace internal + +} // namespace base + +#endif // BASE_TEMPLATE_UTIL_H_ diff --git a/third_party/chromium/base/template_util_unittest.cc b/third_party/chromium/base/template_util_unittest.cc new file mode 100644 index 0000000..7c86355 --- /dev/null +++ b/third_party/chromium/base/template_util_unittest.cc @@ -0,0 +1,117 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/template_util.h" + +#include <gtest/gtest.h> + +#include "base/basictypes.h" + +namespace base { +namespace { + +struct AStruct {}; +class AClass {}; +enum AnEnum {}; + +class Parent {}; +class Child : public Parent {}; + +using std::is_pointer; +using std::is_array; +using std::is_convertible; +using std::is_same; +using std::is_class; +using std::is_member_function_pointer; + +// is_pointer<Type> +COMPILE_ASSERT(!is_pointer<int>::value, IsPointer); +COMPILE_ASSERT(!is_pointer<int&>::value, IsPointer); +COMPILE_ASSERT(is_pointer<int*>::value, IsPointer); +COMPILE_ASSERT(is_pointer<const int*>::value, IsPointer); + +// is_array<Type> +COMPILE_ASSERT(!is_array<int>::value, IsArray); +COMPILE_ASSERT(!is_array<int*>::value, IsArray); +COMPILE_ASSERT(!is_array<int(*)[3]>::value, IsArray); +COMPILE_ASSERT(is_array<int[]>::value, IsArray); +COMPILE_ASSERT(is_array<const int[]>::value, IsArray); +COMPILE_ASSERT(is_array<int[3]>::value, IsArray); + +// is_non_const_reference<Type> +COMPILE_ASSERT(!is_non_const_reference<int>::value, IsNonConstReference); +COMPILE_ASSERT(!is_non_const_reference<const int&>::value, IsNonConstReference); +COMPILE_ASSERT(is_non_const_reference<int&>::value, IsNonConstReference); + +// is_convertible<From, To> + +// Extra parens needed to make preprocessor macro parsing happy. Otherwise, +// it sees the equivalent of: +// +// (is_convertible < Child), (Parent > ::value) +// +// Silly C++. +COMPILE_ASSERT( (is_convertible<Child, Parent>::value), IsConvertible); +COMPILE_ASSERT(!(is_convertible<Parent, Child>::value), IsConvertible); +COMPILE_ASSERT(!(is_convertible<Parent, AStruct>::value), IsConvertible); +COMPILE_ASSERT( (is_convertible<int, double>::value), IsConvertible); +COMPILE_ASSERT( (is_convertible<int*, void*>::value), IsConvertible); +COMPILE_ASSERT(!(is_convertible<void*, int*>::value), IsConvertible); + +// Array types are an easy corner case. Make sure to test that +// it does indeed compile. +COMPILE_ASSERT(!(is_convertible<int[10], double>::value), IsConvertible); +COMPILE_ASSERT(!(is_convertible<double, int[10]>::value), IsConvertible); +COMPILE_ASSERT( (is_convertible<int[10], int*>::value), IsConvertible); + +// is_same<Type1, Type2> +COMPILE_ASSERT(!(is_same<Child, Parent>::value), IsSame); +COMPILE_ASSERT(!(is_same<Parent, Child>::value), IsSame); +COMPILE_ASSERT( (is_same<Parent, Parent>::value), IsSame); +COMPILE_ASSERT( (is_same<int*, int*>::value), IsSame); +COMPILE_ASSERT( (is_same<int, int>::value), IsSame); +COMPILE_ASSERT( (is_same<void, void>::value), IsSame); +COMPILE_ASSERT(!(is_same<int, double>::value), IsSame); + + +// is_class<Type> +COMPILE_ASSERT(is_class<AStruct>::value, IsClass); +COMPILE_ASSERT(is_class<AClass>::value, IsClass); +COMPILE_ASSERT(!is_class<AnEnum>::value, IsClass); +COMPILE_ASSERT(!is_class<int>::value, IsClass); +COMPILE_ASSERT(!is_class<char*>::value, IsClass); +COMPILE_ASSERT(!is_class<int&>::value, IsClass); +COMPILE_ASSERT(!is_class<char[3]>::value, IsClass); + + +COMPILE_ASSERT(!is_member_function_pointer<int>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(!is_member_function_pointer<int*>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(!is_member_function_pointer<void*>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(!is_member_function_pointer<AStruct>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(!is_member_function_pointer<AStruct*>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(!is_member_function_pointer<void(*)()>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(!is_member_function_pointer<int(*)(int)>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(!is_member_function_pointer<int(*)(int, int)>::value, + IsMemberFunctionPointer); + +COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)()>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)(int)>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int)>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int) const>::value, + IsMemberFunctionPointer); +COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int, int)>::value, + IsMemberFunctionPointer); + +} // namespace +} // namespace base diff --git a/third_party/chromium/base/third_party/dmg_fp/LICENSE b/third_party/chromium/base/third_party/dmg_fp/LICENSE new file mode 100644 index 0000000..716f1ef --- /dev/null +++ b/third_party/chromium/base/third_party/dmg_fp/LICENSE @@ -0,0 +1,18 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ diff --git a/third_party/chromium/base/third_party/dmg_fp/README.chromium b/third_party/chromium/base/third_party/dmg_fp/README.chromium new file mode 100644 index 0000000..4538b7e --- /dev/null +++ b/third_party/chromium/base/third_party/dmg_fp/README.chromium @@ -0,0 +1,20 @@ +Name: David M. Gay's floating point routines +URL: http://www.netlib.org/fp/ +License: MIT-like + +Original dtoa.c file can be found at <http://www.netlib.org/fp/dtoa.c>. +Original g_fmt.c file can be found at <http://www.netlib.org/fp/g_fmt.c>. + +List of changes made to original code: + - wrapped functions in dmg_fp namespace + - renamed .c files to .cc + - added dmg_fp.h header + - added #define IEEE_8087 to dtoa.cc + - added #define NO_HEX_FP to dtoa.cc + - made some minor changes to allow clean compilation under g++ -Wall, see + gcc_warnings.patch. + - made some minor changes to build on 64-bit, see gcc_64_bit.patch. + - made minor changes for -Wextra for Mac build, see mac_wextra.patch + - crash fix for running with reduced CPU float precision, see + float_precision_crash.patch and crbug.com/123157 + - fixed warnings under msvc, see msvc_warnings.patch
\ No newline at end of file diff --git a/third_party/chromium/base/third_party/dmg_fp/dmg_fp.h b/third_party/chromium/base/third_party/dmg_fp/dmg_fp.h new file mode 100644 index 0000000..4795397 --- /dev/null +++ b/third_party/chromium/base/third_party/dmg_fp/dmg_fp.h @@ -0,0 +1,30 @@ +// Copyright (c) 2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_DMG_FP_H_ +#define THIRD_PARTY_DMG_FP_H_ + +namespace dmg_fp { + +// Return a nearest machine number to the input decimal +// string (or set errno to ERANGE). With IEEE arithmetic, ties are +// broken by the IEEE round-even rule. Otherwise ties are broken by +// biased rounding (add half and chop). +double strtod(const char* s00, char** se); + +// Convert double to ASCII string. For meaning of parameters +// see dtoa.cc file. +char* dtoa(double d, int mode, int ndigits, + int* decpt, int* sign, char** rve); + +// Must be used to free values returned by dtoa. +void freedtoa(char* s); + +// Store the closest decimal approximation to x in b (null terminated). +// Returns a pointer to b. It is sufficient for |b| to be 32 characters. +char* g_fmt(char* b, double x); + +} // namespace dmg_fp + +#endif // THIRD_PARTY_DMG_FP_H_ diff --git a/third_party/chromium/base/third_party/dmg_fp/dtoa.cc b/third_party/chromium/base/third_party/dmg_fp/dtoa.cc new file mode 100644 index 0000000..502c16c --- /dev/null +++ b/third_party/chromium/base/third_party/dmg_fp/dtoa.cc @@ -0,0 +1,4234 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_8087 for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_MC68k for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic (D_floating). + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. Unless Trust_FLT_ROUNDS + * is also #defined, fegetround() will be queried for the rounding mode. + * Note that both FLT_ROUNDS and fegetround() are specified by the C99 + * standard (and are specified to be consistent, with fesetround() + * affecting the value of FLT_ROUNDS), but that some (Linux) systems + * do not work correctly in this regard, so using fegetround() is more + * portable than using FLT_FOUNDS directly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. Similarly, if you + * want something other than the system's free() to be called to + * recycle memory acquired from MALLOC, #define FREE to be the + * name of the alternate routine. (FREE or free is only called in + * pathological cases, e.g., in a dtoa call after a dtoa return in + * mode 3 with thousands of digits requested.) + * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making + * memory allocations from a private pool of memory when possible. + * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, + * unless #defined to be a different length. This default length + * suffices to get rid of MALLOC calls except for unusual cases, + * such as decimal-to-binary conversion of a very long string of + * digits. The longest string dtoa can return is about 751 bytes + * long. For conversions by strtod of strings of 800 digits and + * all dtoa conversions in single-threaded executions with 8-byte + * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte + * pointers, PRIVATE_MEM >= 7112 appears adequate. + * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK + * #defined automatically on IEEE systems. On such systems, + * when INFNAN_CHECK is #defined, strtod checks + * for Infinity and NaN (case insensitively). On some systems + * (e.g., some HP systems), it may be necessary to #define NAN_WORD0 + * appropriately -- to the most significant word of a quiet NaN. + * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, + * strtod also accepts (case insensitively) strings of the form + * NaN(x), where x is a string of hexadecimal digits and spaces; + * if there is only one string of hexadecimal digits, it is taken + * for the 52 fraction bits of the resulting NaN; if there are two + * or more strings of hex digits, the first is for the high 20 bits, + * the second and subsequent for the low 32 bits, with intervening + * white space ignored; but if this results in none of the 52 + * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 + * and NAN_WORD1 are used instead. + * #define MULTIPLE_THREADS if the system offers preemptively scheduled + * multiple threads. In this case, you must provide (or suitably + * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #define USE_LOCALE to use the current locale's decimal_point value. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. + * #define NO_HEX_FP to omit recognition of hexadecimal floating-point + * values by strtod. + * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now) + * to disable logic for "fast" testing of very long input strings + * to strtod. This testing proceeds by initially truncating the + * input string, then if necessary comparing the whole string with + * a decimal expansion to decide close cases. This logic is only + * used for input more than STRTOD_DIGLIM digits long (default 40). + */ + +#define IEEE_8087 +#define NO_HEX_FP + +#ifndef Long +#if __LP64__ +#define Long int +#else +#define Long long +#endif +#endif +#ifndef ULong +typedef unsigned Long ULong; +#endif + +#ifdef DEBUG +#include "stdio.h" +#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#endif + +#include "stdlib.h" +#include "string.h" + +#ifdef USE_LOCALE +#include "locale.h" +#endif + +#ifdef Honor_FLT_ROUNDS +#ifndef Trust_FLT_ROUNDS +#include <fenv.h> +#endif +#endif + +#ifdef MALLOC +#ifdef KR_headers +extern char *MALLOC(); +#else +extern void *MALLOC(size_t); +#endif +#else +#define MALLOC malloc +#endif + +#ifndef Omit_Private_Memory +#ifndef PRIVATE_MEM +#define PRIVATE_MEM 2304 +#endif +#define PRIVATE_mem ((unsigned)((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))) +static double private_mem[PRIVATE_mem], *pmem_next = private_mem; +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow +#ifdef IEEE_MC68k +#define IEEE_Arith +#endif +#ifdef IEEE_8087 +#define IEEE_Arith +#endif + +#ifdef IEEE_Arith +#ifndef NO_INFNAN_CHECK +#undef INFNAN_CHECK +#define INFNAN_CHECK +#endif +#else +#undef INFNAN_CHECK +#define NO_STRTOD_BIGCOMP +#endif + +#include "errno.h" + +#ifdef Bad_float_h + +#ifdef IEEE_Arith +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 +#endif /*IEEE_Arith*/ + +#ifdef IBM +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 75 +#define DBL_MAX_EXP 63 +#define FLT_RADIX 16 +#define DBL_MAX 7.2370055773322621e+75 +#endif + +#ifdef VAX +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 38 +#define DBL_MAX_EXP 127 +#define FLT_RADIX 2 +#define DBL_MAX 1.7014118346046923e+38 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#else /* ifndef Bad_float_h */ +#include "float.h" +#endif /* Bad_float_h */ + +#ifndef __MATH_H__ +#include "math.h" +#endif + +namespace dmg_fp { + +#ifndef CONST +#ifdef KR_headers +#define CONST /* blank */ +#else +#define CONST const +#endif +#endif + +#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 +Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. +#endif + +typedef union { double d; ULong L[2]; } U; + +#ifdef IEEE_8087 +#define word0(x) (x)->L[1] +#define word1(x) (x)->L[0] +#else +#define word0(x) (x)->L[0] +#define word1(x) (x)->L[1] +#endif +#define dval(x) (x)->d + +#ifndef STRTOD_DIGLIM +#define STRTOD_DIGLIM 40 +#endif + +#ifdef DIGLIM_DEBUG +extern int strtod_diglim; +#else +#define strtod_diglim STRTOD_DIGLIM +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_8087) + defined(VAX) +#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ +((unsigned short *)a)[0] = (unsigned short)c, a++) +#else +#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ +((unsigned short *)a)[1] = (unsigned short)c, a++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#ifdef IEEE_Arith +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Nbits 53 +#define Bias 1023 +#define Emax 1023 +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS +#else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Nbits 56 +#define Bias 65 +#define Emax 248 +#define Emin (-260) +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Nbits 56 +#define Bias 129 +#define Emax 126 +#define Emin (-129) +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) a = rnd_prod(a, b) +#define rounded_quotient(a,b) a = rnd_quot(a, b) +#ifdef KR_headers +extern double rnd_prod(), rnd_quot(); +#else +extern double rnd_prod(double, double), rnd_quot(double, double); +#endif +#else +#define rounded_product(a,b) a *= b +#define rounded_quotient(a,b) a /= b +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Pack_32 +#define Pack_32 +#endif + +typedef struct BCinfo BCinfo; + struct +BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; }; + +#ifdef KR_headers +#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff) +#else +#define FFFFFFFF 0xffffffffUL +#endif + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ +#endif + +#define Kmax 7 + +double strtod(const char *s00, char **se); +char *dtoa(double d, int mode, int ndigits, + int *decpt, int *sign, char **rve); + + struct +Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; + }; + + typedef struct Bigint Bigint; + + static Bigint *freelist[Kmax+1]; + + static Bigint * +Balloc +#ifdef KR_headers + (k) int k; +#else + (int k) +#endif +{ + int x; + Bigint *rv; +#ifndef Omit_Private_Memory + unsigned int len; +#endif + + ACQUIRE_DTOA_LOCK(0); + /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ + /* but this case seems very unlikely. */ + if (k <= Kmax && freelist[k]) { + rv = freelist[k]; + freelist[k] = rv->next; + } + else { + x = 1 << k; +#ifdef Omit_Private_Memory + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); +#else + len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) + /sizeof(double); + if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { + rv = (Bigint*)pmem_next; + pmem_next += len; + } + else + rv = (Bigint*)MALLOC(len*sizeof(double)); +#endif + rv->k = k; + rv->maxwds = x; + } + FREE_DTOA_LOCK(0); + rv->sign = rv->wds = 0; + return rv; + } + + static void +Bfree +#ifdef KR_headers + (v) Bigint *v; +#else + (Bigint *v) +#endif +{ + if (v) { + if (v->k > Kmax) +#ifdef FREE + FREE((void*)v); +#else + free((void*)v); +#endif + else { + ACQUIRE_DTOA_LOCK(0); + v->next = freelist[v->k]; + freelist[v->k] = v; + FREE_DTOA_LOCK(0); + } + } + } + +#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ +y->wds*sizeof(Long) + 2*sizeof(int)) + + static Bigint * +multadd +#ifdef KR_headers + (b, m, a) Bigint *b; int m, a; +#else + (Bigint *b, int m, int a) /* multiply by m and add a */ +#endif +{ + int i, wds; +#ifdef ULLong + ULong *x; + ULLong carry, y; +#else + ULong carry, *x, y; +#ifdef Pack_32 + ULong xi, z; +#endif +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + carry; + carry = y >> 16; + *x++ = y & 0xffff; +#endif +#endif + } + while(++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = (ULong)carry; + b->wds = wds; + } + return b; + } + + static Bigint * +s2b +#ifdef KR_headers + (s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9; +#else + (CONST char *s, int nd0, int nd, ULong y9, int dplen) +#endif +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for(k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do b = multadd(b, 10, *s++ - '0'); + while(++i < nd0); + s += dplen; + } + else + s += dplen + 9; + for(; i < nd; i++) + b = multadd(b, 10, *s++ - '0'); + return b; + } + + static int +hi0bits +#ifdef KR_headers + (x) ULong x; +#else + (ULong x) +#endif +{ + int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; + } + + static int +lo0bits +#ifdef KR_headers + (y) ULong *y; +#else + (ULong *y) +#endif +{ + int k; + ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; + } + + static Bigint * +i2b +#ifdef KR_headers + (i) int i; +#else + (int i) +#endif +{ + Bigint *b; + + b = Balloc(1); + b->x[0] = i; + b->wds = 1; + return b; + } + + static Bigint * +mult +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; +#ifdef Pack_32 + ULong z2; +#endif +#endif + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + for(x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for(; xb < xbe; xc0++) { + y = *xb++; + if (y) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = z & FFFFFFFF; + } + while(x < xae); + *xc = (ULong)carry; + } + } +#else +#ifdef Pack_32 + for(; xb < xbe; xb++, xc0++) { + if (y = *xb & 0xffff) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } + while(x < xae); + *xc = carry; + } + if (y = *xb >> 16) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } + while(x < xae); + *xc = z2; + } + } +#else + for(; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } + while(x < xae); + *xc = carry; + } + } +#endif +#endif + for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; + } + + static Bigint *p5s; + + static Bigint * +pow5mult +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + Bigint *b1, *p5, *p51; + int i; + static int p05[3] = { 5, 25, 125 }; + + i = k & 3; + if (i) + b = multadd(b, p05[i-1], 0); + + if (!(k >>= 2)) + return b; + p5 = p5s; + if (!p5) { + /* first time */ +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + p5 = p5s; + if (!p5) { + p5 = p5s = i2b(625); + p5->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p5 = p5s = i2b(625); + p5->next = 0; +#endif + } + for(;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + } + if (!(k >>= 1)) + break; + p51 = p5->next; + if (!p51) { +#ifdef MULTIPLE_THREADS + ACQUIRE_DTOA_LOCK(1); + p51 = p5->next; + if (!p51) { + p51 = p5->next = mult(p5,p5); + p51->next = 0; + } + FREE_DTOA_LOCK(1); +#else + p51 = p5->next = mult(p5,p5); + p51->next = 0; +#endif + } + p5 = p51; + } + return b; + } + + static Bigint * +lshift +#ifdef KR_headers + (b, k) Bigint *b; int k; +#else + (Bigint *b, int k) +#endif +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for(i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + x1 = b1->x; + for(i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } + while(x < xe); + *x1 = z; + if (*x1) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } + while(x < xe); + if (*x1 = z) + ++n1; + } +#endif + else do + *x1++ = *x++; + while(x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; + } + + static int +cmp +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for(;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; + } + + static Bigint * +diff +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; +#ifdef Pack_32 + ULong z; +#endif +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = y & FFFFFFFF; + } +#else +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } + while(xb < xbe); + while(xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } + while(xb < xbe); + while(xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } +#endif +#endif + while(!*--xc) + wa--; + c->wds = wa; + return c; + } + + static double +ulp +#ifdef KR_headers + (x) U *x; +#else + (U *x) +#endif +{ + Long L; + U u; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(&u) = L; + word1(&u) = 0; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(&u) = 0x80000 >> L; + word1(&u) = 0; + } + else { + word0(&u) = 0; + L -= Exp_shift; + word1(&u) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif +#endif + return dval(&u); + } + + static double +b2d +#ifdef KR_headers + (a, e) Bigint *a; int *e; +#else + (Bigint *a, int *e) +#endif +{ + ULong *xa, *xa0, w, y, z; + int k; + U d; +#ifdef VAX + ULong d0, d1; +#else +#define d0 word0(&d) +#define d1 word1(&d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> (Ebits - k); + w = xa > xa0 ? *--xa : 0; + d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> (32 - k); + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> (32 - k); + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif + ret_d: +#ifdef VAX + word0(&d) = d0 >> 16 | d0 << 16; + word1(&d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return dval(&d); + } + + static Bigint * +d2b +#ifdef KR_headers + (d, e, bits) U *d; int *e, *bits; +#else + (U *d, int *e, int *bits) +#endif +{ + Bigint *b; + int de, k; + ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif +#ifdef VAX + ULong d0, d1; + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(d0 >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + de = (int)(d0 >> Exp_shift); + if (de) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + y = d1; + if (y) { + k = lo0bits(&y); + if (k) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; + x[1] = z; + b->wds = x[1] ? 2 : 1; +#ifndef Sudden_Underflow + i = b->wds; +#endif + } + else { + k = lo0bits(&z); + x[0] = z; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while(!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; + } +#undef d0 +#undef d1 + + static double +ratio +#ifdef KR_headers + (a, b) Bigint *a, *b; +#else + (Bigint *a, Bigint *b) +#endif +{ + U da, db; + int k, ka, kb; + + dval(&da) = b2d(a, &ka); + dval(&db) = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(&da) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(&da) *= 1 << k; + } + else { + k = -k; + word0(&db) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(&db) *= 1 << k; + } +#else + if (k > 0) + word0(&da) += k*Exp_msk1; + else { + k = -k; + word0(&db) += k*Exp_msk1; + } +#endif + return dval(&da) / dval(&db); + } + + static CONST double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif + }; + + static CONST double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-256 */ +#else + 1e-256 +#endif + }; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static CONST double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +#undef Need_Hexdig +#ifdef INFNAN_CHECK +#ifndef No_Hex_NaN +#define Need_Hexdig +#endif +#endif + +#ifndef Need_Hexdig +#ifndef NO_HEX_FP +#define Need_Hexdig +#endif +#endif + +#ifdef Need_Hexdig /*{*/ +static unsigned char hexdig[256]; + + static void +#ifdef KR_headers +htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc; +#else +htinit(unsigned char *h, unsigned char *s, int inc) +#endif +{ + int i, j; + for(i = 0; (j = s[i]) !=0; i++) + h[j] = (unsigned char)(i + inc); + } + + static void +#ifdef KR_headers +hexdig_init() +#else +hexdig_init(void) +#endif +{ +#define USC (unsigned char *) + htinit(hexdig, USC "0123456789", 0x10); + htinit(hexdig, USC "abcdef", 0x10 + 10); + htinit(hexdig, USC "ABCDEF", 0x10 + 10); + } +#endif /* } Need_Hexdig */ + +#ifdef INFNAN_CHECK + +#ifndef NAN_WORD0 +#define NAN_WORD0 0x7ff80000 +#endif + +#ifndef NAN_WORD1 +#define NAN_WORD1 0 +#endif + + static int +match +#ifdef KR_headers + (sp, t) char **sp, *t; +#else + (CONST char **sp, CONST char *t) +#endif +{ + int c, d; + CONST char *s = *sp; + + for(d = *t++; d; d = *t++) { + if ((c = *++s) >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != d) + return 0; + } + *sp = s + 1; + return 1; + } + +#ifndef No_Hex_NaN + static void +hexnan +#ifdef KR_headers + (rvp, sp) U *rvp; CONST char **sp; +#else + (U *rvp, CONST char **sp) +#endif +{ + ULong c, x[2]; + CONST char *s; + int c1, havedig, udx0, xshift; + + if (!hexdig['0']) + hexdig_init(); + x[0] = x[1] = 0; + havedig = xshift = 0; + udx0 = 1; + s = *sp; + /* allow optional initial 0x or 0X */ + for(c = *(CONST unsigned char*)(s+1); c && c <= ' '; c = *(CONST unsigned char*)(s+1)) + ++s; + if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')) + s += 2; + for(c = *(CONST unsigned char*)++s; c; c = *(CONST unsigned char*)++s) { + c1 = hexdig[c]; + if (c1) + c = c1 & 0xf; + else if (c <= ' ') { + if (udx0 && havedig) { + udx0 = 0; + xshift = 1; + } + continue; + } +#ifdef GDTOA_NON_PEDANTIC_NANCHECK + else if (/*(*/ c == ')' && havedig) { + *sp = s + 1; + break; + } + else + return; /* invalid form: don't change *sp */ +#else + else { + do { + if (/*(*/ c == ')') { + *sp = s + 1; + break; + } + c = *++s; + } while(c); + break; + } +#endif + havedig = 1; + if (xshift) { + xshift = 0; + x[0] = x[1]; + x[1] = 0; + } + if (udx0) + x[0] = (x[0] << 4) | (x[1] >> 28); + x[1] = (x[1] << 4) | c; + } + if ((x[0] &= 0xfffff) || x[1]) { + word0(rvp) = Exp_mask | x[0]; + word1(rvp) = x[1]; + } + } +#endif /*No_Hex_NaN*/ +#endif /* INFNAN_CHECK */ + +#ifdef Pack_32 +#define ULbits 32 +#define kshift 5 +#define kmask 31 +#else +#define ULbits 16 +#define kshift 4 +#define kmask 15 +#endif +#ifndef NO_HEX_FP /*{*/ + + static void +#ifdef KR_headers +rshift(b, k) Bigint *b; int k; +#else +rshift(Bigint *b, int k) +#endif +{ + ULong *x, *x1, *xe, y; + int n; + + x = x1 = b->x; + n = k >> kshift; + if (n < b->wds) { + xe = x + b->wds; + x += n; + if (k &= kmask) { + n = 32 - k; + y = *x++ >> k; + while(x < xe) { + *x1++ = (y | (*x << n)) & 0xffffffff; + y = *x++ >> k; + } + if ((*x1 = y) !=0) + x1++; + } + else + while(x < xe) + *x1++ = *x++; + } + if ((b->wds = x1 - b->x) == 0) + b->x[0] = 0; + } + + static ULong +#ifdef KR_headers +any_on(b, k) Bigint *b; int k; +#else +any_on(Bigint *b, int k) +#endif +{ + int n, nwds; + ULong *x, *x0, x1, x2; + + x = b->x; + nwds = b->wds; + n = k >> kshift; + if (n > nwds) + n = nwds; + else if (n < nwds && (k &= kmask)) { + x1 = x2 = x[n]; + x1 >>= k; + x1 <<= k; + if (x1 != x2) + return 1; + } + x0 = x; + x += n; + while(x > x0) + if (*--x) + return 1; + return 0; + } + +enum { /* rounding values: same as FLT_ROUNDS */ + Round_zero = 0, + Round_near = 1, + Round_up = 2, + Round_down = 3 + }; + + static Bigint * +#ifdef KR_headers +increment(b) Bigint *b; +#else +increment(Bigint *b) +#endif +{ + ULong *x, *xe; + Bigint *b1; + + x = b->x; + xe = x + b->wds; + do { + if (*x < (ULong)0xffffffffL) { + ++*x; + return b; + } + *x++ = 0; + } while(x < xe); + { + if (b->wds >= b->maxwds) { + b1 = Balloc(b->k+1); + Bcopy(b1,b); + Bfree(b); + b = b1; + } + b->x[b->wds++] = 1; + } + return b; + } + + void +#ifdef KR_headers +gethex(sp, rvp, rounding, sign) + CONST char **sp; U *rvp; int rounding, sign; +#else +gethex( CONST char **sp, U *rvp, int rounding, int sign) +#endif +{ + Bigint *b; + CONST unsigned char *decpt, *s0, *s, *s1; + Long e, e1; + ULong L, lostbits, *x; + int big, denorm, esign, havedig, k, n, nbits, up, zret; +#ifdef IBM + int j; +#endif + enum { +#ifdef IEEE_Arith /*{{*/ + emax = 0x7fe - Bias - P + 1, + emin = Emin - P + 1 +#else /*}{*/ + emin = Emin - P, +#ifdef VAX + emax = 0x7ff - Bias - P + 1 +#endif +#ifdef IBM + emax = 0x7f - Bias - P +#endif +#endif /*}}*/ + }; +#ifdef USE_LOCALE + int i; +#ifdef NO_LOCALE_CACHE + const unsigned char *decimalpoint = (unsigned char*) + localeconv()->decimal_point; +#else + const unsigned char *decimalpoint; + static unsigned char *decimalpoint_cache; + if (!(s0 = decimalpoint_cache)) { + s0 = (unsigned char*)localeconv()->decimal_point; + if ((decimalpoint_cache = (unsigned char*) + MALLOC(strlen((CONST char*)s0) + 1))) { + strcpy((char*)decimalpoint_cache, (CONST char*)s0); + s0 = decimalpoint_cache; + } + } + decimalpoint = s0; +#endif +#endif + + if (!hexdig['0']) + hexdig_init(); + havedig = 0; + s0 = *(CONST unsigned char **)sp + 2; + while(s0[havedig] == '0') + havedig++; + s0 += havedig; + s = s0; + decpt = 0; + zret = 0; + e = 0; + if (hexdig[*s]) + havedig++; + else { + zret = 1; +#ifdef USE_LOCALE + for(i = 0; decimalpoint[i]; ++i) { + if (s[i] != decimalpoint[i]) + goto pcheck; + } + decpt = s += i; +#else + if (*s != '.') + goto pcheck; + decpt = ++s; +#endif + if (!hexdig[*s]) + goto pcheck; + while(*s == '0') + s++; + if (hexdig[*s]) + zret = 0; + havedig = 1; + s0 = s; + } + while(hexdig[*s]) + s++; +#ifdef USE_LOCALE + if (*s == *decimalpoint && !decpt) { + for(i = 1; decimalpoint[i]; ++i) { + if (s[i] != decimalpoint[i]) + goto pcheck; + } + decpt = s += i; +#else + if (*s == '.' && !decpt) { + decpt = ++s; +#endif + while(hexdig[*s]) + s++; + }/*}*/ + if (decpt) + e = -(((Long)(s-decpt)) << 2); + pcheck: + s1 = s; + big = esign = 0; + switch(*s) { + case 'p': + case 'P': + switch(*++s) { + case '-': + esign = 1; + /* no break */ + case '+': + s++; + } + if ((n = hexdig[*s]) == 0 || n > 0x19) { + s = s1; + break; + } + e1 = n - 0x10; + while((n = hexdig[*++s]) !=0 && n <= 0x19) { + if (e1 & 0xf8000000) + big = 1; + e1 = 10*e1 + n - 0x10; + } + if (esign) + e1 = -e1; + e += e1; + } + *sp = (char*)s; + if (!havedig) + *sp = (char*)s0 - 1; + if (zret) + goto retz1; + if (big) { + if (esign) { +#ifdef IEEE_Arith + switch(rounding) { + case Round_up: + if (sign) + break; + goto ret_tiny; + case Round_down: + if (!sign) + break; + goto ret_tiny; + } +#endif + goto retz; +#ifdef IEEE_Arith + ret_tiny: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + word0(rvp) = 0; + word1(rvp) = 1; + return; +#endif /* IEEE_Arith */ + } + switch(rounding) { + case Round_near: + goto ovfl1; + case Round_up: + if (!sign) + goto ovfl1; + goto ret_big; + case Round_down: + if (sign) + goto ovfl1; + goto ret_big; + } + ret_big: + word0(rvp) = Big0; + word1(rvp) = Big1; + return; + } + n = s1 - s0 - 1; + for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) + k++; + b = Balloc(k); + x = b->x; + n = 0; + L = 0; +#ifdef USE_LOCALE + for(i = 0; decimalpoint[i+1]; ++i); +#endif + while(s1 > s0) { +#ifdef USE_LOCALE + if (*--s1 == decimalpoint[i]) { + s1 -= i; + continue; + } +#else + if (*--s1 == '.') + continue; +#endif + if (n == ULbits) { + *x++ = L; + L = 0; + n = 0; + } + L |= (hexdig[*s1] & 0x0f) << n; + n += 4; + } + *x++ = L; + b->wds = n = x - b->x; + n = ULbits*n - hi0bits(L); + nbits = Nbits; + lostbits = 0; + x = b->x; + if (n > nbits) { + n -= nbits; + if (any_on(b,n)) { + lostbits = 1; + k = n - 1; + if (x[k>>kshift] & 1 << (k & kmask)) { + lostbits = 2; + if (k > 0 && any_on(b,k)) + lostbits = 3; + } + } + rshift(b, n); + e += n; + } + else if (n < nbits) { + n = nbits - n; + b = lshift(b, n); + e -= n; + x = b->x; + } + if (e > Emax) { + ovfl: + Bfree(b); + ovfl1: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + word0(rvp) = Exp_mask; + word1(rvp) = 0; + return; + } + denorm = 0; + if (e < emin) { + denorm = 1; + n = emin - e; + if (n >= nbits) { +#ifdef IEEE_Arith /*{*/ + switch (rounding) { + case Round_near: + if (n == nbits && (n < 2 || any_on(b,n-1))) + goto ret_tiny; + break; + case Round_up: + if (!sign) + goto ret_tiny; + break; + case Round_down: + if (sign) + goto ret_tiny; + } +#endif /* } IEEE_Arith */ + Bfree(b); + retz: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + retz1: + rvp->d = 0.; + return; + } + k = n - 1; + if (lostbits) + lostbits = 1; + else if (k > 0) + lostbits = any_on(b,k); + if (x[k>>kshift] & 1 << (k & kmask)) + lostbits |= 2; + nbits -= n; + rshift(b,n); + e = emin; + } + if (lostbits) { + up = 0; + switch(rounding) { + case Round_zero: + break; + case Round_near: + if (lostbits & 2 + && (lostbits & 1) | (x[0] & 1)) + up = 1; + break; + case Round_up: + up = 1 - sign; + break; + case Round_down: + up = sign; + } + if (up) { + k = b->wds; + b = increment(b); + x = b->x; + if (denorm) { +#if 0 + if (nbits == Nbits - 1 + && x[nbits >> kshift] & 1 << (nbits & kmask)) + denorm = 0; /* not currently used */ +#endif + } + else if (b->wds > k + || ((n = nbits & kmask) !=0 + && hi0bits(x[k-1]) < 32-n)) { + rshift(b,1); + if (++e > Emax) + goto ovfl; + } + } + } +#ifdef IEEE_Arith + if (denorm) + word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0; + else + word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20); + word1(rvp) = b->x[0]; +#endif +#ifdef IBM + if ((j = e & 3)) { + k = b->x[0] & ((1 << j) - 1); + rshift(b,j); + if (k) { + switch(rounding) { + case Round_up: + if (!sign) + increment(b); + break; + case Round_down: + if (sign) + increment(b); + break; + case Round_near: + j = 1 << (j-1); + if (k & j && ((k & (j-1)) | lostbits)) + increment(b); + } + } + } + e >>= 2; + word0(rvp) = b->x[1] | ((e + 65 + 13) << 24); + word1(rvp) = b->x[0]; +#endif +#ifdef VAX + /* The next two lines ignore swap of low- and high-order 2 bytes. */ + /* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */ + /* word1(rvp) = b->x[0]; */ + word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16); + word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16); +#endif + Bfree(b); + } +#endif /*}!NO_HEX_FP*/ + + static int +#ifdef KR_headers +dshift(b, p2) Bigint *b; int p2; +#else +dshift(Bigint *b, int p2) +#endif +{ + int rv = hi0bits(b->x[b->wds-1]) - 4; + if (p2 > 0) + rv -= p2; + return rv & kmask; + } + + static int +quorem +#ifdef KR_headers + (b, S) Bigint *b, *S; +#else + (Bigint *b, Bigint *S) +#endif +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; +#ifdef Pack_32 + ULong si, z, zs; +#endif +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + if (!*bxe) { + bx = b->x; + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = y & FFFFFFFF; +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } + while(sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while(--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; + } + +#ifndef NO_STRTOD_BIGCOMP + + static void +bigcomp +#ifdef KR_headers + (rv, s0, bc) + U *rv; CONST char *s0; BCinfo *bc; +#else + (U *rv, CONST char *s0, BCinfo *bc) +#endif +{ + Bigint *b, *d; + int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase; + + dsign = bc->dsign; + nd = bc->nd; + nd0 = bc->nd0; + p5 = nd + bc->e0 - 1; + dd = speccase = 0; +#ifndef Sudden_Underflow + if (rv->d == 0.) { /* special case: value near underflow-to-zero */ + /* threshold was rounded to zero */ + b = i2b(1); + p2 = Emin - P + 1; + bbits = 1; +#ifdef Avoid_Underflow + word0(rv) = (P+2) << Exp_shift; +#else + word1(rv) = 1; +#endif + i = 0; +#ifdef Honor_FLT_ROUNDS + if (bc->rounding == 1) +#endif + { + speccase = 1; + --p2; + dsign = 0; + goto have_i; + } + } + else +#endif + b = d2b(rv, &p2, &bbits); +#ifdef Avoid_Underflow + p2 -= bc->scale; +#endif + /* floor(log2(rv)) == bbits - 1 + p2 */ + /* Check for denormal case. */ + i = P - bbits; + if (i > (j = P - Emin - 1 + p2)) { +#ifdef Sudden_Underflow + Bfree(b); + b = i2b(1); + p2 = Emin; + i = P - 1; +#ifdef Avoid_Underflow + word0(rv) = (1 + bc->scale) << Exp_shift; +#else + word0(rv) = Exp_msk1; +#endif + word1(rv) = 0; +#else + i = j; +#endif + } +#ifdef Honor_FLT_ROUNDS + if (bc->rounding != 1) { + if (i > 0) + b = lshift(b, i); + if (dsign) + b = increment(b); + } + else +#endif + { + b = lshift(b, ++i); + b->x[0] |= 1; + } +#ifndef Sudden_Underflow + have_i: +#endif + p2 -= p5 + i; + d = i2b(1); + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + */ + if (p5 > 0) + d = pow5mult(d, p5); + else if (p5 < 0) + b = pow5mult(b, -p5); + if (p2 > 0) { + b2 = p2; + d2 = 0; + } + else { + b2 = 0; + d2 = -p2; + } + i = dshift(d, d2); + if ((b2 += i) > 0) + b = lshift(b, b2); + if ((d2 += i) > 0) + d = lshift(d, d2); + + /* Now b/d = exactly half-way between the two floating-point values */ + /* on either side of the input string. Compute first digit of b/d. */ + + dig = quorem(b,d); + if (!dig) { + b = multadd(b, 10, 0); /* very unlikely */ + dig = quorem(b,d); + } + + /* Compare b/d with s0 */ + + for(i = 0; i < nd0; ) { + dd = s0[i++] - '0' - dig; + if (dd) + goto ret; + if (!b->x[0] && b->wds == 1) { + if (i < nd) + dd = 1; + goto ret; + } + b = multadd(b, 10, 0); + dig = quorem(b,d); + } + for(j = bc->dp1; i++ < nd;) { + dd = s0[j++] - '0' - dig; + if (dd) + goto ret; + if (!b->x[0] && b->wds == 1) { + if (i < nd) + dd = 1; + goto ret; + } + b = multadd(b, 10, 0); + dig = quorem(b,d); + } + if (b->x[0] || b->wds > 1) + dd = -1; + ret: + Bfree(b); + Bfree(d); +#ifdef Honor_FLT_ROUNDS + if (bc->rounding != 1) { + if (dd < 0) { + if (bc->rounding == 0) { + if (!dsign) + goto retlow1; + } + else if (dsign) + goto rethi1; + } + else if (dd > 0) { + if (bc->rounding == 0) { + if (dsign) + goto rethi1; + goto ret1; + } + if (!dsign) + goto rethi1; + dval(rv) += 2.*ulp(rv); + } + else { + bc->inexact = 0; + if (dsign) + goto rethi1; + } + } + else +#endif + if (speccase) { + if (dd <= 0) + rv->d = 0.; + } + else if (dd < 0) { + if (!dsign) /* does not happen for round-near */ +retlow1: + dval(rv) -= ulp(rv); + } + else if (dd > 0) { + if (dsign) { + rethi1: + dval(rv) += ulp(rv); + } + } + else { + /* Exact half-way case: apply round-even rule. */ + if (word1(rv) & 1) { + if (dsign) + goto rethi1; + goto retlow1; + } + } + +#ifdef Honor_FLT_ROUNDS + ret1: +#endif + return; + } +#endif /* NO_STRTOD_BIGCOMP */ + + double +strtod +#ifdef KR_headers + (s00, se) CONST char *s00; char **se; +#else + (CONST char *s00, char **se) +#endif +{ + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1; + int esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + CONST char *s, *s0, *s1; + double aadj, aadj1; + Long L; + U aadj2, adj, rv, rv0; + ULong y, z; + BCinfo bc; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; +#ifdef SET_INEXACT + int oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS /*{*/ +#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ + bc.rounding = Flt_Rounds; +#else /*}{*/ + bc.rounding = 1; + switch(fegetround()) { + case FE_TOWARDZERO: bc.rounding = 0; break; + case FE_UPWARD: bc.rounding = 2; break; + case FE_DOWNWARD: bc.rounding = 3; + } +#endif /*}}*/ +#endif /*}*/ +#ifdef USE_LOCALE + CONST char *s2; +#endif + + sign = nz0 = nz = bc.dplen = bc.uflchk = 0; + dval(&rv) = 0.; + for(s = s00;;s++) switch(*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } + break2: + if (*s == '0') { +#ifndef NO_HEX_FP /*{*/ + switch(s[1]) { + case 'x': + case 'X': +#ifdef Honor_FLT_ROUNDS + gethex(&s, &rv, bc.rounding, sign); +#else + gethex(&s, &rv, 1, sign); +#endif + goto ret; + } +#endif /*}*/ + nz0 = 1; + while(*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < 16) + z = 10*z + c - '0'; + nd0 = nd; + bc.dp0 = bc.dp1 = s - s0; +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for(;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { + c = *++s; + bc.dp1 = s - s0; + bc.dplen = bc.dp1 - bc.dp0; + if (!nd) { + for(; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for(; c >= '0' && c <= '9'; c = *++s) { + have_dig: + nz++; + if (c -= '0') { + nf += nz; + for(i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 1) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 1) + z = 10*z + c; + nz = 0; + } + } + } + dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + goto ret0; + } + s00 = s; + esign = 0; + switch(c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while(c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = (int)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) { +#ifdef INFNAN_CHECK + /* Check for Nan and Infinity */ + if (!bc.dplen) + switch(c) { + case 'i': + case 'I': + if (match(&s,"nf")) { + --s; + if (!match(&s,"inity")) + ++s; + word0(&rv) = 0x7ff00000; + word1(&rv) = 0; + goto ret; + } + break; + case 'n': + case 'N': + if (match(&s, "an")) { + word0(&rv) = NAN_WORD0; + word1(&rv) = NAN_WORD1; +#ifndef No_Hex_NaN + if (*s == '(') /*)*/ + hexnan(&rv, &s); +#endif + goto ret; + } + } +#endif /* INFNAN_CHECK */ + ret0: + s = s00; + sign = 0; + } + goto ret; + } + bc.e0 = e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + dval(&rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(&rv) = tens[k - 9] * dval(&rv) + z; + } + bd0 = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif +#endif + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv.d = -rv.d; + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(&rv), tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv.d = -rv.d; + sign = 0; + } +#endif + e -= i; + dval(&rv) *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ + vax_ovfl_check: + word0(&rv) -= P*Exp_msk1; + /* rv = */ rounded_product(dval(&rv), tens[e]); + if ((word0(&rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(&rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(dval(&rv), tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + rv.d = -rv.d; + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(&rv), tens[-e]); + goto ret; + } +#endif + } + e1 += nd - k; + +#ifdef IEEE_Arith +#ifdef SET_INEXACT + bc.inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + bc.scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if (bc.rounding >= 2) { + if (sign) + bc.rounding = bc.rounding == 2 ? 0 : 2; + else + if (bc.rounding != 2) + bc.rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + i = e1 & 15; + if (i) + dval(&rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { + ovfl: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch(bc.rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(&rv) = Big0; + word1(&rv) = Big1; + break; + default: + word0(&rv) = Exp_mask; + word1(&rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ + word0(&rv) = Exp_mask; + word1(&rv) = 0; +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(&rv0) = 1e300; + dval(&rv0) *= dval(&rv0); +#endif +#else /*IEEE_Arith*/ + word0(&rv) = Big0; + word1(&rv) = Big1; +#endif /*IEEE_Arith*/ + goto ret; + } + e1 >>= 4; + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(&rv) -= P*Exp_msk1; + dval(&rv) *= bigtens[j]; + if ((z = word0(&rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(&rv) = Big0; + word1(&rv) = Big1; + } + else + word0(&rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + i = e1 & 15; + if (i) + dval(&rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + bc.scale = 2*P; + for(j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= tinytens[j]; + if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; clear j low bits */ + if (j >= 32) { + word1(&rv) = 0; + if (j >= 53) + word0(&rv) = (P+2)*Exp_msk1; + else + word0(&rv) &= 0xffffffff << (j-32); + } + else + word1(&rv) &= 0xffffffff << j; + } +#else + for(j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(&rv) *= tinytens[j]; + /* The last multiplication could underflow. */ + dval(&rv0) = dval(&rv); + dval(&rv) *= tinytens[j]; + if (!dval(&rv)) { + dval(&rv) = 2.*dval(&rv0); + dval(&rv) *= tinytens[j]; +#endif + if (!dval(&rv)) { + undfl: + dval(&rv) = 0.; +#ifndef NO_ERRNO + errno = ERANGE; +#endif + goto ret; + } +#ifndef Avoid_Underflow + word0(&rv) = Tiny0; + word1(&rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } +#endif + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bc.nd = nd; +#ifndef NO_STRTOD_BIGCOMP + bc.nd0 = nd0; /* Only needed if nd > strtod_diglim, but done here */ + /* to silence an erroneous warning about bc.nd0 */ + /* possibly not being initialized. */ + if (nd > strtod_diglim) { + /* ASSERT(strtod_diglim >= 18); 18 == one more than the */ + /* minimum number of decimal digits to distinguish double values */ + /* in IEEE arithmetic. */ + i = j = 18; + if (i > nd0) + j += bc.dplen; + for(;;) { + if (--j <= bc.dp1 && j >= bc.dp0) + j = bc.dp0 - 1; + if (s0[j] != '0') + break; + --i; + } + e += nd - i; + nd = i; + if (nd0 > nd) + nd0 = nd; + if (nd < 9) { /* must recompute y */ + y = 0; + for(i = 0; i < nd0; ++i) + y = 10*y + s0[i] - '0'; + for(j = bc.dp1; i < nd; ++i) + y = 10*y + s0[j++] - '0'; + } + } +#endif + bd0 = s2b(s0, nd0, nd, y, bc.dplen); + + for(;;) { + bd = Balloc(bd0->k); + Bcopy(bd, bd0); + bb = d2b(&rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ + bs = i2b(1); + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (bc.rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + j = bbe - bc.scale; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#else /*Avoid_Underflow*/ +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + bb2 += j; + bd2 += j; +#ifdef Avoid_Underflow + bd2 += bc.scale; +#endif + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + } + if (bb2 > 0) + bb = lshift(bb, bb2); + if (bd5 > 0) + bd = pow5mult(bd, bd5); + if (bd2 > 0) + bd = lshift(bd, bd2); + if (bs2 > 0) + bs = lshift(bs, bs2); + delta = diff(bb, bd); + bc.dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); +#ifndef NO_STRTOD_BIGCOMP + if (bc.nd > nd && i <= 0) { + if (bc.dsign) + break; /* Must use bigcomp(). */ +#ifdef Honor_FLT_ROUNDS + if (bc.rounding != 1) { + if (i < 0) + break; + } + else +#endif + { + bc.nd = nd; + i = -1; /* Discarded digits make delta smaller. */ + } + } +#endif +#ifdef Honor_FLT_ROUNDS + if (bc.rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + bc.inexact = 0; +#endif + break; + } + if (bc.rounding) { + if (bc.dsign) { + adj.d = 1.; + goto apply_adj; + } + } + else if (!bc.dsign) { + adj.d = -1.; + if (!word1(&rv) + && !(word0(&rv) & Frac_mask)) { + y = word0(&rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!bc.scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(delta,Log2P); + if (cmp(delta, bs) <= 0) + adj.d = -0.5; + } + } + apply_adj: +#ifdef Avoid_Underflow + if (bc.scale && (y = word0(&rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(&adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(&rv) & Exp_mask) <= + P*Exp_msk1) { + word0(&rv) += P*Exp_msk1; + dval(&rv) += adj.d*ulp(dval(&rv)); + word0(&rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + dval(&rv) += adj.d*ulp(&rv); + } + break; + } + adj.d = ratio(delta, bs); + if (adj.d < 1.) + adj.d = 1.; + if (adj.d <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj.d; + if (y != adj.d) { + if (!((bc.rounding>>1) ^ bc.dsign)) + y++; + adj.d = y; + } + } +#ifdef Avoid_Underflow + if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(&adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { + word0(&rv) += P*Exp_msk1; + adj.d *= ulp(dval(&rv)); + if (bc.dsign) + dval(&rv) += adj.d; + else + dval(&rv) -= adj.d; + word0(&rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + adj.d *= ulp(&rv); + if (bc.dsign) { + if (word0(&rv) == Big0 && word1(&rv) == Big1) + goto ovfl; + dval(&rv) += adj.d; + } + else + dval(&rv) -= adj.d; + goto cont; + } +#endif /*Honor_FLT_ROUNDS*/ + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask +#ifdef IEEE_Arith +#ifdef Avoid_Underflow + || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(&rv) & Exp_mask) <= Exp_msk1 +#endif +#endif + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + bc.inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + bc.inexact = 0; +#endif + break; + } + delta = lshift(delta,Log2P); + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (bc.dsign) { + if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 + && word1(&rv) == ( +#ifdef Avoid_Underflow + (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { + /*boundary case -- increment exponent*/ + word0(&rv) = (word0(&rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(&rv) = 0; +#ifdef Avoid_Underflow + bc.dsign = 0; +#endif + break; + } + } + else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { + drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow /*{{*/ + L = word0(&rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) +#else + if (L <= Exp_msk1) +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ + { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } + L -= Exp_msk1; +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (bc.scale) { + L = word0(&rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } + } +#endif /*Avoid_Underflow*/ + L = (word0(&rv) & Exp_mask) - Exp_msk1; +#endif /*Sudden_Underflow}}*/ + word0(&rv) = L | Bndry_mask1; + word1(&rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else + break; +#endif + } +#ifndef ROUND_BIASED + if (!(word1(&rv) & LSB)) + break; +#endif + if (bc.dsign) + dval(&rv) += ulp(&rv); +#ifndef ROUND_BIASED + else { + dval(&rv) -= ulp(&rv); +#ifndef Sudden_Underflow + if (!dval(&rv)) { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } +#endif + } +#ifdef Avoid_Underflow + bc.dsign = 1 - bc.dsign; +#endif +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (bc.dsign) + aadj = aadj1 = 1.; + else if (word1(&rv) || word0(&rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(&rv) == Tiny1 && !word0(&rv)) { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } +#endif + aadj = 1.; + aadj1 = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + aadj1 = -aadj; + } + } + else { + aadj *= 0.5; + aadj1 = bc.dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch(bc.rounding) { + case 2: /* towards +infinity */ + aadj1 -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + aadj1 += 0.5; + } +#else + if (Flt_Rounds == 0) + aadj1 += 0.5; +#endif /*Check_FLT_ROUNDS*/ + } + y = word0(&rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(&rv0) = dval(&rv); + word0(&rv) -= P*Exp_msk1; + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + if ((word0(&rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(&rv0) == Big0 && word1(&rv0) == Big1) + goto ovfl; + word0(&rv) = Big0; + word1(&rv) = Big1; + goto cont; + } + else + word0(&rv) += P*Exp_msk1; + } + else { +#ifdef Avoid_Underflow + if (bc.scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = (ULong)aadj) <= 0) + z = 1; + aadj = z; + aadj1 = bc.dsign ? aadj : -aadj; + } + dval(&aadj2) = aadj1; + word0(&aadj2) += (2*P+1)*Exp_msk1 - y; + aadj1 = dval(&aadj2); + } + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; +#else +#ifdef Sudden_Underflow + if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { + dval(&rv0) = dval(&rv); + word0(&rv) += P*Exp_msk1; + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; +#ifdef IBM + if ((word0(&rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(&rv0) == Tiny0 + && word1(&rv0) == Tiny1) { + if (bc.nd >nd) { + bc.uflchk = 1; + break; + } + goto undfl; + } + word0(&rv) = Tiny0; + word1(&rv) = Tiny1; + goto cont; + } + else + word0(&rv) -= P*Exp_msk1; + } + else { + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; + } +#else /*Sudden_Underflow*/ + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { + aadj1 = (double)(int)(aadj + 0.5); + if (!bc.dsign) + aadj1 = -aadj1; + } + adj.d = aadj1 * ulp(&rv); + dval(&rv) += adj.d; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + } + z = word0(&rv) & Exp_mask; +#ifndef SET_INEXACT + if (bc.nd == nd) { +#ifdef Avoid_Underflow + if (!bc.scale) +#endif + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } + } +#endif + cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); +#ifndef NO_STRTOD_BIGCOMP + if (bc.nd > nd) + bigcomp(&rv, s0, &bc); +#endif +#ifdef SET_INEXACT + if (bc.inexact) { + if (!oldinexact) { + word0(&rv0) = Exp_1 + (70 << Exp_shift); + word1(&rv0) = 0; + dval(&rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (bc.scale) { + word0(&rv0) = Exp_1 - 2*P*Exp_msk1; + word1(&rv0) = 0; + dval(&rv) *= dval(&rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ +#ifdef IEEE_Arith + if (!(word0(&rv) & Exp_mask)) +#else + if (word0(&rv) == 0 && word1(&rv) == 0) +#endif + errno = ERANGE; +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (bc.inexact && !(word0(&rv) & Exp_mask)) { + /* set underflow bit */ + dval(&rv0) = 1e-300; + dval(&rv0) *= dval(&rv0); + } +#endif + ret: + if (se) + *se = (char *)s; + return sign ? -dval(&rv) : dval(&rv); + } + +#ifndef MULTIPLE_THREADS + static char *dtoa_result; +#endif + + static char * +#ifdef KR_headers +rv_alloc(i) int i; +#else +rv_alloc(int i) +#endif +{ + int j, k, *r; + + j = sizeof(ULong); + for(k = 0; + sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)i; + j <<= 1) + k++; + r = (int*)Balloc(k); + *r = k; + return +#ifndef MULTIPLE_THREADS + dtoa_result = +#endif + (char *)(r+1); + } + + static char * +#ifdef KR_headers +nrv_alloc(s, rve, n) char *s, **rve; int n; +#else +nrv_alloc(CONST char *s, char **rve, int n) +#endif +{ + char *rv, *t; + + t = rv = rv_alloc(n); + for(*t = *s++; *t; *t = *s++) t++; + if (rve) + *rve = t; + return rv; + } + +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + + void +#ifdef KR_headers +freedtoa(s) char *s; +#else +freedtoa(char *s) +#endif +{ + Bigint *b = (Bigint *)((int *)s - 1); + b->maxwds = 1 << (b->k = *(int*)b); + Bfree(b); +#ifndef MULTIPLE_THREADS + if (s == dtoa_result) + dtoa_result = 0; +#endif + } + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + + char * +dtoa +#ifdef KR_headers + (dd, mode, ndigits, decpt, sign, rve) + double dd; int mode, ndigits, *decpt, *sign; char **rve; +#else + (double dd, int mode, int ndigits, int *decpt, int *sign, char **rve) +#endif +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick; + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S; + U d2, eps, u; + double ds; + char *s, *s0; +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS /*{*/ + int Rounding; +#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ + Rounding = Flt_Rounds; +#else /*}{*/ + Rounding = 1; + switch(fegetround()) { + case FE_TOWARDZERO: Rounding = 0; break; + case FE_UPWARD: Rounding = 2; break; + case FE_DOWNWARD: Rounding = 3; + } +#endif /*}}*/ +#endif /*}*/ + +#ifndef MULTIPLE_THREADS + if (dtoa_result) { + freedtoa(dtoa_result); + dtoa_result = 0; + } +#endif + + u.d = dd; + if (word0(&u) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(&u) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(&u) & Exp_mask) == Exp_mask) +#else + if (word0(&u) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(&u) && !(word0(&u) & 0xfffff)) + return nrv_alloc("Infinity", rve, 8); +#endif + return nrv_alloc("NaN", rve, 3); + } +#endif +#ifdef IBM + dval(&u) += 0; /* normalize */ +#endif + if (!dval(&u)) { + *decpt = 1; + return nrv_alloc("0", rve, 1); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if (Rounding >= 2) { + if (*sign) + Rounding = Rounding == 2 ? 0 : 2; + else + if (Rounding != 2) + Rounding = 0; + } +#endif + + b = d2b(&u, &be, &bbits); + i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#ifndef Sudden_Underflow + if (i) { +#endif + dval(&d2) = dval(&u); + word0(&d2) &= Frac_mask1; + word0(&d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(&d2) & Frac_mask)) + dval(&d2) /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) + : word1(&u) << (32 - i); + dval(&d2) = x; + word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(&u) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else + try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ + /* silence erroneous "gcc -Wall" warning. */ + switch(mode) { + case 0: + case 1: + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s = s0 = rv_alloc(i); + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && Rounding != 1) + leftright = 0; +#endif + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(&d2) = dval(&u); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(&u) /= bigtens[n_bigtens-1]; + ieps++; + } + for(; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(&u) /= ds; + } + else { + j1 = -k; + if (j1) { + dval(&u) *= tens[j1 & 0xf]; + for(j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(&u) *= bigtens[i]; + } + } + } + if (k_check && dval(&u) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(&u) *= 10.; + ieps++; + } + dval(&eps) = ieps*dval(&u) + 7.; + word0(&eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(&u) -= 5.; + if (dval(&u) > dval(&eps)) + goto one_digit; + if (dval(&u) < -dval(&eps)) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); + for(i = 0;;) { + L = (long)dval(&u); + dval(&u) -= L; + *s++ = '0' + (char)L; + if (dval(&u) < dval(&eps)) + goto ret1; + if (1. - dval(&u) < dval(&eps)) + goto bump_up; + if (++i >= ilim) + break; + dval(&eps) *= 10.; + dval(&u) *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + dval(&eps) *= tens[ilim-1]; + for(i = 1;; i++, dval(&u) *= 10.) { + L = (Long)(dval(&u)); + if (!(dval(&u) -= L)) + ilim = i; + *s++ = '0' + (char)L; + if (i == ilim) { + if (dval(&u) > 0.5 + dval(&eps)) + goto bump_up; + else if (dval(&u) < 0.5 - dval(&eps)) { + while(*--s == '0') {} + s++; + goto ret1; + } + break; + } + } +#ifndef No_leftright + } +#endif + fast_failed: + s = s0; + dval(&u) = dval(&d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(&u) <= 5*ds) + goto no_digits; + goto one_digit; + } + for(i = 1; i <= k + 1; i++, dval(&u) *= 10.) { + L = (Long)(dval(&u) / ds); + dval(&u) -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (dval(&u) < 0) { + L--; + dval(&u) += ds; + } +#endif + *s++ = '0' + (char)L; + if (!dval(&u)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (i == ilim) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(Rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(&u) += dval(&u); + if (dval(&u) > ds || (dval(&u) == ds && L & 1)) { + bump_up: + while(*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + mhi = mlo = 0; + if (leftright) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + b2 += i; + s2 += i; + mhi = i2b(1); + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + b1 = mult(mhi, b); + Bfree(b); + b = b1; + } + j = b5 - m5; + if (j) + b = pow5mult(b, j); + } + else + b = pow5mult(b, b5); + } + S = i2b(1); + if (s5 > 0) + S = pow5mult(S, s5); + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && Rounding == 1 +#endif + ) { + if (!word1(&u) && !(word0(&u) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(&u) & (Exp_mask & ~Exp_msk1) +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#ifdef Pack_32 + i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f; + if (i) + i = 32 - i; +#define iInc 28 +#else + if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) + i = 16 - i; +#define iInc 12 +#endif + i = dshift(S, s2); + b2 += i; + m2 += i; + s2 += i; + if (b2 > 0) + b = lshift(b, b2); + if (s2 > 0) + S = lshift(S, s2); + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (leftright) + mhi = multadd(mhi, 10, 0); + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ + no_digits: + k = -1 - ndigits; + goto ret; + } + one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) + mhi = lshift(mhi, m2); + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + } + + for(i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && mode != 1 && !(word1(&u) & 1) +#ifdef Honor_FLT_ROUNDS + && Rounding >= 1 +#endif + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif + *s++ = (char)dig; + goto ret; + } +#endif + if (j < 0 || (j == 0 && mode != 1 +#ifndef ROUND_BIASED + && !(word1(&u) & 1) +#endif + )) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch(Rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ + if (j1 > 0) { + b = lshift(b, 1); + j1 = cmp(b, S); + if ((j1 > 0 || (j1 == 0 && dig & 1)) + && dig++ == '9') + goto round_9_up; + } + accept_dig: + *s++ = (char)dig; + goto ret; + } + if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!Rounding) + goto accept_dig; +#endif + if (dig == '9') { /* possible if i == 1 */ + round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = (char)dig + 1; + goto ret; + } +#ifdef Honor_FLT_ROUNDS + keep_dig: +#endif + *s++ = (char)dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (mlo == mhi) + mlo = mhi = multadd(mhi, 10, 0); + else { + mlo = multadd(mlo, 10, 0); + mhi = multadd(mhi, 10, 0); + } + } + } + else + for(i = 1;; i++) { + dig = quorem(b,S) + '0'; + *s++ = (char)dig; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } + if (i >= ilim) + break; + b = multadd(b, 10, 0); + } + + /* Round off last digit */ + +#ifdef Honor_FLT_ROUNDS + switch(Rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif + b = lshift(b, 1); + j = cmp(b, S); + if (j > 0 || (j == 0 && dig & 1)) { + roundoff: + while(*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + ++*s++; + } + else { +#ifdef Honor_FLT_ROUNDS + trimzeros: +#endif + while(*--s == '0') {} + s++; + } + ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(&u) = Exp_1 + (70 << Exp_shift); + word1(&u) = 0; + dval(&u) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + } + +} // namespace dmg_fp diff --git a/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc b/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc new file mode 100644 index 0000000..bfa358d --- /dev/null +++ b/third_party/chromium/base/third_party/dmg_fp/g_fmt.cc @@ -0,0 +1,102 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 1996 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* g_fmt(buf,x) stores the closest decimal approximation to x in buf; + * it suffices to declare buf + * char buf[32]; + */ + +#include "dmg_fp.h" + +namespace dmg_fp { + + char * +g_fmt(register char *b, double x) +{ + register int i, k; + register char *s; + int decpt, j, sign; + char *b0, *s0, *se; + + b0 = b; +#ifdef IGNORE_ZERO_SIGN + if (!x) { + *b++ = '0'; + *b = 0; + goto done; + } +#endif + s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se); + if (sign) + *b++ = '-'; + if (decpt == 9999) /* Infinity or Nan */ { + for(*b = *s++; *b++; *b = *s++) {} + goto done0; + } + if (decpt <= -4 || decpt > se - s + 5) { + *b++ = *s++; + if (*s) { + *b++ = '.'; + for(*b = *s++; *b; *b = *s++) + b++; + } + *b++ = 'e'; + /* sprintf(b, "%+.2d", decpt - 1); */ + if (--decpt < 0) { + *b++ = '-'; + decpt = -decpt; + } + else + *b++ = '+'; + for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10) {} + for(;;) { + i = decpt / k; + *b++ = (char)i + '0'; + if (--j <= 0) + break; + decpt -= i*k; + decpt *= 10; + } + *b = 0; + } + else if (decpt <= 0) { + *b++ = '.'; + for(; decpt < 0; decpt++) + *b++ = '0'; + for(*b = *s++; *b++; *b = *s++) {} + } + else { + for(*b = *s++; *b; *b = *s++) { + b++; + if (--decpt == 0 && *s) + *b++ = '.'; + } + for(; decpt > 0; decpt--) + *b++ = '0'; + *b = 0; + } + done0: + freedtoa(s0); +#ifdef IGNORE_ZERO_SIGN + done: +#endif + return b0; + } + +} // namespace dmg_fp diff --git a/third_party/chromium/base/third_party/icu/LICENSE b/third_party/chromium/base/third_party/icu/LICENSE new file mode 100644 index 0000000..40282f4 --- /dev/null +++ b/third_party/chromium/base/third_party/icu/LICENSE @@ -0,0 +1,32 @@ +ICU License - ICU 1.8.1 and later + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1995-2009 International Business Machines Corporation and others + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY +SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. diff --git a/third_party/chromium/base/third_party/icu/README.chromium b/third_party/chromium/base/third_party/icu/README.chromium new file mode 100644 index 0000000..6a9a15a --- /dev/null +++ b/third_party/chromium/base/third_party/icu/README.chromium @@ -0,0 +1,16 @@ +Name: ICU +URL: http://site.icu-project.org/ +License: MIT +License File: NOT_SHIPPED + +This file has the relevant components from ICU copied to handle basic +UTF8/16/32 conversions. Components are copied from utf.h utf8.h utf16.h and +utf_impl.c + +The same module appears in third_party/icu, so we don't repeat the license +file here. + +The main change is that U_/U8_/U16_ prefixes have been replaced with +CBU_/CBU8_/CBU16_ (for "Chrome Base") to avoid confusion with the "real" ICU +macros should ICU be in use on the system. For the same reason, the functions +and types have been put in the "base_icu" namespace. diff --git a/third_party/chromium/base/third_party/icu/icu_utf.cc b/third_party/chromium/base/third_party/icu/icu_utf.cc new file mode 100644 index 0000000..b47c8ac --- /dev/null +++ b/third_party/chromium/base/third_party/icu/icu_utf.cc @@ -0,0 +1,228 @@ +/* +****************************************************************************** +* +* Copyright (C) 1999-2006, International Business Machines +* Corporation and others. All Rights Reserved. +* +****************************************************************************** +* file name: utf_impl.c +* encoding: US-ASCII +* tab size: 8 (not used) +* indentation:4 +* +* created on: 1999sep13 +* created by: Markus W. Scherer +* +* This file provides implementation functions for macros in the utfXX.h +* that would otherwise be too long as macros. +*/ + +#include "base/third_party/icu/icu_utf.h" + +namespace base_icu { + +/** + * UTF8_ERROR_VALUE_1 and UTF8_ERROR_VALUE_2 are special error values for UTF-8, + * which need 1 or 2 bytes in UTF-8: + * \code + * U+0015 = NAK = Negative Acknowledge, C0 control character + * U+009f = highest C1 control character + * \endcode + * + * These are used by UTF8_..._SAFE macros so that they can return an error value + * that needs the same number of code units (bytes) as were seen by + * a macro. They should be tested with UTF_IS_ERROR() or UTF_IS_VALID(). + * + * @deprecated ICU 2.4. Obsolete, see utf_old.h. + */ +#define CBUTF8_ERROR_VALUE_1 0x15 + +/** + * See documentation on UTF8_ERROR_VALUE_1 for details. + * + * @deprecated ICU 2.4. Obsolete, see utf_old.h. + */ +#define CBUTF8_ERROR_VALUE_2 0x9f + + +/** + * Error value for all UTFs. This code point value will be set by macros with e> + * checking if an error is detected. + * + * @deprecated ICU 2.4. Obsolete, see utf_old.h. + */ +#define CBUTF_ERROR_VALUE 0xffff + +/* + * This table could be replaced on many machines by + * a few lines of assembler code using an + * "index of first 0-bit from msb" instruction and + * one or two more integer instructions. + * + * For example, on an i386, do something like + * - MOV AL, leadByte + * - NOT AL (8-bit, leave b15..b8==0..0, reverse only b7..b0) + * - MOV AH, 0 + * - BSR BX, AX (16-bit) + * - MOV AX, 6 (result) + * - JZ finish (ZF==1 if leadByte==0xff) + * - SUB AX, BX (result) + * -finish: + * (BSR: Bit Scan Reverse, scans for a 1-bit, starting from the MSB) + * + * In Unicode, all UTF-8 byte sequences with more than 4 bytes are illegal; + * lead bytes above 0xf4 are illegal. + * We keep them in this table for skipping long ISO 10646-UTF-8 sequences. + */ +const uint8 +utf8_countTrailBytes[256]={ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, + 3, 3, 3, /* illegal in Unicode */ + 4, 4, 4, 4, /* illegal in Unicode */ + 5, 5, /* illegal in Unicode */ + 0, 0 /* illegal bytes 0xfe and 0xff */ +}; + +static const UChar32 +utf8_minLegal[4]={ 0, 0x80, 0x800, 0x10000 }; + +static const UChar32 +utf8_errorValue[6]={ + CBUTF8_ERROR_VALUE_1, CBUTF8_ERROR_VALUE_2, CBUTF_ERROR_VALUE, 0x10ffff, + 0x3ffffff, 0x7fffffff +}; + +/* + * Handle the non-inline part of the U8_NEXT() macro and its obsolete sibling + * UTF8_NEXT_CHAR_SAFE(). + * + * The "strict" parameter controls the error behavior: + * <0 "Safe" behavior of U8_NEXT(): All illegal byte sequences yield a negative + * code point result. + * 0 Obsolete "safe" behavior of UTF8_NEXT_CHAR_SAFE(..., FALSE): + * All illegal byte sequences yield a positive code point such that this + * result code point would be encoded with the same number of bytes as + * the illegal sequence. + * >0 Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., TRUE): + * Same as the obsolete "safe" behavior, but non-characters are also treated + * like illegal sequences. + * + * The special negative (<0) value -2 is used for lenient treatment of surrogate + * code points as legal. Some implementations use this for roundtripping of + * Unicode 16-bit strings that are not well-formed UTF-16, that is, they + * contain unpaired surrogates. + * + * Note that a UBool is the same as an int8_t. + */ +UChar32 +utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict) { + int32 i=*pi; + uint8 count=CBU8_COUNT_TRAIL_BYTES(c); + if((i)+count<=(length)) { + uint8 trail, illegal=0; + + CBU8_MASK_LEAD_BYTE((c), count); + /* count==0 for illegally leading trail bytes and the illegal bytes 0xfe and 0xff */ + switch(count) { + /* each branch falls through to the next one */ + case 5: + case 4: + /* count>=4 is always illegal: no more than 3 trail bytes in Unicode's UTF-8 */ + illegal=1; + break; + case 3: + trail=s[(i)++]; + (c)=((c)<<6)|(trail&0x3f); + if(c<0x110) { + illegal|=(trail&0xc0)^0x80; + } else { + /* code point>0x10ffff, outside Unicode */ + illegal=1; + break; + } + case 2: + trail=s[(i)++]; + (c)=((c)<<6)|(trail&0x3f); + illegal|=(trail&0xc0)^0x80; + case 1: + trail=s[(i)++]; + (c)=((c)<<6)|(trail&0x3f); + illegal|=(trail&0xc0)^0x80; + break; + case 0: + if(strict>=0) { + return CBUTF8_ERROR_VALUE_1; + } else { + return CBU_SENTINEL; + } + /* no default branch to optimize switch() - all values are covered */ + } + + /* + * All the error handling should return a value + * that needs count bytes so that UTF8_GET_CHAR_SAFE() works right. + * + * Starting with Unicode 3.0.1, non-shortest forms are illegal. + * Starting with Unicode 3.2, surrogate code points must not be + * encoded in UTF-8, and there are no irregular sequences any more. + * + * U8_ macros (new in ICU 2.4) return negative values for error conditions. + */ + + /* correct sequence - all trail bytes have (b7..b6)==(10)? */ + /* illegal is also set if count>=4 */ + if(illegal || (c)<utf8_minLegal[count] || (CBU_IS_SURROGATE(c) && strict!=-2)) { + /* error handling */ + uint8 errorCount=count; + /* don't go beyond this sequence */ + i=*pi; + while(count>0 && CBU8_IS_TRAIL(s[i])) { + ++(i); + --count; + } + if(strict>=0) { + c=utf8_errorValue[errorCount-count]; + } else { + c=CBU_SENTINEL; + } + } else if((strict)>0 && CBU_IS_UNICODE_NONCHAR(c)) { + /* strict: forbid non-characters like U+fffe */ + c=utf8_errorValue[count]; + } + } else /* too few bytes left */ { + /* error handling */ + int32 i0=i; + /* don't just set (i)=(length) in case there is an illegal sequence */ + while((i)<(length) && CBU8_IS_TRAIL(s[i])) { + ++(i); + } + if(strict>=0) { + c=utf8_errorValue[i-i0]; + } else { + c=CBU_SENTINEL; + } + } + *pi=i; + return c; +} + +} // namespace base_icu diff --git a/third_party/chromium/base/third_party/icu/icu_utf.h b/third_party/chromium/base/third_party/icu/icu_utf.h new file mode 100644 index 0000000..2b993b0 --- /dev/null +++ b/third_party/chromium/base/third_party/icu/icu_utf.h @@ -0,0 +1,391 @@ +/* +******************************************************************************* +* +* Copyright (C) 1999-2004, International Business Machines +* Corporation and others. All Rights Reserved. +* +******************************************************************************* +* file name: utf.h +* encoding: US-ASCII +* tab size: 8 (not used) +* indentation:4 +* +* created on: 1999sep09 +* created by: Markus W. Scherer +*/ + +#ifndef BASE_THIRD_PARTY_ICU_ICU_UTF_H_ +#define BASE_THIRD_PARTY_ICU_ICU_UTF_H_ + +#include "base/basictypes.h" + +namespace base_icu { + +typedef int32 UChar32; +typedef uint16 UChar; +typedef int8 UBool; + +// General --------------------------------------------------------------------- +// from utf.h + +/** + * This value is intended for sentinel values for APIs that + * (take or) return single code points (UChar32). + * It is outside of the Unicode code point range 0..0x10ffff. + * + * For example, a "done" or "error" value in a new API + * could be indicated with CBU_SENTINEL. + * + * ICU APIs designed before ICU 2.4 usually define service-specific "done" + * values, mostly 0xffff. + * Those may need to be distinguished from + * actual U+ffff text contents by calling functions like + * CharacterIterator::hasNext() or UnicodeString::length(). + * + * @return -1 + * @see UChar32 + * @stable ICU 2.4 + */ +#define CBU_SENTINEL (-1) + +/** + * Is this code point a Unicode noncharacter? + * @param c 32-bit code point + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU_IS_UNICODE_NONCHAR(c) \ + ((c)>=0xfdd0 && \ + ((uint32)(c)<=0xfdef || ((c)&0xfffe)==0xfffe) && \ + (uint32)(c)<=0x10ffff) + +/** + * Is c a Unicode code point value (0..U+10ffff) + * that can be assigned a character? + * + * Code points that are not characters include: + * - single surrogate code points (U+d800..U+dfff, 2048 code points) + * - the last two code points on each plane (U+__fffe and U+__ffff, 34 code points) + * - U+fdd0..U+fdef (new with Unicode 3.1, 32 code points) + * - the highest Unicode code point value is U+10ffff + * + * This means that all code points below U+d800 are character code points, + * and that boundary is tested first for performance. + * + * @param c 32-bit code point + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU_IS_UNICODE_CHAR(c) \ + ((uint32)(c)<0xd800 || \ + ((uint32)(c)>0xdfff && \ + (uint32)(c)<=0x10ffff && \ + !CBU_IS_UNICODE_NONCHAR(c))) + +/** + * Is this code point a surrogate (U+d800..U+dfff)? + * @param c 32-bit code point + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800) + +/** + * Assuming c is a surrogate code point (U_IS_SURROGATE(c)), + * is it a lead surrogate? + * @param c 32-bit code point + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU_IS_SURROGATE_LEAD(c) (((c)&0x400)==0) + + +// UTF-8 macros ---------------------------------------------------------------- +// from utf8.h + +extern const uint8 utf8_countTrailBytes[256]; + +/** + * Count the trail bytes for a UTF-8 lead byte. + * @internal + */ +#define CBU8_COUNT_TRAIL_BYTES(leadByte) (base_icu::utf8_countTrailBytes[(uint8)leadByte]) + +/** + * Mask a UTF-8 lead byte, leave only the lower bits that form part of the code point value. + * @internal + */ +#define CBU8_MASK_LEAD_BYTE(leadByte, countTrailBytes) ((leadByte)&=(1<<(6-(countTrailBytes)))-1) + +/** + * Does this code unit (byte) encode a code point by itself (US-ASCII 0..0x7f)? + * @param c 8-bit code unit (byte) + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU8_IS_SINGLE(c) (((c)&0x80)==0) + +/** + * Is this code unit (byte) a UTF-8 lead byte? + * @param c 8-bit code unit (byte) + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU8_IS_LEAD(c) ((uint8)((c)-0xc0)<0x3e) + +/** + * Is this code unit (byte) a UTF-8 trail byte? + * @param c 8-bit code unit (byte) + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU8_IS_TRAIL(c) (((c)&0xc0)==0x80) + +/** + * How many code units (bytes) are used for the UTF-8 encoding + * of this Unicode code point? + * @param c 32-bit code point + * @return 1..4, or 0 if c is a surrogate or not a Unicode code point + * @stable ICU 2.4 + */ +#define CBU8_LENGTH(c) \ + ((uint32)(c)<=0x7f ? 1 : \ + ((uint32)(c)<=0x7ff ? 2 : \ + ((uint32)(c)<=0xd7ff ? 3 : \ + ((uint32)(c)<=0xdfff || (uint32)(c)>0x10ffff ? 0 : \ + ((uint32)(c)<=0xffff ? 3 : 4)\ + ) \ + ) \ + ) \ + ) + +/** + * The maximum number of UTF-8 code units (bytes) per Unicode code point (U+0000..U+10ffff). + * @return 4 + * @stable ICU 2.4 + */ +#define CBU8_MAX_LENGTH 4 + +/** + * Function for handling "next code point" with error-checking. + * @internal + */ +UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict); + +/** + * Get a code point from a string at a code point boundary offset, + * and advance the offset to the next code point boundary. + * (Post-incrementing forward iteration.) + * "Safe" macro, checks for illegal sequences and for string boundaries. + * + * The offset may point to the lead byte of a multi-byte sequence, + * in which case the macro will read the whole sequence. + * If the offset points to a trail byte or an illegal UTF-8 sequence, then + * c is set to a negative value. + * + * @param s const uint8 * string + * @param i string offset, i<length + * @param length string length + * @param c output UChar32 variable, set to <0 in case of an error + * @see CBU8_NEXT_UNSAFE + * @stable ICU 2.4 + */ +#define CBU8_NEXT(s, i, length, c) { \ + (c)=(s)[(i)++]; \ + if(((uint8)(c))>=0x80) { \ + if(CBU8_IS_LEAD(c)) { \ + (c)=base_icu::utf8_nextCharSafeBody((const uint8 *)s, &(i), (int32)(length), c, -1); \ + } else { \ + (c)=CBU_SENTINEL; \ + } \ + } \ +} + +/** + * Append a code point to a string, overwriting 1 to 4 bytes. + * The offset points to the current end of the string contents + * and is advanced (post-increment). + * "Unsafe" macro, assumes a valid code point and sufficient space in the string. + * Otherwise, the result is undefined. + * + * @param s const uint8 * string buffer + * @param i string offset + * @param c code point to append + * @see CBU8_APPEND + * @stable ICU 2.4 + */ +#define CBU8_APPEND_UNSAFE(s, i, c) { \ + if((uint32)(c)<=0x7f) { \ + (s)[(i)++]=(uint8)(c); \ + } else { \ + if((uint32)(c)<=0x7ff) { \ + (s)[(i)++]=(uint8)(((c)>>6)|0xc0); \ + } else { \ + if((uint32)(c)<=0xffff) { \ + (s)[(i)++]=(uint8)(((c)>>12)|0xe0); \ + } else { \ + (s)[(i)++]=(uint8)(((c)>>18)|0xf0); \ + (s)[(i)++]=(uint8)((((c)>>12)&0x3f)|0x80); \ + } \ + (s)[(i)++]=(uint8)((((c)>>6)&0x3f)|0x80); \ + } \ + (s)[(i)++]=(uint8)(((c)&0x3f)|0x80); \ + } \ +} + +// UTF-16 macros --------------------------------------------------------------- +// from utf16.h + +/** + * Does this code unit alone encode a code point (BMP, not a surrogate)? + * @param c 16-bit code unit + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU16_IS_SINGLE(c) !CBU_IS_SURROGATE(c) + +/** + * Is this code unit a lead surrogate (U+d800..U+dbff)? + * @param c 16-bit code unit + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800) + +/** + * Is this code unit a trail surrogate (U+dc00..U+dfff)? + * @param c 16-bit code unit + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00) + +/** + * Is this code unit a surrogate (U+d800..U+dfff)? + * @param c 16-bit code unit + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU16_IS_SURROGATE(c) CBU_IS_SURROGATE(c) + +/** + * Assuming c is a surrogate code point (U16_IS_SURROGATE(c)), + * is it a lead surrogate? + * @param c 16-bit code unit + * @return TRUE or FALSE + * @stable ICU 2.4 + */ +#define CBU16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0) + +/** + * Helper constant for CBU16_GET_SUPPLEMENTARY. + * @internal + */ +#define CBU16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000) + +/** + * Get a supplementary code point value (U+10000..U+10ffff) + * from its lead and trail surrogates. + * The result is undefined if the input values are not + * lead and trail surrogates. + * + * @param lead lead surrogate (U+d800..U+dbff) + * @param trail trail surrogate (U+dc00..U+dfff) + * @return supplementary code point (U+10000..U+10ffff) + * @stable ICU 2.4 + */ +#define CBU16_GET_SUPPLEMENTARY(lead, trail) \ + (((base_icu::UChar32)(lead)<<10UL)+(base_icu::UChar32)(trail)-CBU16_SURROGATE_OFFSET) + + +/** + * Get the lead surrogate (0xd800..0xdbff) for a + * supplementary code point (0x10000..0x10ffff). + * @param supplementary 32-bit code point (U+10000..U+10ffff) + * @return lead surrogate (U+d800..U+dbff) for supplementary + * @stable ICU 2.4 + */ +#define CBU16_LEAD(supplementary) \ + (base_icu::UChar)(((supplementary)>>10)+0xd7c0) + +/** + * Get the trail surrogate (0xdc00..0xdfff) for a + * supplementary code point (0x10000..0x10ffff). + * @param supplementary 32-bit code point (U+10000..U+10ffff) + * @return trail surrogate (U+dc00..U+dfff) for supplementary + * @stable ICU 2.4 + */ +#define CBU16_TRAIL(supplementary) \ + (base_icu::UChar)(((supplementary)&0x3ff)|0xdc00) + +/** + * How many 16-bit code units are used to encode this Unicode code point? (1 or 2) + * The result is not defined if c is not a Unicode code point (U+0000..U+10ffff). + * @param c 32-bit code point + * @return 1 or 2 + * @stable ICU 2.4 + */ +#define CBU16_LENGTH(c) ((uint32)(c)<=0xffff ? 1 : 2) + +/** + * The maximum number of 16-bit code units per Unicode code point (U+0000..U+10ffff). + * @return 2 + * @stable ICU 2.4 + */ +#define CBU16_MAX_LENGTH 2 + +/** + * Get a code point from a string at a code point boundary offset, + * and advance the offset to the next code point boundary. + * (Post-incrementing forward iteration.) + * "Safe" macro, handles unpaired surrogates and checks for string boundaries. + * + * The offset may point to the lead surrogate unit + * for a supplementary code point, in which case the macro will read + * the following trail surrogate as well. + * If the offset points to a trail surrogate or + * to a single, unpaired lead surrogate, then that itself + * will be returned as the code point. + * + * @param s const UChar * string + * @param i string offset, i<length + * @param length string length + * @param c output UChar32 variable + * @stable ICU 2.4 + */ +#define CBU16_NEXT(s, i, length, c) { \ + (c)=(s)[(i)++]; \ + if(CBU16_IS_LEAD(c)) { \ + uint16 __c2; \ + if((i)<(length) && CBU16_IS_TRAIL(__c2=(s)[(i)])) { \ + ++(i); \ + (c)=CBU16_GET_SUPPLEMENTARY((c), __c2); \ + } \ + } \ +} + +/** + * Append a code point to a string, overwriting 1 or 2 code units. + * The offset points to the current end of the string contents + * and is advanced (post-increment). + * "Unsafe" macro, assumes a valid code point and sufficient space in the string. + * Otherwise, the result is undefined. + * + * @param s const UChar * string buffer + * @param i string offset + * @param c code point to append + * @see CBU16_APPEND + * @stable ICU 2.4 + */ +#define CBU16_APPEND_UNSAFE(s, i, c) { \ + if((uint32)(c)<=0xffff) { \ + (s)[(i)++]=(uint16)(c); \ + } else { \ + (s)[(i)++]=(uint16)(((c)>>10)+0xd7c0); \ + (s)[(i)++]=(uint16)(((c)&0x3ff)|0xdc00); \ + } \ +} + +} // namesapce base_icu + +#endif // BASE_THIRD_PARTY_ICU_ICU_UTF_H_ diff --git a/third_party/chromium/base/time/clock.cc b/third_party/chromium/base/time/clock.cc new file mode 100644 index 0000000..34dc37e --- /dev/null +++ b/third_party/chromium/base/time/clock.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/clock.h" + +namespace base { + +Clock::~Clock() {} + +} // namespace base diff --git a/third_party/chromium/base/time/clock.h b/third_party/chromium/base/time/clock.h new file mode 100644 index 0000000..507a850 --- /dev/null +++ b/third_party/chromium/base/time/clock.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_TIME_CLOCK_H_ +#define BASE_TIME_CLOCK_H_ + +#include "base/base_export.h" +#include "base/time/time.h" + +namespace base { + +// A Clock is an interface for objects that vend Times. It is +// intended to be able to test the behavior of classes with respect to +// time. +// +// See DefaultClock (base/time/default_clock.h) for the default +// implementation that simply uses Time::Now(). +// +// (An implementation that uses Time::SystemTime() should be added as +// needed.) +// +// See SimpleTestClock (base/test/simple_test_clock.h) for a simple +// test implementation. +// +// See TickClock (base/time/tick_clock.h) for the equivalent interface for +// TimeTicks. +class BASE_EXPORT Clock { + public: + virtual ~Clock(); + + // Now() must be safe to call from any thread. The caller cannot + // make any ordering assumptions about the returned Time. For + // example, the system clock may change to an earlier time. + virtual Time Now() = 0; +}; + +} // namespace base + +#endif // BASE_TIME_CLOCK_H_ diff --git a/third_party/chromium/base/time/default_clock.cc b/third_party/chromium/base/time/default_clock.cc new file mode 100644 index 0000000..5f70114 --- /dev/null +++ b/third_party/chromium/base/time/default_clock.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/default_clock.h" + +namespace base { + +DefaultClock::~DefaultClock() {} + +Time DefaultClock::Now() { + return Time::Now(); +} + +} // namespace base diff --git a/third_party/chromium/base/time/default_clock.h b/third_party/chromium/base/time/default_clock.h new file mode 100644 index 0000000..140e6f4 --- /dev/null +++ b/third_party/chromium/base/time/default_clock.h @@ -0,0 +1,25 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_TIME_DEFAULT_CLOCK_H_ +#define BASE_TIME_DEFAULT_CLOCK_H_ + +#include "base/base_export.h" +#include "base/compiler_specific.h" +#include "base/time/clock.h" + +namespace base { + +// DefaultClock is a Clock implementation that uses Time::Now(). +class DefaultClock : public Clock { + public: + ~DefaultClock() override; + + // Simply returns Time::Now(). + Time Now() override; +}; + +} // namespace base + +#endif // BASE_TIME_DEFAULT_CLOCK_H_ diff --git a/third_party/chromium/base/time/time.cc b/third_party/chromium/base/time/time.cc new file mode 100644 index 0000000..7006407 --- /dev/null +++ b/third_party/chromium/base/time/time.cc @@ -0,0 +1,325 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/time.h" + +#include <cmath> +#include <ios> +#include <limits> +#include <ostream> +#include <sstream> + +#include "base/logging.h" +#include "base/strings/stringprintf.h" + +namespace base { + +// TimeDelta ------------------------------------------------------------------ + +// static +TimeDelta TimeDelta::Max() { + return TimeDelta(std::numeric_limits<int64>::max()); +} + +int TimeDelta::InDays() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int>::max(); + } + return static_cast<int>(delta_ / Time::kMicrosecondsPerDay); +} + +int TimeDelta::InHours() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int>::max(); + } + return static_cast<int>(delta_ / Time::kMicrosecondsPerHour); +} + +int TimeDelta::InMinutes() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int>::max(); + } + return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute); +} + +double TimeDelta::InSecondsF() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<double>::infinity(); + } + return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond; +} + +int64 TimeDelta::InSeconds() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return delta_ / Time::kMicrosecondsPerSecond; +} + +double TimeDelta::InMillisecondsF() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<double>::infinity(); + } + return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond; +} + +int64 TimeDelta::InMilliseconds() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return delta_ / Time::kMicrosecondsPerMillisecond; +} + +int64 TimeDelta::InMillisecondsRoundedUp() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return (delta_ + Time::kMicrosecondsPerMillisecond - 1) / + Time::kMicrosecondsPerMillisecond; +} + +int64 TimeDelta::InMicroseconds() const { + if (is_max()) { + // Preserve max to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return delta_; +} + +namespace time_internal { + +int64 SaturatedAdd(TimeDelta delta, int64 value) { + CheckedNumeric<int64> rv(delta.delta_); + rv += value; + return FromCheckedNumeric(rv); +} + +int64 SaturatedSub(TimeDelta delta, int64 value) { + CheckedNumeric<int64> rv(delta.delta_); + rv -= value; + return FromCheckedNumeric(rv); +} + +int64 FromCheckedNumeric(const CheckedNumeric<int64> value) { + if (value.IsValid()) + return value.ValueUnsafe(); + + // We could return max/min but we don't really expose what the maximum delta + // is. Instead, return max/(-max), which is something that clients can reason + // about. + // TODO(rvargas) crbug.com/332611: don't use internal values. + int64 limit = std::numeric_limits<int64>::max(); + if (value.validity() == internal::RANGE_UNDERFLOW) + limit = -limit; + return value.ValueOrDefault(limit); +} + +} // namespace time_internal + +std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) { + return os << time_delta.InSecondsF() << "s"; +} + +// Time ----------------------------------------------------------------------- + +// static +Time Time::Max() { + return Time(std::numeric_limits<int64>::max()); +} + +// static +Time Time::FromTimeT(time_t tt) { + if (tt == 0) + return Time(); // Preserve 0 so we can tell it doesn't exist. + if (tt == std::numeric_limits<time_t>::max()) + return Max(); + return Time((tt * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset); +} + +time_t Time::ToTimeT() const { + if (is_null()) + return 0; // Preserve 0 so we can tell it doesn't exist. + if (is_max()) { + // Preserve max without offset to prevent overflow. + return std::numeric_limits<time_t>::max(); + } + if (std::numeric_limits<int64>::max() - kTimeTToMicrosecondsOffset <= us_) { + DLOG(WARNING) << "Overflow when converting base::Time with internal " << + "value " << us_ << " to time_t."; + return std::numeric_limits<time_t>::max(); + } + return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond; +} + +// static +Time Time::FromDoubleT(double dt) { + if (dt == 0 || std::isnan(dt)) + return Time(); // Preserve 0 so we can tell it doesn't exist. + if (dt == std::numeric_limits<double>::infinity()) + return Max(); + return Time(static_cast<int64>((dt * + static_cast<double>(kMicrosecondsPerSecond)) + + kTimeTToMicrosecondsOffset)); +} + +double Time::ToDoubleT() const { + if (is_null()) + return 0; // Preserve 0 so we can tell it doesn't exist. + if (is_max()) { + // Preserve max without offset to prevent overflow. + return std::numeric_limits<double>::infinity(); + } + return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) / + static_cast<double>(kMicrosecondsPerSecond)); +} + +#if defined(OS_POSIX) +// static +Time Time::FromTimeSpec(const timespec& ts) { + return FromDoubleT(ts.tv_sec + + static_cast<double>(ts.tv_nsec) / + base::Time::kNanosecondsPerSecond); +} +#endif + +// static +Time Time::FromJsTime(double ms_since_epoch) { + // The epoch is a valid time, so this constructor doesn't interpret + // 0 as the null time. + if (ms_since_epoch == std::numeric_limits<double>::infinity()) + return Max(); + return Time(static_cast<int64>(ms_since_epoch * kMicrosecondsPerMillisecond) + + kTimeTToMicrosecondsOffset); +} + +double Time::ToJsTime() const { + if (is_null()) { + // Preserve 0 so the invalid result doesn't depend on the platform. + return 0; + } + if (is_max()) { + // Preserve max without offset to prevent overflow. + return std::numeric_limits<double>::infinity(); + } + return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) / + kMicrosecondsPerMillisecond); +} + +int64 Time::ToJavaTime() const { + if (is_null()) { + // Preserve 0 so the invalid result doesn't depend on the platform. + return 0; + } + if (is_max()) { + // Preserve max without offset to prevent overflow. + return std::numeric_limits<int64>::max(); + } + return ((us_ - kTimeTToMicrosecondsOffset) / + kMicrosecondsPerMillisecond); +} + +// static +Time Time::UnixEpoch() { + Time time; + time.us_ = kTimeTToMicrosecondsOffset; + return time; +} + +Time Time::LocalMidnight() const { + Exploded exploded; + LocalExplode(&exploded); + exploded.hour = 0; + exploded.minute = 0; + exploded.second = 0; + exploded.millisecond = 0; + return FromLocalExploded(exploded); +} + +std::ostream& operator<<(std::ostream& os, Time time) { + Time::Exploded exploded; + time.UTCExplode(&exploded); + // Use StringPrintf because iostreams formatting is painful. + return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC", + exploded.year, + exploded.month, + exploded.day_of_month, + exploded.hour, + exploded.minute, + exploded.second, + exploded.millisecond); +} + +// Local helper class to hold the conversion from Time to TickTime at the +// time of the Unix epoch. +class UnixEpochSingleton { + public: + UnixEpochSingleton() + : unix_epoch_(TimeTicks::Now() - (Time::Now() - Time::UnixEpoch())) {} + + TimeTicks unix_epoch() const { return unix_epoch_; } + + private: + const TimeTicks unix_epoch_; + + DISALLOW_COPY_AND_ASSIGN(UnixEpochSingleton); +}; + +TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase, + TimeDelta tick_interval) const { + // |interval_offset| is the offset from |this| to the next multiple of + // |tick_interval| after |tick_phase|, possibly negative if in the past. + TimeDelta interval_offset = (tick_phase - *this) % tick_interval; + // If |this| is exactly on the interval (i.e. offset==0), don't adjust. + // Otherwise, if |tick_phase| was in the past, adjust forward to the next + // tick after |this|. + if (!interval_offset.is_zero() && tick_phase < *this) + interval_offset += tick_interval; + return *this + interval_offset; +} + +std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) { + // This function formats a TimeTicks object as "bogo-microseconds". + // The origin and granularity of the count are platform-specific, and may very + // from run to run. Although bogo-microseconds usually roughly correspond to + // real microseconds, the only real guarantee is that the number never goes + // down during a single run. + const TimeDelta as_time_delta = time_ticks - TimeTicks(); + return os << as_time_delta.InMicroseconds() << " bogo-microseconds"; +} + +std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) { + const TimeDelta as_time_delta = thread_ticks - ThreadTicks(); + return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds"; +} + +std::ostream& operator<<(std::ostream& os, TraceTicks trace_ticks) { + const TimeDelta as_time_delta = trace_ticks - TraceTicks(); + return os << as_time_delta.InMicroseconds() << " bogo-trace-microseconds"; +} + +// Time::Exploded ------------------------------------------------------------- + +inline bool is_in_range(int value, int lo, int hi) { + return lo <= value && value <= hi; +} + +bool Time::Exploded::HasValidValues() const { + return is_in_range(month, 1, 12) && + is_in_range(day_of_week, 0, 6) && + is_in_range(day_of_month, 1, 31) && + is_in_range(hour, 0, 23) && + is_in_range(minute, 0, 59) && + is_in_range(second, 0, 60) && + is_in_range(millisecond, 0, 999); +} + +} // namespace base diff --git a/third_party/chromium/base/time/time.h b/third_party/chromium/base/time/time.h new file mode 100644 index 0000000..f421539 --- /dev/null +++ b/third_party/chromium/base/time/time.h @@ -0,0 +1,784 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Time represents an absolute point in coordinated universal time (UTC), +// internally represented as microseconds (s/1,000,000) since the Windows epoch +// (1601-01-01 00:00:00 UTC). System-dependent clock interface routines are +// defined in time_PLATFORM.cc. Note that values for Time may skew and jump +// around as the operating system makes adjustments to synchronize (e.g., with +// NTP servers). Thus, client code that uses the Time class must account for +// this. +// +// TimeDelta represents a duration of time, internally represented in +// microseconds. +// +// TimeTicks, ThreadTicks, and TraceTicks represent an abstract time that is +// most of the time incrementing, for use in measuring time durations. +// Internally, they are represented in microseconds. They can not be converted +// to a human-readable time, but are guaranteed not to decrease (unlike the Time +// class). Note that TimeTicks may "stand still" (e.g., if the computer is +// suspended), and ThreadTicks will "stand still" whenever the thread has been +// de-scheduled by the operating system. +// +// All time classes are copyable, assignable, and occupy 64-bits per +// instance. Thus, they can be efficiently passed by-value (as opposed to +// by-reference). +// +// Definitions of operator<< are provided to make these types work with +// DCHECK_EQ() and other log macros. For human-readable formatting, see +// "base/i18n/time_formatting.h". +// +// So many choices! Which time class should you use? Examples: +// +// Time: Interpreting the wall-clock time provided by a remote +// system. Detecting whether cached resources have +// expired. Providing the user with a display of the current date +// and time. Determining the amount of time between events across +// re-boots of the machine. +// +// TimeTicks: Tracking the amount of time a task runs. Executing delayed +// tasks at the right time. Computing presentation timestamps. +// Synchronizing audio and video using TimeTicks as a common +// reference clock (lip-sync). Measuring network round-trip +// latency. +// +// ThreadTicks: Benchmarking how long the current thread has been doing actual +// work. +// +// TraceTicks: This is only meant to be used by the event tracing +// infrastructure, and by outside code modules in special +// circumstances. Please be sure to consult a +// base/trace_event/OWNER before committing any new code that +// uses this. + +#ifndef BASE_TIME_TIME_H_ +#define BASE_TIME_TIME_H_ + +#include <time.h> + +#include <iosfwd> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/build/build_config.h" +#include "base/numerics/safe_math.h" + +#if defined(OS_MACOSX) +#include <CoreFoundation/CoreFoundation.h> +// Avoid Mac system header macro leak. +#undef TYPE_BOOL +#endif + +#if defined(OS_POSIX) +#include <unistd.h> +#include <sys/time.h> +#endif + +#if defined(OS_WIN) +// For FILETIME in FromFileTime, until it moves to a new converter class. +// See TODO(iyengar) below. +#include <windows.h> +#endif + +#include <limits> + +namespace base { + +class TimeDelta; + +// The functions in the time_internal namespace are meant to be used only by the +// time classes and functions. Please use the math operators defined in the +// time classes instead. +namespace time_internal { + +// Add or subtract |value| from a TimeDelta. The int64 argument and return value +// are in terms of a microsecond timebase. +BASE_EXPORT int64 SaturatedAdd(TimeDelta delta, int64 value); +BASE_EXPORT int64 SaturatedSub(TimeDelta delta, int64 value); + +// Clamp |value| on overflow and underflow conditions. The int64 argument and +// return value are in terms of a microsecond timebase. +BASE_EXPORT int64 FromCheckedNumeric(const CheckedNumeric<int64> value); + +} // namespace time_internal + +// TimeDelta ------------------------------------------------------------------ + +class BASE_EXPORT TimeDelta { + public: + TimeDelta() : delta_(0) { + } + + // Converts units of time to TimeDeltas. + static TimeDelta FromDays(int days); + static TimeDelta FromHours(int hours); + static TimeDelta FromMinutes(int minutes); + static TimeDelta FromSeconds(int64 secs); + static TimeDelta FromMilliseconds(int64 ms); + static TimeDelta FromSecondsD(double secs); + static TimeDelta FromMillisecondsD(double ms); + static TimeDelta FromMicroseconds(int64 us); +#if defined(OS_WIN) + static TimeDelta FromQPCValue(LONGLONG qpc_value); +#endif + + // Converts an integer value representing TimeDelta to a class. This is used + // when deserializing a |TimeDelta| structure, using a value known to be + // compatible. It is not provided as a constructor because the integer type + // may be unclear from the perspective of a caller. + static TimeDelta FromInternalValue(int64 delta) { + return TimeDelta(delta); + } + + // Returns the maximum time delta, which should be greater than any reasonable + // time delta we might compare it to. Adding or subtracting the maximum time + // delta to a time or another time delta has an undefined result. + static TimeDelta Max(); + + // Returns the internal numeric value of the TimeDelta object. Please don't + // use this and do arithmetic on it, as it is more error prone than using the + // provided operators. + // For serializing, use FromInternalValue to reconstitute. + int64 ToInternalValue() const { + return delta_; + } + + // Returns the magnitude (absolute value) of this TimeDelta. + TimeDelta magnitude() const { + // Some toolchains provide an incomplete C++11 implementation and lack an + // int64 overload for std::abs(). The following is a simple branchless + // implementation: + const int64 mask = delta_ >> (sizeof(delta_) * 8 - 1); + return TimeDelta((delta_ + mask) ^ mask); + } + + // Returns true if the time delta is zero. + bool is_zero() const { + return delta_ == 0; + } + + // Returns true if the time delta is the maximum time delta. + bool is_max() const { + return delta_ == std::numeric_limits<int64>::max(); + } + +#if defined(OS_POSIX) + struct timespec ToTimeSpec() const; +#endif + + // Returns the time delta in some unit. The F versions return a floating + // point value, the "regular" versions return a rounded-down value. + // + // InMillisecondsRoundedUp() instead returns an integer that is rounded up + // to the next full millisecond. + int InDays() const; + int InHours() const; + int InMinutes() const; + double InSecondsF() const; + int64 InSeconds() const; + double InMillisecondsF() const; + int64 InMilliseconds() const; + int64 InMillisecondsRoundedUp() const; + int64 InMicroseconds() const; + + TimeDelta& operator=(TimeDelta other) { + delta_ = other.delta_; + return *this; + } + + // Computations with other deltas. + TimeDelta operator+(TimeDelta other) const { + return TimeDelta(time_internal::SaturatedAdd(*this, other.delta_)); + } + TimeDelta operator-(TimeDelta other) const { + return TimeDelta(time_internal::SaturatedSub(*this, other.delta_)); + } + + TimeDelta& operator+=(TimeDelta other) { + return *this = (*this + other); + } + TimeDelta& operator-=(TimeDelta other) { + return *this = (*this - other); + } + TimeDelta operator-() const { + return TimeDelta(-delta_); + } + + // Computations with numeric types. + template<typename T> + TimeDelta operator*(T a) const { + CheckedNumeric<int64> rv(delta_); + rv *= a; + return TimeDelta(time_internal::FromCheckedNumeric(rv)); + } + template<typename T> + TimeDelta operator/(T a) const { + CheckedNumeric<int64> rv(delta_); + rv /= a; + return TimeDelta(time_internal::FromCheckedNumeric(rv)); + } + template<typename T> + TimeDelta& operator*=(T a) { + return *this = (*this * a); + } + template<typename T> + TimeDelta& operator/=(T a) { + return *this = (*this / a); + } + + int64 operator/(TimeDelta a) const { + return delta_ / a.delta_; + } + TimeDelta operator%(TimeDelta a) const { + return TimeDelta(delta_ % a.delta_); + } + + // Comparison operators. + bool operator==(TimeDelta other) const { + return delta_ == other.delta_; + } + bool operator!=(TimeDelta other) const { + return delta_ != other.delta_; + } + bool operator<(TimeDelta other) const { + return delta_ < other.delta_; + } + bool operator<=(TimeDelta other) const { + return delta_ <= other.delta_; + } + bool operator>(TimeDelta other) const { + return delta_ > other.delta_; + } + bool operator>=(TimeDelta other) const { + return delta_ >= other.delta_; + } + + private: + friend int64 time_internal::SaturatedAdd(TimeDelta delta, int64 value); + friend int64 time_internal::SaturatedSub(TimeDelta delta, int64 value); + + // Constructs a delta given the duration in microseconds. This is private + // to avoid confusion by callers with an integer constructor. Use + // FromSeconds, FromMilliseconds, etc. instead. + explicit TimeDelta(int64 delta_us) : delta_(delta_us) { + } + + // Delta in microseconds. + int64 delta_; +}; + +template<typename T> +inline TimeDelta operator*(T a, TimeDelta td) { + return td * a; +} + +// For logging use only. +BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeDelta time_delta); + +// Do not reference the time_internal::TimeBase template class directly. Please +// use one of the time subclasses instead, and only reference the public +// TimeBase members via those classes. +namespace time_internal { + +// TimeBase-------------------------------------------------------------------- + +// Provides value storage and comparison/math operations common to all time +// classes. Each subclass provides for strong type-checking to ensure +// semantically meaningful comparison/math of time values from the same clock +// source or timeline. +template<class TimeClass> +class TimeBase { + public: + static const int64 kHoursPerDay = 24; + static const int64 kMillisecondsPerSecond = 1000; + static const int64 kMillisecondsPerDay = kMillisecondsPerSecond * 60 * 60 * + kHoursPerDay; + static const int64 kMicrosecondsPerMillisecond = 1000; + static const int64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond * + kMillisecondsPerSecond; + static const int64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60; + static const int64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60; + static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * kHoursPerDay; + static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7; + static const int64 kNanosecondsPerMicrosecond = 1000; + static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond * + kMicrosecondsPerSecond; + + // Returns true if this object has not been initialized. + // + // Warning: Be careful when writing code that performs math on time values, + // since it's possible to produce a valid "zero" result that should not be + // interpreted as a "null" value. + bool is_null() const { + return us_ == 0; + } + + // Returns true if this object represents the maximum time. + bool is_max() const { + return us_ == std::numeric_limits<int64>::max(); + } + + // For serializing only. Use FromInternalValue() to reconstitute. Please don't + // use this and do arithmetic on it, as it is more error prone than using the + // provided operators. + int64 ToInternalValue() const { + return us_; + } + + TimeClass& operator=(TimeClass other) { + us_ = other.us_; + return *(static_cast<TimeClass*>(this)); + } + + // Compute the difference between two times. + TimeDelta operator-(TimeClass other) const { + return TimeDelta::FromMicroseconds(us_ - other.us_); + } + + // Return a new time modified by some delta. + TimeClass operator+(TimeDelta delta) const { + return TimeClass(time_internal::SaturatedAdd(delta, us_)); + } + TimeClass operator-(TimeDelta delta) const { + return TimeClass(-time_internal::SaturatedSub(delta, us_)); + } + + // Modify by some time delta. + TimeClass& operator+=(TimeDelta delta) { + return static_cast<TimeClass&>(*this = (*this + delta)); + } + TimeClass& operator-=(TimeDelta delta) { + return static_cast<TimeClass&>(*this = (*this - delta)); + } + + // Comparison operators + bool operator==(TimeClass other) const { + return us_ == other.us_; + } + bool operator!=(TimeClass other) const { + return us_ != other.us_; + } + bool operator<(TimeClass other) const { + return us_ < other.us_; + } + bool operator<=(TimeClass other) const { + return us_ <= other.us_; + } + bool operator>(TimeClass other) const { + return us_ > other.us_; + } + bool operator>=(TimeClass other) const { + return us_ >= other.us_; + } + + // Converts an integer value representing TimeClass to a class. This is used + // when deserializing a |TimeClass| structure, using a value known to be + // compatible. It is not provided as a constructor because the integer type + // may be unclear from the perspective of a caller. + static TimeClass FromInternalValue(int64 us) { + return TimeClass(us); + } + + protected: + explicit TimeBase(int64 us) : us_(us) { + } + + // Time value in a microsecond timebase. + int64 us_; +}; + +} // namespace time_internal + +template<class TimeClass> +inline TimeClass operator+(TimeDelta delta, TimeClass t) { + return t + delta; +} + +// Time ----------------------------------------------------------------------- + +// Represents a wall clock time in UTC. Values are not guaranteed to be +// monotonically non-decreasing and are subject to large amounts of skew. +class BASE_EXPORT Time : public time_internal::TimeBase<Time> { + public: + // The representation of Jan 1, 1970 UTC in microseconds since the + // platform-dependent epoch. + static const int64 kTimeTToMicrosecondsOffset; + +#if !defined(OS_WIN) + // On Mac & Linux, this value is the delta from the Windows epoch of 1601 to + // the Posix delta of 1970. This is used for migrating between the old + // 1970-based epochs to the new 1601-based ones. It should be removed from + // this global header and put in the platform-specific ones when we remove the + // migration code. + static const int64 kWindowsEpochDeltaMicroseconds; +#else + // To avoid overflow in QPC to Microseconds calculations, since we multiply + // by kMicrosecondsPerSecond, then the QPC value should not exceed + // (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply. + static const int64 kQPCOverflowThreshold = 0x8637BD05AF7; +#endif + + // Represents an exploded time that can be formatted nicely. This is kind of + // like the Win32 SYSTEMTIME structure or the Unix "struct tm" with a few + // additions and changes to prevent errors. + struct Exploded { + int year; // Four digit year "2007" + int month; // 1-based month (values 1 = January, etc.) + int day_of_week; // 0-based day of week (0 = Sunday, etc.) + int day_of_month; // 1-based day of month (1-31) + int hour; // Hour within the current day (0-23) + int minute; // Minute within the current hour (0-59) + int second; // Second within the current minute (0-59 plus leap + // seconds which may take it up to 60). + int millisecond; // Milliseconds within the current second (0-999) + + // A cursory test for whether the data members are within their + // respective ranges. A 'true' return value does not guarantee the + // Exploded value can be successfully converted to a Time value. + bool HasValidValues() const; + }; + + // Contains the NULL time. Use Time::Now() to get the current time. + Time() : TimeBase(0) { + } + + // Returns the time for epoch in Unix-like system (Jan 1, 1970). + static Time UnixEpoch(); + + // Returns the current time. Watch out, the system might adjust its clock + // in which case time will actually go backwards. We don't guarantee that + // times are increasing, or that two calls to Now() won't be the same. + static Time Now(); + + // Returns the maximum time, which should be greater than any reasonable time + // with which we might compare it. + static Time Max(); + + // Returns the current time. Same as Now() except that this function always + // uses system time so that there are no discrepancies between the returned + // time and system time even on virtual environments including our test bot. + // For timing sensitive unittests, this function should be used. + static Time NowFromSystemTime(); + + // Converts to/from time_t in UTC and a Time class. + // TODO(brettw) this should be removed once everybody starts using the |Time| + // class. + static Time FromTimeT(time_t tt); + time_t ToTimeT() const; + + // Converts time to/from a double which is the number of seconds since epoch + // (Jan 1, 1970). Webkit uses this format to represent time. + // Because WebKit initializes double time value to 0 to indicate "not + // initialized", we map it to empty Time object that also means "not + // initialized". + static Time FromDoubleT(double dt); + double ToDoubleT() const; + +#if defined(OS_POSIX) + // Converts the timespec structure to time. MacOS X 10.8.3 (and tentatively, + // earlier versions) will have the |ts|'s tv_nsec component zeroed out, + // having a 1 second resolution, which agrees with + // https://developer.apple.com/legacy/library/#technotes/tn/tn1150.html#HFSPlusDates. + static Time FromTimeSpec(const timespec& ts); +#endif + + // Converts to/from the Javascript convention for times, a number of + // milliseconds since the epoch: + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/getTime. + static Time FromJsTime(double ms_since_epoch); + double ToJsTime() const; + + // Converts to Java convention for times, a number of + // milliseconds since the epoch. + int64 ToJavaTime() const; + +#if defined(OS_POSIX) + static Time FromTimeVal(struct timeval t); + struct timeval ToTimeVal() const; +#endif + +#if defined(OS_MACOSX) + static Time FromCFAbsoluteTime(CFAbsoluteTime t); + CFAbsoluteTime ToCFAbsoluteTime() const; +#endif + +#if defined(OS_WIN) + static Time FromFileTime(FILETIME ft); + FILETIME ToFileTime() const; + + // The minimum time of a low resolution timer. This is basically a windows + // constant of ~15.6ms. While it does vary on some older OS versions, we'll + // treat it as static across all windows versions. + static const int kMinLowResolutionThresholdMs = 16; + + // Enable or disable Windows high resolution timer. + static void EnableHighResolutionTimer(bool enable); + + // Activates or deactivates the high resolution timer based on the |activate| + // flag. If the HighResolutionTimer is not Enabled (see + // EnableHighResolutionTimer), this function will return false. Otherwise + // returns true. Each successful activate call must be paired with a + // subsequent deactivate call. + // All callers to activate the high resolution timer must eventually call + // this function to deactivate the high resolution timer. + static bool ActivateHighResolutionTimer(bool activate); + + // Returns true if the high resolution timer is both enabled and activated. + // This is provided for testing only, and is not tracked in a thread-safe + // way. + static bool IsHighResolutionTimerInUse(); +#endif + + // Converts an exploded structure representing either the local time or UTC + // into a Time class. + static Time FromUTCExploded(const Exploded& exploded) { + return FromExploded(false, exploded); + } + static Time FromLocalExploded(const Exploded& exploded) { + return FromExploded(true, exploded); + } + + // Fills the given exploded structure with either the local time or UTC from + // this time structure (containing UTC). + void UTCExplode(Exploded* exploded) const { + return Explode(false, exploded); + } + void LocalExplode(Exploded* exploded) const { + return Explode(true, exploded); + } + + // Rounds this time down to the nearest day in local time. It will represent + // midnight on that day. + Time LocalMidnight() const; + + private: + friend class time_internal::TimeBase<Time>; + + explicit Time(int64 us) : TimeBase(us) { + } + + // Explodes the given time to either local time |is_local = true| or UTC + // |is_local = false|. + void Explode(bool is_local, Exploded* exploded) const; + + // Unexplodes a given time assuming the source is either local time + // |is_local = true| or UTC |is_local = false|. + static Time FromExploded(bool is_local, const Exploded& exploded); +}; + +// Inline the TimeDelta factory methods, for fast TimeDelta construction. + +// static +inline TimeDelta TimeDelta::FromDays(int days) { + // Preserve max to prevent overflow. + if (days == std::numeric_limits<int>::max()) + return Max(); + return TimeDelta(days * Time::kMicrosecondsPerDay); +} + +// static +inline TimeDelta TimeDelta::FromHours(int hours) { + // Preserve max to prevent overflow. + if (hours == std::numeric_limits<int>::max()) + return Max(); + return TimeDelta(hours * Time::kMicrosecondsPerHour); +} + +// static +inline TimeDelta TimeDelta::FromMinutes(int minutes) { + // Preserve max to prevent overflow. + if (minutes == std::numeric_limits<int>::max()) + return Max(); + return TimeDelta(minutes * Time::kMicrosecondsPerMinute); +} + +// static +inline TimeDelta TimeDelta::FromSeconds(int64 secs) { + // Preserve max to prevent overflow. + if (secs == std::numeric_limits<int64>::max()) + return Max(); + return TimeDelta(secs * Time::kMicrosecondsPerSecond); +} + +// static +inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) { + // Preserve max to prevent overflow. + if (ms == std::numeric_limits<int64>::max()) + return Max(); + return TimeDelta(ms * Time::kMicrosecondsPerMillisecond); +} + +// static +inline TimeDelta TimeDelta::FromSecondsD(double secs) { + // Preserve max to prevent overflow. + if (secs == std::numeric_limits<double>::infinity()) + return Max(); + return TimeDelta(static_cast<int64>(secs * Time::kMicrosecondsPerSecond)); +} + +// static +inline TimeDelta TimeDelta::FromMillisecondsD(double ms) { + // Preserve max to prevent overflow. + if (ms == std::numeric_limits<double>::infinity()) + return Max(); + return TimeDelta(static_cast<int64>(ms * Time::kMicrosecondsPerMillisecond)); +} + +// static +inline TimeDelta TimeDelta::FromMicroseconds(int64 us) { + // Preserve max to prevent overflow. + if (us == std::numeric_limits<int64>::max()) + return Max(); + return TimeDelta(us); +} + +// For logging use only. +BASE_EXPORT std::ostream& operator<<(std::ostream& os, Time time); + +// TimeTicks ------------------------------------------------------------------ + +// Represents monotonically non-decreasing clock time. +class TimeTicks : public time_internal::TimeBase<TimeTicks> { + public: + TimeTicks() : TimeBase(0) { + } + + // Platform-dependent tick count representing "right now." When + // IsHighResolution() returns false, the resolution of the clock could be + // as coarse as ~15.6ms. Otherwise, the resolution should be no worse than one + // microsecond. + static TimeTicks Now(); + + // Returns true if the high resolution clock is working on this system and + // Now() will return high resolution values. Note that, on systems where the + // high resolution clock works but is deemed inefficient, the low resolution + // clock will be used instead. + static bool IsHighResolution(); + +#if defined(OS_WIN) + // Translates an absolute QPC timestamp into a TimeTicks value. The returned + // value has the same origin as Now(). Do NOT attempt to use this if + // IsHighResolution() returns false. + static TimeTicks FromQPCValue(LONGLONG qpc_value); +#endif + + // Get the TimeTick value at the time of the UnixEpoch. This is useful when + // you need to relate the value of TimeTicks to a real time and date. + // Note: Upon first invocation, this function takes a snapshot of the realtime + // clock to establish a reference point. This function will return the same + // value for the duration of the application, but will be different in future + // application runs. + static TimeTicks UnixEpoch(); + + // Returns |this| snapped to the next tick, given a |tick_phase| and + // repeating |tick_interval| in both directions. |this| may be before, + // after, or equal to the |tick_phase|. + TimeTicks SnappedToNextTick(TimeTicks tick_phase, + TimeDelta tick_interval) const; + +#if defined(OS_WIN) + protected: + typedef DWORD (*TickFunctionType)(void); + static TickFunctionType SetMockTickFunction(TickFunctionType ticker); +#endif + + private: + friend class time_internal::TimeBase<TimeTicks>; + + // Please use Now() to create a new object. This is for internal use + // and testing. + explicit TimeTicks(int64 us) : TimeBase(us) { + } +}; + +// For logging use only. +std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks); + +// ThreadTicks ---------------------------------------------------------------- + +// Represents a clock, specific to a particular thread, than runs only while the +// thread is running. +class ThreadTicks : public time_internal::TimeBase<ThreadTicks> { + public: + ThreadTicks() : TimeBase(0) { + } + + // Returns true if ThreadTicks::Now() is supported on this system. + static bool IsSupported() { +#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ + (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID) + return true; +#else + return false; +#endif + } + + // Returns thread-specific CPU-time on systems that support this feature. + // Needs to be guarded with a call to IsSupported(). Use this timer + // to (approximately) measure how much time the calling thread spent doing + // actual work vs. being de-scheduled. May return bogus results if the thread + // migrates to another CPU between two calls. + static ThreadTicks Now(); + + private: + friend class time_internal::TimeBase<ThreadTicks>; + + // Please use Now() to create a new object. This is for internal use + // and testing. + explicit ThreadTicks(int64 us) : TimeBase(us) { + } +}; + +// For logging use only. +std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks); + +// TraceTicks ---------------------------------------------------------------- + +// Represents high-resolution system trace clock time. +class TraceTicks : public time_internal::TimeBase<TraceTicks> { + public: + // We define this even without OS_CHROMEOS for seccomp sandbox testing. +#if defined(OS_LINUX) + // Force definition of the system trace clock; it is a chromeos-only api + // at the moment and surfacing it in the right place requires mucking + // with glibc et al. + static const clockid_t kClockSystemTrace = 11; +#endif + + TraceTicks() : TimeBase(0) { + } + + // Returns the current system trace time or, if not available on this + // platform, a high-resolution time value; or a low-resolution time value if + // neither are avalable. On systems where a global trace clock is defined, + // timestamping TraceEvents's with this value guarantees synchronization + // between events collected inside chrome and events collected outside + // (e.g. kernel, X server). + // + // On some platforms, the clock source used for tracing can vary depending on + // hardware and/or kernel support. Do not make any assumptions without + // consulting the documentation for this functionality in the time_win.cc, + // time_posix.cc, etc. files. + // + // NOTE: This is only meant to be used by the event tracing infrastructure, + // and by outside code modules in special circumstances. Please be sure to + // consult a base/trace_event/OWNER before committing any new code that uses + // this. + static TraceTicks Now(); + + private: + friend class time_internal::TimeBase<TraceTicks>; + + // Please use Now() to create a new object. This is for internal use + // and testing. + explicit TraceTicks(int64 us) : TimeBase(us) { + } +}; + +// For logging use only. +std::ostream& operator<<(std::ostream& os, TraceTicks time_ticks); + +} // namespace base + +#endif // BASE_TIME_TIME_H_ diff --git a/third_party/chromium/base/time/time_posix.cc b/third_party/chromium/base/time/time_posix.cc new file mode 100644 index 0000000..b625af6 --- /dev/null +++ b/third_party/chromium/base/time/time_posix.cc @@ -0,0 +1,368 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/time.h" + +#include <stdint.h> +#include <sys/time.h> +#include <time.h> +#if defined(OS_ANDROID) && !defined(__LP64__) +#include <time64.h> +#endif +#include <unistd.h> + +#include <limits> +#include <ostream> + +#include "base/basictypes.h" +#include "base/build/build_config.h" +#include "base/logging.h" + +namespace { + +#if !defined(OS_MACOSX) +// Define a system-specific SysTime that wraps either to a time_t or +// a time64_t depending on the host system, and associated convertion. +// See crbug.com/162007 +#if defined(OS_ANDROID) && !defined(__LP64__) +typedef time64_t SysTime; + +SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) { + if (is_local) + return mktime64(timestruct); + else + return timegm64(timestruct); +} + +void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) { + if (is_local) + localtime64_r(&t, timestruct); + else + gmtime64_r(&t, timestruct); +} + +#else // OS_ANDROID && !__LP64__ +typedef time_t SysTime; + +SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) { + if (is_local) + return mktime(timestruct); + else + return timegm(timestruct); +} + +void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) { + if (is_local) + localtime_r(&t, timestruct); + else + gmtime_r(&t, timestruct); +} +#endif // OS_ANDROID + +int64 ConvertTimespecToMicros(const struct timespec& ts) { + base::CheckedNumeric<int64> result(ts.tv_sec); + result *= base::Time::kMicrosecondsPerSecond; + result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond); + return result.ValueOrDie(); +} + +// Helper function to get results from clock_gettime() and convert to a +// microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported +// on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines +// _POSIX_MONOTONIC_CLOCK to -1. +#if (defined(OS_POSIX) && \ + defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \ + defined(OS_BSD) || defined(OS_ANDROID) +int64 ClockNow(clockid_t clk_id) { + struct timespec ts; + if (clock_gettime(clk_id, &ts) != 0) { + NOTREACHED() << "clock_gettime(" << clk_id << ") failed."; + return 0; + } + return ConvertTimespecToMicros(ts); +} +#else // _POSIX_MONOTONIC_CLOCK +#error No usable tick clock function on this platform. +#endif // _POSIX_MONOTONIC_CLOCK +#endif // !defined(OS_MACOSX) + +} // namespace + +namespace base { + +struct timespec TimeDelta::ToTimeSpec() const { + int64 microseconds = InMicroseconds(); + time_t seconds = 0; + if (microseconds >= Time::kMicrosecondsPerSecond) { + seconds = InSeconds(); + microseconds -= seconds * Time::kMicrosecondsPerSecond; + } + struct timespec result = + {seconds, + static_cast<long>(microseconds * Time::kNanosecondsPerMicrosecond)}; + return result; +} + +#if !defined(OS_MACOSX) +// The Time routines in this file use standard POSIX routines, or almost- +// standard routines in the case of timegm. We need to use a Mach-specific +// function for TimeTicks::Now() on Mac OS X. + +// Time ----------------------------------------------------------------------- + +// Windows uses a Gregorian epoch of 1601. We need to match this internally +// so that our time representations match across all platforms. See bug 14734. +// irb(main):010:0> Time.at(0).getutc() +// => Thu Jan 01 00:00:00 UTC 1970 +// irb(main):011:0> Time.at(-11644473600).getutc() +// => Mon Jan 01 00:00:00 UTC 1601 +static const int64 kWindowsEpochDeltaSeconds = INT64_C(11644473600); + +// static +const int64 Time::kWindowsEpochDeltaMicroseconds = + kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond; + +// Some functions in time.cc use time_t directly, so we provide an offset +// to convert from time_t (Unix epoch) and internal (Windows epoch). +// static +const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds; + +// static +Time Time::Now() { + struct timeval tv; + struct timezone tz = { 0, 0 }; // UTC + if (gettimeofday(&tv, &tz) != 0) { + DCHECK(0) << "Could not determine time of day"; + LOG(ERROR) << "Call to gettimeofday failed."; + // Return null instead of uninitialized |tv| value, which contains random + // garbage data. This may result in the crash seen in crbug.com/147570. + return Time(); + } + // Combine seconds and microseconds in a 64-bit field containing microseconds + // since the epoch. That's enough for nearly 600 centuries. Adjust from + // Unix (1970) to Windows (1601) epoch. + return Time((tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec) + + kWindowsEpochDeltaMicroseconds); +} + +// static +Time Time::NowFromSystemTime() { + // Just use Now() because Now() returns the system time. + return Now(); +} + +void Time::Explode(bool is_local, Exploded* exploded) const { + // Time stores times with microsecond resolution, but Exploded only carries + // millisecond resolution, so begin by being lossy. Adjust from Windows + // epoch (1601) to Unix epoch (1970); + int64 microseconds = us_ - kWindowsEpochDeltaMicroseconds; + // The following values are all rounded towards -infinity. + int64 milliseconds; // Milliseconds since epoch. + SysTime seconds; // Seconds since epoch. + int millisecond; // Exploded millisecond value (0-999). + if (microseconds >= 0) { + // Rounding towards -infinity <=> rounding towards 0, in this case. + milliseconds = microseconds / kMicrosecondsPerMillisecond; + seconds = milliseconds / kMillisecondsPerSecond; + millisecond = milliseconds % kMillisecondsPerSecond; + } else { + // Round these *down* (towards -infinity). + milliseconds = (microseconds - kMicrosecondsPerMillisecond + 1) / + kMicrosecondsPerMillisecond; + seconds = (milliseconds - kMillisecondsPerSecond + 1) / + kMillisecondsPerSecond; + // Make this nonnegative (and between 0 and 999 inclusive). + millisecond = milliseconds % kMillisecondsPerSecond; + if (millisecond < 0) + millisecond += kMillisecondsPerSecond; + } + + struct tm timestruct; + SysTimeToTimeStruct(seconds, ×truct, is_local); + + exploded->year = timestruct.tm_year + 1900; + exploded->month = timestruct.tm_mon + 1; + exploded->day_of_week = timestruct.tm_wday; + exploded->day_of_month = timestruct.tm_mday; + exploded->hour = timestruct.tm_hour; + exploded->minute = timestruct.tm_min; + exploded->second = timestruct.tm_sec; + exploded->millisecond = millisecond; +} + +// static +Time Time::FromExploded(bool is_local, const Exploded& exploded) { + struct tm timestruct; + timestruct.tm_sec = exploded.second; + timestruct.tm_min = exploded.minute; + timestruct.tm_hour = exploded.hour; + timestruct.tm_mday = exploded.day_of_month; + timestruct.tm_mon = exploded.month - 1; + timestruct.tm_year = exploded.year - 1900; + timestruct.tm_wday = exploded.day_of_week; // mktime/timegm ignore this + timestruct.tm_yday = 0; // mktime/timegm ignore this + timestruct.tm_isdst = -1; // attempt to figure it out +#if !defined(OS_NACL) && !defined(OS_SOLARIS) + timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore + timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore +#endif + + + int64 milliseconds; + SysTime seconds; + + // Certain exploded dates do not really exist due to daylight saving times, + // and this causes mktime() to return implementation-defined values when + // tm_isdst is set to -1. On Android, the function will return -1, while the + // C libraries of other platforms typically return a liberally-chosen value. + // Handling this requires the special code below. + + // SysTimeFromTimeStruct() modifies the input structure, save current value. + struct tm timestruct0 = timestruct; + + seconds = SysTimeFromTimeStruct(×truct, is_local); + if (seconds == -1) { + // Get the time values with tm_isdst == 0 and 1, then select the closest one + // to UTC 00:00:00 that isn't -1. + timestruct = timestruct0; + timestruct.tm_isdst = 0; + int64 seconds_isdst0 = SysTimeFromTimeStruct(×truct, is_local); + + timestruct = timestruct0; + timestruct.tm_isdst = 1; + int64 seconds_isdst1 = SysTimeFromTimeStruct(×truct, is_local); + + // seconds_isdst0 or seconds_isdst1 can be -1 for some timezones. + // E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'. + if (seconds_isdst0 < 0) + seconds = seconds_isdst1; + else if (seconds_isdst1 < 0) + seconds = seconds_isdst0; + else + seconds = std::min(seconds_isdst0, seconds_isdst1); + } + + // Handle overflow. Clamping the range to what mktime and timegm might + // return is the best that can be done here. It's not ideal, but it's better + // than failing here or ignoring the overflow case and treating each time + // overflow as one second prior to the epoch. + if (seconds == -1 && + (exploded.year < 1969 || exploded.year > 1970)) { + // If exploded.year is 1969 or 1970, take -1 as correct, with the + // time indicating 1 second prior to the epoch. (1970 is allowed to handle + // time zone and DST offsets.) Otherwise, return the most future or past + // time representable. Assumes the time_t epoch is 1970-01-01 00:00:00 UTC. + // + // The minimum and maximum representible times that mktime and timegm could + // return are used here instead of values outside that range to allow for + // proper round-tripping between exploded and counter-type time + // representations in the presence of possible truncation to time_t by + // division and use with other functions that accept time_t. + // + // When representing the most distant time in the future, add in an extra + // 999ms to avoid the time being less than any other possible value that + // this function can return. + + // On Android, SysTime is int64, special care must be taken to avoid + // overflows. + const int64 min_seconds = (sizeof(SysTime) < sizeof(int64)) + ? std::numeric_limits<SysTime>::min() + : std::numeric_limits<int32_t>::min(); + const int64 max_seconds = (sizeof(SysTime) < sizeof(int64)) + ? std::numeric_limits<SysTime>::max() + : std::numeric_limits<int32_t>::max(); + if (exploded.year < 1969) { + milliseconds = min_seconds * kMillisecondsPerSecond; + } else { + milliseconds = max_seconds * kMillisecondsPerSecond; + milliseconds += (kMillisecondsPerSecond - 1); + } + } else { + milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond; + } + + // Adjust from Unix (1970) to Windows (1601) epoch. + return Time((milliseconds * kMicrosecondsPerMillisecond) + + kWindowsEpochDeltaMicroseconds); +} + +// TimeTicks ------------------------------------------------------------------ +// static +TimeTicks TimeTicks::Now() { + return TimeTicks(ClockNow(CLOCK_MONOTONIC)); +} + +// static +bool TimeTicks::IsHighResolution() { + return true; +} + +// static +ThreadTicks ThreadTicks::Now() { +#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ + defined(OS_ANDROID) + return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID)); +#else + NOTREACHED(); + return ThreadTicks(); +#endif +} + +// Use the Chrome OS specific system-wide clock. +#if defined(OS_CHROMEOS) +// static +TraceTicks TraceTicks::Now() { + struct timespec ts; + if (clock_gettime(kClockSystemTrace, &ts) != 0) { + // NB: fall-back for a chrome os build running on linux + return TraceTicks(ClockNow(CLOCK_MONOTONIC)); + } + return TraceTicks(ConvertTimespecToMicros(ts)); +} + +#else // !defined(OS_CHROMEOS) + +// static +TraceTicks TraceTicks::Now() { + return TraceTicks(ClockNow(CLOCK_MONOTONIC)); +} + +#endif // defined(OS_CHROMEOS) + +#endif // !OS_MACOSX + +// static +Time Time::FromTimeVal(struct timeval t) { + DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond)); + DCHECK_GE(t.tv_usec, 0); + if (t.tv_usec == 0 && t.tv_sec == 0) + return Time(); + if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 && + t.tv_sec == std::numeric_limits<time_t>::max()) + return Max(); + return Time( + (static_cast<int64>(t.tv_sec) * Time::kMicrosecondsPerSecond) + + t.tv_usec + + kTimeTToMicrosecondsOffset); +} + +struct timeval Time::ToTimeVal() const { + struct timeval result; + if (is_null()) { + result.tv_sec = 0; + result.tv_usec = 0; + return result; + } + if (is_max()) { + result.tv_sec = std::numeric_limits<time_t>::max(); + result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1; + return result; + } + int64 us = us_ - kTimeTToMicrosecondsOffset; + result.tv_sec = us / Time::kMicrosecondsPerSecond; + result.tv_usec = us % Time::kMicrosecondsPerSecond; + return result; +} + +} // namespace base diff --git a/third_party/chromium/base/time/time_unittest.cc b/third_party/chromium/base/time/time_unittest.cc new file mode 100644 index 0000000..43373e7 --- /dev/null +++ b/third_party/chromium/base/time/time_unittest.cc @@ -0,0 +1,848 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/time/time.h" + +#include <stdint.h> +#include <time.h> +#include <limits> +#include <string> + +#include <gtest/gtest.h> + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "base/build/build_config.h" + +namespace base { + +namespace { + +// Specialized test fixture allowing time strings without timezones to be +// tested by comparing them to a known time in the local zone. +// See also pr_time_unittests.cc +class TimeTest : public testing::Test { + protected: + void SetUp() override { + // Use mktime to get a time_t, and turn it into a PRTime by converting + // seconds to microseconds. Use 15th Oct 2007 12:45:00 local. This + // must be a time guaranteed to be outside of a DST fallback hour in + // any timezone. + struct tm local_comparison_tm = { + 0, // second + 45, // minute + 12, // hour + 15, // day of month + 10 - 1, // month + 2007 - 1900, // year + 0, // day of week (ignored, output only) + 0, // day of year (ignored, output only) + -1 // DST in effect, -1 tells mktime to figure it out + }; + + time_t converted_time = mktime(&local_comparison_tm); + ASSERT_GT(converted_time, 0); + comparison_time_local_ = Time::FromTimeT(converted_time); + + // time_t representation of 15th Oct 2007 12:45:00 PDT + comparison_time_pdt_ = Time::FromTimeT(1192477500); + } + + Time comparison_time_local_; + Time comparison_time_pdt_; +}; + +// Test conversions to/from time_t and exploding/unexploding. +TEST_F(TimeTest, TimeT) { + // C library time and exploded time. + time_t now_t_1 = time(NULL); + struct tm tms; +#if defined(OS_WIN) + localtime_s(&tms, &now_t_1); +#elif defined(OS_POSIX) + localtime_r(&now_t_1, &tms); +#endif + + // Convert to ours. + Time our_time_1 = Time::FromTimeT(now_t_1); + Time::Exploded exploded; + our_time_1.LocalExplode(&exploded); + + // This will test both our exploding and our time_t -> Time conversion. + EXPECT_EQ(tms.tm_year + 1900, exploded.year); + EXPECT_EQ(tms.tm_mon + 1, exploded.month); + EXPECT_EQ(tms.tm_mday, exploded.day_of_month); + EXPECT_EQ(tms.tm_hour, exploded.hour); + EXPECT_EQ(tms.tm_min, exploded.minute); + EXPECT_EQ(tms.tm_sec, exploded.second); + + // Convert exploded back to the time struct. + Time our_time_2 = Time::FromLocalExploded(exploded); + EXPECT_TRUE(our_time_1 == our_time_2); + + time_t now_t_2 = our_time_2.ToTimeT(); + EXPECT_EQ(now_t_1, now_t_2); + + EXPECT_EQ(10, Time().FromTimeT(10).ToTimeT()); + EXPECT_EQ(10.0, Time().FromTimeT(10).ToDoubleT()); + + // Conversions of 0 should stay 0. + EXPECT_EQ(0, Time().ToTimeT()); + EXPECT_EQ(0, Time::FromTimeT(0).ToInternalValue()); +} + +// Test conversions to/from javascript time. +TEST_F(TimeTest, JsTime) { + Time epoch = Time::FromJsTime(0.0); + EXPECT_EQ(epoch, Time::UnixEpoch()); + Time t = Time::FromJsTime(700000.3); + EXPECT_EQ(700.0003, t.ToDoubleT()); + t = Time::FromDoubleT(800.73); + EXPECT_EQ(800730.0, t.ToJsTime()); +} + +#if defined(OS_POSIX) +TEST_F(TimeTest, FromTimeVal) { + Time now = Time::Now(); + Time also_now = Time::FromTimeVal(now.ToTimeVal()); + EXPECT_EQ(now, also_now); +} +#endif // OS_POSIX + +TEST_F(TimeTest, FromExplodedWithMilliseconds) { + // Some platform implementations of FromExploded are liable to drop + // milliseconds if we aren't careful. + Time now = Time::NowFromSystemTime(); + Time::Exploded exploded1 = {0}; + now.UTCExplode(&exploded1); + exploded1.millisecond = 500; + Time time = Time::FromUTCExploded(exploded1); + Time::Exploded exploded2 = {0}; + time.UTCExplode(&exploded2); + EXPECT_EQ(exploded1.millisecond, exploded2.millisecond); +} + +TEST_F(TimeTest, ZeroIsSymmetric) { + Time zero_time(Time::FromTimeT(0)); + EXPECT_EQ(0, zero_time.ToTimeT()); + + EXPECT_EQ(0.0, zero_time.ToDoubleT()); +} + +TEST_F(TimeTest, LocalExplode) { + Time a = Time::Now(); + Time::Exploded exploded; + a.LocalExplode(&exploded); + + Time b = Time::FromLocalExploded(exploded); + + // The exploded structure doesn't have microseconds, and on Mac & Linux, the + // internal OS conversion uses seconds, which will cause truncation. So we + // can only make sure that the delta is within one second. + EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1)); +} + +TEST_F(TimeTest, UTCExplode) { + Time a = Time::Now(); + Time::Exploded exploded; + a.UTCExplode(&exploded); + + Time b = Time::FromUTCExploded(exploded); + EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1)); +} + +TEST_F(TimeTest, LocalMidnight) { + Time::Exploded exploded; + Time::Now().LocalMidnight().LocalExplode(&exploded); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(0, exploded.second); + EXPECT_EQ(0, exploded.millisecond); +} + +TEST_F(TimeTest, ExplodeBeforeUnixEpoch) { + static const int kUnixEpochYear = 1970; // In case this changes (ha!). + Time t; + Time::Exploded exploded; + + t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:59 999 milliseconds (and 999 microseconds). + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(59, exploded.second); + EXPECT_EQ(999, exploded.millisecond); + + t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1000); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:59 999 milliseconds. + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(59, exploded.second); + EXPECT_EQ(999, exploded.millisecond); + + t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1001); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:59 998 milliseconds (and 999 microseconds). + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(59, exploded.second); + EXPECT_EQ(998, exploded.millisecond); + + t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1000); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:59. + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(59, exploded.second); + EXPECT_EQ(0, exploded.millisecond); + + t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1001); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1969-12-31 23:59:58 999 milliseconds. + EXPECT_EQ(kUnixEpochYear - 1, exploded.year); + EXPECT_EQ(12, exploded.month); + EXPECT_EQ(31, exploded.day_of_month); + EXPECT_EQ(23, exploded.hour); + EXPECT_EQ(59, exploded.minute); + EXPECT_EQ(58, exploded.second); + EXPECT_EQ(999, exploded.millisecond); + + // Make sure we still handle at/after Unix epoch correctly. + t = Time::UnixEpoch(); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-12-31 00:00:00 0 milliseconds. + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(0, exploded.second); + EXPECT_EQ(0, exploded.millisecond); + + t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-01-01 00:00:00 0 milliseconds (and 1 microsecond). + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(0, exploded.second); + EXPECT_EQ(0, exploded.millisecond); + + t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1000); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-01-01 00:00:00 1 millisecond. + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(0, exploded.second); + EXPECT_EQ(1, exploded.millisecond); + + t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1000); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-01-01 00:00:01. + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(1, exploded.second); + EXPECT_EQ(0, exploded.millisecond); + + t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1001); + t.UTCExplode(&exploded); + EXPECT_TRUE(exploded.HasValidValues()); + // Should be 1970-01-01 00:00:01 1 millisecond. + EXPECT_EQ(kUnixEpochYear, exploded.year); + EXPECT_EQ(1, exploded.month); + EXPECT_EQ(1, exploded.day_of_month); + EXPECT_EQ(0, exploded.hour); + EXPECT_EQ(0, exploded.minute); + EXPECT_EQ(1, exploded.second); + EXPECT_EQ(1, exploded.millisecond); +} + +TEST_F(TimeTest, TimeDeltaMax) { + TimeDelta max = TimeDelta::Max(); + EXPECT_TRUE(max.is_max()); + EXPECT_EQ(max, TimeDelta::Max()); + EXPECT_GT(max, TimeDelta::FromDays(100 * 365)); + EXPECT_GT(max, TimeDelta()); +} + +TEST_F(TimeTest, TimeDeltaMaxConversions) { + TimeDelta t = TimeDelta::Max(); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue()); + + EXPECT_EQ(std::numeric_limits<int>::max(), t.InDays()); + EXPECT_EQ(std::numeric_limits<int>::max(), t.InHours()); + EXPECT_EQ(std::numeric_limits<int>::max(), t.InMinutes()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InSecondsF()); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.InSeconds()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InMillisecondsF()); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMilliseconds()); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMillisecondsRoundedUp()); + + t = TimeDelta::FromDays(std::numeric_limits<int>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromHours(std::numeric_limits<int>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromMinutes(std::numeric_limits<int>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromSeconds(std::numeric_limits<int64>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromMilliseconds(std::numeric_limits<int64>::max()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromMillisecondsD(std::numeric_limits<double>::infinity()); + EXPECT_TRUE(t.is_max()); + + t = TimeDelta::FromMicroseconds(std::numeric_limits<int64>::max()); + EXPECT_TRUE(t.is_max()); +} + +TEST_F(TimeTest, Max) { + Time max = Time::Max(); + EXPECT_TRUE(max.is_max()); + EXPECT_EQ(max, Time::Max()); + EXPECT_GT(max, Time::Now()); + EXPECT_GT(max, Time()); +} + +TEST_F(TimeTest, MaxConversions) { + Time t = Time::Max(); + EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue()); + + t = Time::FromDoubleT(std::numeric_limits<double>::infinity()); + EXPECT_TRUE(t.is_max()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToDoubleT()); + + t = Time::FromJsTime(std::numeric_limits<double>::infinity()); + EXPECT_TRUE(t.is_max()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToJsTime()); + + t = Time::FromTimeT(std::numeric_limits<time_t>::max()); + EXPECT_TRUE(t.is_max()); + EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT()); + +#if defined(OS_POSIX) + struct timeval tval; + tval.tv_sec = std::numeric_limits<time_t>::max(); + tval.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1; + t = Time::FromTimeVal(tval); + EXPECT_TRUE(t.is_max()); + tval = t.ToTimeVal(); + EXPECT_EQ(std::numeric_limits<time_t>::max(), tval.tv_sec); + EXPECT_EQ(static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1, + tval.tv_usec); +#endif + +#if defined(OS_MACOSX) + t = Time::FromCFAbsoluteTime(std::numeric_limits<CFAbsoluteTime>::infinity()); + EXPECT_TRUE(t.is_max()); + EXPECT_EQ(std::numeric_limits<CFAbsoluteTime>::infinity(), + t.ToCFAbsoluteTime()); +#endif + +#if defined(OS_WIN) + FILETIME ftime; + ftime.dwHighDateTime = std::numeric_limits<DWORD>::max(); + ftime.dwLowDateTime = std::numeric_limits<DWORD>::max(); + t = Time::FromFileTime(ftime); + EXPECT_TRUE(t.is_max()); + ftime = t.ToFileTime(); + EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwHighDateTime); + EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwLowDateTime); +#endif +} + +#if defined(OS_MACOSX) +TEST_F(TimeTest, TimeTOverflow) { + Time t = Time::FromInternalValue(std::numeric_limits<int64>::max() - 1); + EXPECT_FALSE(t.is_max()); + EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT()); +} +#endif + +#if defined(OS_ANDROID) +TEST_F(TimeTest, FromLocalExplodedCrashOnAndroid) { + // This crashed inside Time:: FromLocalExploded() on Android 4.1.2. + // See http://crbug.com/287821 + Time::Exploded midnight = {2013, // year + 10, // month + 0, // day_of_week + 13, // day_of_month + 0, // hour + 0, // minute + 0, // second + }; + // The string passed to putenv() must be a char* and the documentation states + // that it 'becomes part of the environment', so use a static buffer. + static char buffer[] = "TZ=America/Santiago"; + putenv(buffer); + tzset(); + Time t = Time::FromLocalExploded(midnight); + EXPECT_EQ(1381633200, t.ToTimeT()); +} +#endif // OS_ANDROID + +static void HighResClockTest(TimeTicks (*GetTicks)()) { + // IsHighResolution() is false on some systems. Since the product still works + // even if it's false, it makes this entire test questionable. + if (!TimeTicks::IsHighResolution()) + return; + + // Why do we loop here? + // We're trying to measure that intervals increment in a VERY small amount + // of time -- less than 15ms. Unfortunately, if we happen to have a + // context switch in the middle of our test, the context switch could easily + // exceed our limit. So, we iterate on this several times. As long as we're + // able to detect the fine-granularity timers at least once, then the test + // has succeeded. + + const int kTargetGranularityUs = 15000; // 15ms + + bool success = false; + int retries = 100; // Arbitrary. + TimeDelta delta; + while (!success && retries--) { + TimeTicks ticks_start = GetTicks(); + // Loop until we can detect that the clock has changed. Non-HighRes timers + // will increment in chunks, e.g. 15ms. By spinning until we see a clock + // change, we detect the minimum time between measurements. + do { + delta = GetTicks() - ticks_start; + } while (delta.InMilliseconds() == 0); + + if (delta.InMicroseconds() <= kTargetGranularityUs) + success = true; + } + + // In high resolution mode, we expect to see the clock increment + // in intervals less than 15ms. + EXPECT_TRUE(success); +} + +TEST(TimeTicks, HighRes) { + HighResClockTest(&TimeTicks::Now); +} + +TEST(TraceTicks, NowFromSystemTraceTime) { + // Re-use HighRes test for now since clock properties are identical. + using NowFunction = TimeTicks (*)(void); + HighResClockTest(reinterpret_cast<NowFunction>(&TraceTicks::Now)); +} + +TEST(TimeTicks, SnappedToNextTickBasic) { + base::TimeTicks phase = base::TimeTicks::FromInternalValue(4000); + base::TimeDelta interval = base::TimeDelta::FromMicroseconds(1000); + base::TimeTicks timestamp; + + // Timestamp in previous interval. + timestamp = base::TimeTicks::FromInternalValue(3500); + EXPECT_EQ(4000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp in next interval. + timestamp = base::TimeTicks::FromInternalValue(4500); + EXPECT_EQ(5000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp multiple intervals before. + timestamp = base::TimeTicks::FromInternalValue(2500); + EXPECT_EQ(3000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp multiple intervals after. + timestamp = base::TimeTicks::FromInternalValue(6500); + EXPECT_EQ(7000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp on previous interval. + timestamp = base::TimeTicks::FromInternalValue(3000); + EXPECT_EQ(3000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp on next interval. + timestamp = base::TimeTicks::FromInternalValue(5000); + EXPECT_EQ(5000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + + // Timestamp equal to phase. + timestamp = base::TimeTicks::FromInternalValue(4000); + EXPECT_EQ(4000, + timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); +} + +TEST(TimeTicks, SnappedToNextTickOverflow) { + // int(big_timestamp / interval) < 0, so this causes a crash if the number of + // intervals elapsed is attempted to be stored in an int. + base::TimeTicks phase = base::TimeTicks::FromInternalValue(0); + base::TimeDelta interval = base::TimeDelta::FromMicroseconds(4000); + base::TimeTicks big_timestamp = + base::TimeTicks::FromInternalValue(8635916564000); + + EXPECT_EQ(8635916564000, + big_timestamp.SnappedToNextTick(phase, interval).ToInternalValue()); + EXPECT_EQ(8635916564000, + big_timestamp.SnappedToNextTick(big_timestamp, interval) + .ToInternalValue()); +} + +TEST(TimeDelta, FromAndIn) { + EXPECT_TRUE(TimeDelta::FromDays(2) == TimeDelta::FromHours(48)); + EXPECT_TRUE(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180)); + EXPECT_TRUE(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120)); + EXPECT_TRUE(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000)); + EXPECT_TRUE(TimeDelta::FromMilliseconds(2) == + TimeDelta::FromMicroseconds(2000)); + EXPECT_TRUE(TimeDelta::FromSecondsD(2.3) == + TimeDelta::FromMilliseconds(2300)); + EXPECT_TRUE(TimeDelta::FromMillisecondsD(2.5) == + TimeDelta::FromMicroseconds(2500)); + EXPECT_EQ(13, TimeDelta::FromDays(13).InDays()); + EXPECT_EQ(13, TimeDelta::FromHours(13).InHours()); + EXPECT_EQ(13, TimeDelta::FromMinutes(13).InMinutes()); + EXPECT_EQ(13, TimeDelta::FromSeconds(13).InSeconds()); + EXPECT_EQ(13.0, TimeDelta::FromSeconds(13).InSecondsF()); + EXPECT_EQ(13, TimeDelta::FromMilliseconds(13).InMilliseconds()); + EXPECT_EQ(13.0, TimeDelta::FromMilliseconds(13).InMillisecondsF()); + EXPECT_EQ(13, TimeDelta::FromSecondsD(13.1).InSeconds()); + EXPECT_EQ(13.1, TimeDelta::FromSecondsD(13.1).InSecondsF()); + EXPECT_EQ(13, TimeDelta::FromMillisecondsD(13.3).InMilliseconds()); + EXPECT_EQ(13.3, TimeDelta::FromMillisecondsD(13.3).InMillisecondsF()); + EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).InMicroseconds()); +} + +#if defined(OS_POSIX) +TEST(TimeDelta, TimeSpecConversion) { + struct timespec result = TimeDelta::FromSeconds(0).ToTimeSpec(); + EXPECT_EQ(result.tv_sec, 0); + EXPECT_EQ(result.tv_nsec, 0); + + result = TimeDelta::FromSeconds(1).ToTimeSpec(); + EXPECT_EQ(result.tv_sec, 1); + EXPECT_EQ(result.tv_nsec, 0); + + result = TimeDelta::FromMicroseconds(1).ToTimeSpec(); + EXPECT_EQ(result.tv_sec, 0); + EXPECT_EQ(result.tv_nsec, 1000); + + result = TimeDelta::FromMicroseconds( + Time::kMicrosecondsPerSecond + 1).ToTimeSpec(); + EXPECT_EQ(result.tv_sec, 1); + EXPECT_EQ(result.tv_nsec, 1000); +} +#endif // OS_POSIX + +// Our internal time format is serialized in things like databases, so it's +// important that it's consistent across all our platforms. We use the 1601 +// Windows epoch as the internal format across all platforms. +TEST(TimeDelta, WindowsEpoch) { + Time::Exploded exploded; + exploded.year = 1970; + exploded.month = 1; + exploded.day_of_week = 0; // Should be unusued. + exploded.day_of_month = 1; + exploded.hour = 0; + exploded.minute = 0; + exploded.second = 0; + exploded.millisecond = 0; + Time t = Time::FromUTCExploded(exploded); + // Unix 1970 epoch. + EXPECT_EQ(INT64_C(11644473600000000), t.ToInternalValue()); + + // We can't test 1601 epoch, since the system time functions on Linux + // only compute years starting from 1900. +} + +// We could define this separately for Time, TimeTicks and TimeDelta but the +// definitions would be identical anyway. +template <class Any> +std::string AnyToString(Any any) { + std::ostringstream oss; + oss << any; + return oss.str(); +} + +TEST(TimeDelta, Magnitude) { + const int64 zero = 0; + EXPECT_EQ(TimeDelta::FromMicroseconds(zero), + TimeDelta::FromMicroseconds(zero).magnitude()); + + const int64 one = 1; + const int64 negative_one = -1; + EXPECT_EQ(TimeDelta::FromMicroseconds(one), + TimeDelta::FromMicroseconds(one).magnitude()); + EXPECT_EQ(TimeDelta::FromMicroseconds(one), + TimeDelta::FromMicroseconds(negative_one).magnitude()); + + const int64 max_int64_minus_one = std::numeric_limits<int64>::max() - 1; + const int64 min_int64_plus_two = std::numeric_limits<int64>::min() + 2; + EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one), + TimeDelta::FromMicroseconds(max_int64_minus_one).magnitude()); + EXPECT_EQ(TimeDelta::FromMicroseconds(max_int64_minus_one), + TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude()); +} + + +TEST(TimeDelta, NumericOperators) { + double d = 0.5; + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) * d); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) / d); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) *= d); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) /= d); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + d * TimeDelta::FromMilliseconds(1000)); + + float f = 0.5; + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) * f); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) / f); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) *= f); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) /= f); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + f * TimeDelta::FromMilliseconds(1000)); + + + int i = 2; + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) * i); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) / i); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) *= i); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) /= i); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + i * TimeDelta::FromMilliseconds(1000)); + + int64_t i64 = 2; + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) * i64); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) / i64); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) *= i64); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) /= i64); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + i64 * TimeDelta::FromMilliseconds(1000)); + + + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) * 0.5); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) / 0.5); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) *= 0.5); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) /= 0.5); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + 0.5 * TimeDelta::FromMilliseconds(1000)); + + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) * 2); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) / 2); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + TimeDelta::FromMilliseconds(1000) *= 2); + EXPECT_EQ(TimeDelta::FromMilliseconds(500), + TimeDelta::FromMilliseconds(1000) /= 2); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), + 2 * TimeDelta::FromMilliseconds(1000)); +} + +bool IsMin(TimeDelta delta) { + return (-delta).is_max(); +} + +TEST(TimeDelta, Overflows) { + // Some sanity checks. + EXPECT_TRUE(TimeDelta::Max().is_max()); + EXPECT_TRUE(IsMin(-TimeDelta::Max())); + EXPECT_GT(TimeDelta(), -TimeDelta::Max()); + + TimeDelta large_delta = TimeDelta::Max() - TimeDelta::FromMilliseconds(1); + TimeDelta large_negative = -large_delta; + EXPECT_GT(TimeDelta(), large_negative); + EXPECT_FALSE(large_delta.is_max()); + EXPECT_FALSE(IsMin(-large_negative)); + TimeDelta one_second = TimeDelta::FromSeconds(1); + + // Test +, -, * and / operators. + EXPECT_TRUE((large_delta + one_second).is_max()); + EXPECT_TRUE(IsMin(large_negative + (-one_second))); + EXPECT_TRUE(IsMin(large_negative - one_second)); + EXPECT_TRUE((large_delta - (-one_second)).is_max()); + EXPECT_TRUE((large_delta * 2).is_max()); + EXPECT_TRUE(IsMin(large_delta * -2)); + EXPECT_TRUE((large_delta / 0.5).is_max()); + EXPECT_TRUE(IsMin(large_delta / -0.5)); + + // Test +=, -=, *= and /= operators. + TimeDelta delta = large_delta; + delta += one_second; + EXPECT_TRUE(delta.is_max()); + delta = large_negative; + delta += -one_second; + EXPECT_TRUE(IsMin(delta)); + + delta = large_negative; + delta -= one_second; + EXPECT_TRUE(IsMin(delta)); + delta = large_delta; + delta -= -one_second; + EXPECT_TRUE(delta.is_max()); + + delta = large_delta; + delta *= 2; + EXPECT_TRUE(delta.is_max()); + delta = large_negative; + delta *= 1.5; + EXPECT_TRUE(IsMin(delta)); + + delta = large_delta; + delta /= 0.5; + EXPECT_TRUE(delta.is_max()); + delta = large_negative; + delta /= 0.5; + EXPECT_TRUE(IsMin(delta)); + + // Test operations with Time and TimeTicks. + EXPECT_TRUE((large_delta + Time::Now()).is_max()); + EXPECT_TRUE((large_delta + TimeTicks::Now()).is_max()); + EXPECT_TRUE((Time::Now() + large_delta).is_max()); + EXPECT_TRUE((TimeTicks::Now() + large_delta).is_max()); + + Time time_now = Time::Now(); + EXPECT_EQ(one_second, (time_now + one_second) - time_now); + EXPECT_EQ(-one_second, (time_now - one_second) - time_now); + + TimeTicks ticks_now = TimeTicks::Now(); + EXPECT_EQ(-one_second, (ticks_now - one_second) - ticks_now); + EXPECT_EQ(one_second, (ticks_now + one_second) - ticks_now); +} + +TEST(TimeDeltaLogging, DCheckEqCompiles) { + DCHECK_EQ(TimeDelta(), TimeDelta()); +} + +TEST(TimeDeltaLogging, EmptyIsZero) { + TimeDelta zero; + EXPECT_EQ("0s", AnyToString(zero)); +} + +TEST(TimeDeltaLogging, FiveHundredMs) { + TimeDelta five_hundred_ms = TimeDelta::FromMilliseconds(500); + EXPECT_EQ("0.5s", AnyToString(five_hundred_ms)); +} + +TEST(TimeDeltaLogging, MinusTenSeconds) { + TimeDelta minus_ten_seconds = TimeDelta::FromSeconds(-10); + EXPECT_EQ("-10s", AnyToString(minus_ten_seconds)); +} + +TEST(TimeDeltaLogging, DoesNotMessUpFormattingFlags) { + std::ostringstream oss; + std::ios_base::fmtflags flags_before = oss.flags(); + oss << TimeDelta(); + EXPECT_EQ(flags_before, oss.flags()); +} + +TEST(TimeDeltaLogging, DoesNotMakeStreamBad) { + std::ostringstream oss; + oss << TimeDelta(); + EXPECT_TRUE(oss.good()); +} + +TEST(TimeLogging, DCheckEqCompiles) { + DCHECK_EQ(Time(), Time()); +} + +TEST(TimeLogging, DoesNotMessUpFormattingFlags) { + std::ostringstream oss; + std::ios_base::fmtflags flags_before = oss.flags(); + oss << Time(); + EXPECT_EQ(flags_before, oss.flags()); +} + +TEST(TimeLogging, DoesNotMakeStreamBad) { + std::ostringstream oss; + oss << Time(); + EXPECT_TRUE(oss.good()); +} + +TEST(TimeTicksLogging, DCheckEqCompiles) { + DCHECK_EQ(TimeTicks(), TimeTicks()); +} + +TEST(TimeTicksLogging, ZeroTime) { + TimeTicks zero; + EXPECT_EQ("0 bogo-microseconds", AnyToString(zero)); +} + +TEST(TimeTicksLogging, FortyYearsLater) { + TimeTicks forty_years_later = + TimeTicks() + TimeDelta::FromDays(365.25 * 40); + EXPECT_EQ("1262304000000000 bogo-microseconds", + AnyToString(forty_years_later)); +} + +TEST(TimeTicksLogging, DoesNotMessUpFormattingFlags) { + std::ostringstream oss; + std::ios_base::fmtflags flags_before = oss.flags(); + oss << TimeTicks(); + EXPECT_EQ(flags_before, oss.flags()); +} + +TEST(TimeTicksLogging, DoesNotMakeStreamBad) { + std::ostringstream oss; + oss << TimeTicks(); + EXPECT_TRUE(oss.good()); +} + +} // namespace + +} // namespace base diff --git a/third_party/chromium/base/tuple.h b/third_party/chromium/base/tuple.h new file mode 100644 index 0000000..ef51d85 --- /dev/null +++ b/third_party/chromium/base/tuple.h @@ -0,0 +1,336 @@ +// 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. + +// A Tuple is a generic templatized container, similar in concept to std::pair +// and std::tuple. The convenient MakeTuple() function takes any number of +// arguments and will construct and return the appropriate Tuple object. The +// functions DispatchToMethod and DispatchToFunction take a function pointer or +// instance and method pointer, and unpack a tuple into arguments to the call. +// +// Tuple elements are copied by value, and stored in the tuple. See the unit +// tests for more details of how/when the values are copied. +// +// Example usage: +// // These two methods of creating a Tuple are identical. +// Tuple<int, const char*> tuple_a(1, "wee"); +// Tuple<int, const char*> tuple_b = MakeTuple(1, "wee"); +// +// void SomeFunc(int a, const char* b) { } +// DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee") +// DispatchToFunction( +// &SomeFunc, MakeTuple(10, "foo")); // SomeFunc(10, "foo") +// +// struct { void SomeMeth(int a, int b, int c) { } } foo; +// DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3)); +// // foo->SomeMeth(1, 2, 3); + +#ifndef BASE_TUPLE_H_ +#define BASE_TUPLE_H_ + +#include "base/bind_helpers.h" + +namespace base { + +// Index sequences +// +// Minimal clone of the similarly-named C++14 functionality. + +template <size_t...> +struct IndexSequence {}; + +template <size_t... Ns> +struct MakeIndexSequenceImpl; + +#if defined(_PREFAST_) && defined(OS_WIN) + +// Work around VC++ 2013 /analyze internal compiler error: +// https://connect.microsoft.com/VisualStudio/feedback/details/1053626 + +template <> struct MakeIndexSequenceImpl<0> { + using Type = IndexSequence<>; +}; +template <> struct MakeIndexSequenceImpl<1> { + using Type = IndexSequence<0>; +}; +template <> struct MakeIndexSequenceImpl<2> { + using Type = IndexSequence<0,1>; +}; +template <> struct MakeIndexSequenceImpl<3> { + using Type = IndexSequence<0,1,2>; +}; +template <> struct MakeIndexSequenceImpl<4> { + using Type = IndexSequence<0,1,2,3>; +}; +template <> struct MakeIndexSequenceImpl<5> { + using Type = IndexSequence<0,1,2,3,4>; +}; +template <> struct MakeIndexSequenceImpl<6> { + using Type = IndexSequence<0,1,2,3,4,5>; +}; +template <> struct MakeIndexSequenceImpl<7> { + using Type = IndexSequence<0,1,2,3,4,5,6>; +}; +template <> struct MakeIndexSequenceImpl<8> { + using Type = IndexSequence<0,1,2,3,4,5,6,7>; +}; +template <> struct MakeIndexSequenceImpl<9> { + using Type = IndexSequence<0,1,2,3,4,5,6,7,8>; +}; +template <> struct MakeIndexSequenceImpl<10> { + using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9>; +}; +template <> struct MakeIndexSequenceImpl<11> { + using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10>; +}; +template <> struct MakeIndexSequenceImpl<12> { + using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11>; +}; +template <> struct MakeIndexSequenceImpl<13> { + using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11,12>; +}; + +#else // defined(WIN) && defined(_PREFAST_) + +template <size_t... Ns> +struct MakeIndexSequenceImpl<0, Ns...> { + using Type = IndexSequence<Ns...>; +}; + +template <size_t N, size_t... Ns> +struct MakeIndexSequenceImpl<N, Ns...> + : MakeIndexSequenceImpl<N - 1, N - 1, Ns...> {}; + +#endif // defined(WIN) && defined(_PREFAST_) + +template <size_t N> +using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type; + +// Traits ---------------------------------------------------------------------- +// +// A simple traits class for tuple arguments. +// +// ValueType: the bare, nonref version of a type (same as the type for nonrefs). +// RefType: the ref version of a type (same as the type for refs). +// ParamType: what type to pass to functions (refs should not be constified). + +template <class P> +struct TupleTraits { + typedef P ValueType; + typedef P& RefType; + typedef const P& ParamType; +}; + +template <class P> +struct TupleTraits<P&> { + typedef P ValueType; + typedef P& RefType; + typedef P& ParamType; +}; + +// Tuple ----------------------------------------------------------------------- +// +// This set of classes is useful for bundling 0 or more heterogeneous data types +// into a single variable. The advantage of this is that it greatly simplifies +// function objects that need to take an arbitrary number of parameters; see +// RunnableMethod and IPC::MessageWithTuple. +// +// Tuple<> is supplied to act as a 'void' type. It can be used, for example, +// when dispatching to a function that accepts no arguments (see the +// Dispatchers below). +// Tuple<A> is rarely useful. One such use is when A is non-const ref that you +// want filled by the dispatchee, and the tuple is merely a container for that +// output (a "tier"). See MakeRefTuple and its usages. + +template <typename IxSeq, typename... Ts> +struct TupleBaseImpl; +template <typename... Ts> +using TupleBase = TupleBaseImpl<MakeIndexSequence<sizeof...(Ts)>, Ts...>; +template <size_t N, typename T> +struct TupleLeaf; + +template <typename... Ts> +struct Tuple : TupleBase<Ts...> { + Tuple() : TupleBase<Ts...>() {} + explicit Tuple(typename TupleTraits<Ts>::ParamType... args) + : TupleBase<Ts...>(args...) {} +}; + +// Avoids ambiguity between Tuple's two constructors. +template <> +struct Tuple<> {}; + +template <size_t... Ns, typename... Ts> +struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... { + TupleBaseImpl() : TupleLeaf<Ns, Ts>()... {} + explicit TupleBaseImpl(typename TupleTraits<Ts>::ParamType... args) + : TupleLeaf<Ns, Ts>(args)... {} +}; + +template <size_t N, typename T> +struct TupleLeaf { + TupleLeaf() {} + explicit TupleLeaf(typename TupleTraits<T>::ParamType x) : x(x) {} + + T& get() { return x; } + const T& get() const { return x; } + + T x; +}; + +// Tuple getters -------------------------------------------------------------- +// +// Allows accessing an arbitrary tuple element by index. +// +// Example usage: +// base::Tuple<int, double> t2; +// base::get<0>(t2) = 42; +// base::get<1>(t2) = 3.14; + +template <size_t I, typename T> +T& get(TupleLeaf<I, T>& leaf) { + return leaf.get(); +} + +template <size_t I, typename T> +const T& get(const TupleLeaf<I, T>& leaf) { + return leaf.get(); +} + +// Tuple types ---------------------------------------------------------------- +// +// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the +// definitions of class types the tuple takes as parameters. + +template <typename T> +struct TupleTypes; + +template <typename... Ts> +struct TupleTypes<Tuple<Ts...>> { + using ValueTuple = Tuple<typename TupleTraits<Ts>::ValueType...>; + using RefTuple = Tuple<typename TupleTraits<Ts>::RefType...>; + using ParamTuple = Tuple<typename TupleTraits<Ts>::ParamType...>; +}; + +// Tuple creators ------------------------------------------------------------- +// +// Helper functions for constructing tuples while inferring the template +// argument types. + +template <typename... Ts> +inline Tuple<Ts...> MakeTuple(const Ts&... arg) { + return Tuple<Ts...>(arg...); +} + +// The following set of helpers make what Boost refers to as "Tiers" - a tuple +// of references. + +template <typename... Ts> +inline Tuple<Ts&...> MakeRefTuple(Ts&... arg) { + return Tuple<Ts&...>(arg...); +} + +// Dispatchers ---------------------------------------------------------------- +// +// Helper functions that call the given method on an object, with the unpacked +// tuple arguments. Notice that they all have the same number of arguments, +// so you need only write: +// DispatchToMethod(object, &Object::method, args); +// This is very useful for templated dispatchers, since they don't need to know +// what type |args| is. + +// Non-Static Dispatchers with no out params. + +template <typename ObjT, typename Method, typename A> +inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) { + (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg)); +} + +template <typename ObjT, typename Method, typename... Ts, size_t... Ns> +inline void DispatchToMethodImpl(ObjT* obj, + Method method, + const Tuple<Ts...>& arg, + IndexSequence<Ns...>) { + (obj->*method)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...); +} + +template <typename ObjT, typename Method, typename... Ts> +inline void DispatchToMethod(ObjT* obj, + Method method, + const Tuple<Ts...>& arg) { + DispatchToMethodImpl(obj, method, arg, MakeIndexSequence<sizeof...(Ts)>()); +} + +// Static Dispatchers with no out params. + +template <typename Function, typename A> +inline void DispatchToMethod(Function function, const A& arg) { + (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg)); +} + +template <typename Function, typename... Ts, size_t... Ns> +inline void DispatchToFunctionImpl(Function function, + const Tuple<Ts...>& arg, + IndexSequence<Ns...>) { + (*function)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...); +} + +template <typename Function, typename... Ts> +inline void DispatchToFunction(Function function, const Tuple<Ts...>& arg) { + DispatchToFunctionImpl(function, arg, MakeIndexSequence<sizeof...(Ts)>()); +} + +// Dispatchers with out parameters. + +template <typename ObjT, + typename Method, + typename In, + typename... OutTs, + size_t... OutNs> +inline void DispatchToMethodImpl(ObjT* obj, + Method method, + const In& in, + Tuple<OutTs...>* out, + IndexSequence<OutNs...>) { + (obj->*method)(base::internal::UnwrapTraits<In>::Unwrap(in), + &get<OutNs>(*out)...); +} + +template <typename ObjT, typename Method, typename In, typename... OutTs> +inline void DispatchToMethod(ObjT* obj, + Method method, + const In& in, + Tuple<OutTs...>* out) { + DispatchToMethodImpl(obj, method, in, out, + MakeIndexSequence<sizeof...(OutTs)>()); +} + +template <typename ObjT, + typename Method, + typename... InTs, + typename... OutTs, + size_t... InNs, + size_t... OutNs> +inline void DispatchToMethodImpl(ObjT* obj, + Method method, + const Tuple<InTs...>& in, + Tuple<OutTs...>* out, + IndexSequence<InNs...>, + IndexSequence<OutNs...>) { + (obj->*method)(base::internal::UnwrapTraits<InTs>::Unwrap(get<InNs>(in))..., + &get<OutNs>(*out)...); +} + +template <typename ObjT, typename Method, typename... InTs, typename... OutTs> +inline void DispatchToMethod(ObjT* obj, + Method method, + const Tuple<InTs...>& in, + Tuple<OutTs...>* out) { + DispatchToMethodImpl(obj, method, in, out, + MakeIndexSequence<sizeof...(InTs)>(), + MakeIndexSequence<sizeof...(OutTs)>()); +} + +} // namespace base + +#endif // BASE_TUPLE_H_ diff --git a/third_party/chromium/base/tuple_unittest.cc b/third_party/chromium/base/tuple_unittest.cc new file mode 100644 index 0000000..668c115 --- /dev/null +++ b/third_party/chromium/base/tuple_unittest.cc @@ -0,0 +1,135 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/tuple.h" + +#include <gtest/gtest.h> + +#include "base/compiler_specific.h" + +namespace base { + +namespace { + +void DoAdd(int a, int b, int c, int* res) { + *res = a + b + c; +} + +struct Addy { + Addy() { } + void DoAdd(int a, int b, int c, int d, int* res) { + *res = a + b + c + d; + } +}; + +struct Addz { + Addz() { } + void DoAdd(int a, int b, int c, int d, int e, int* res) { + *res = a + b + c + d + e; + } +}; + +} // namespace + +TEST(TupleTest, Basic) { + base::Tuple<> t0 = base::MakeTuple(); + ALLOW_UNUSED_LOCAL(t0); + base::Tuple<int> t1(1); + base::Tuple<int, const char*> t2 = + base::MakeTuple(1, static_cast<const char*>("wee")); + base::Tuple<int, int, int> t3(1, 2, 3); + base::Tuple<int, int, int, int*> t4(1, 2, 3, &get<0>(t1)); + base::Tuple<int, int, int, int, int*> t5(1, 2, 3, 4, &get<0>(t4)); + base::Tuple<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &get<0>(t4)); + + EXPECT_EQ(1, get<0>(t1)); + EXPECT_EQ(1, get<0>(t2)); + EXPECT_EQ(1, get<0>(t3)); + EXPECT_EQ(2, get<1>(t3)); + EXPECT_EQ(3, get<2>(t3)); + EXPECT_EQ(1, get<0>(t4)); + EXPECT_EQ(2, get<1>(t4)); + EXPECT_EQ(3, get<2>(t4)); + EXPECT_EQ(1, get<0>(t5)); + EXPECT_EQ(2, get<1>(t5)); + EXPECT_EQ(3, get<2>(t5)); + EXPECT_EQ(4, get<3>(t5)); + EXPECT_EQ(1, get<0>(t6)); + EXPECT_EQ(2, get<1>(t6)); + EXPECT_EQ(3, get<2>(t6)); + EXPECT_EQ(4, get<3>(t6)); + EXPECT_EQ(5, get<4>(t6)); + + EXPECT_EQ(1, get<0>(t1)); + DispatchToFunction(&DoAdd, t4); + EXPECT_EQ(6, get<0>(t1)); + + int res = 0; + DispatchToFunction(&DoAdd, base::MakeTuple(9, 8, 7, &res)); + EXPECT_EQ(24, res); + + Addy addy; + EXPECT_EQ(1, get<0>(t4)); + DispatchToMethod(&addy, &Addy::DoAdd, t5); + EXPECT_EQ(10, get<0>(t4)); + + Addz addz; + EXPECT_EQ(10, get<0>(t4)); + DispatchToMethod(&addz, &Addz::DoAdd, t6); + EXPECT_EQ(15, get<0>(t4)); +} + +namespace { + +struct CopyLogger { + CopyLogger() { ++TimesConstructed; } + CopyLogger(const CopyLogger& tocopy) { ++TimesConstructed; ++TimesCopied; } + ~CopyLogger() { } + + static int TimesCopied; + static int TimesConstructed; +}; + +void SomeLoggerMethRef(const CopyLogger& logy, const CopyLogger* ptr, bool* b) { + *b = &logy == ptr; +} + +void SomeLoggerMethCopy(CopyLogger logy, const CopyLogger* ptr, bool* b) { + *b = &logy == ptr; +} + +int CopyLogger::TimesCopied = 0; +int CopyLogger::TimesConstructed = 0; + +} // namespace + +TEST(TupleTest, Copying) { + CopyLogger logger; + EXPECT_EQ(0, CopyLogger::TimesCopied); + EXPECT_EQ(1, CopyLogger::TimesConstructed); + + bool res = false; + + // Creating the tuple should copy the class to store internally in the tuple. + base::Tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res); + get<1>(tuple) = &get<0>(tuple); + EXPECT_EQ(2, CopyLogger::TimesConstructed); + EXPECT_EQ(1, CopyLogger::TimesCopied); + + // Our internal Logger and the one passed to the function should be the same. + res = false; + DispatchToFunction(&SomeLoggerMethRef, tuple); + EXPECT_TRUE(res); + EXPECT_EQ(2, CopyLogger::TimesConstructed); + EXPECT_EQ(1, CopyLogger::TimesCopied); + + // Now they should be different, since the function call will make a copy. + res = false; + DispatchToFunction(&SomeLoggerMethCopy, tuple); + EXPECT_FALSE(res); + EXPECT_EQ(3, CopyLogger::TimesConstructed); + EXPECT_EQ(2, CopyLogger::TimesCopied); +} + +} // namespace base diff --git a/third_party/chromium/base/values.cc b/third_party/chromium/base/values.cc new file mode 100644 index 0000000..689fdd7 --- /dev/null +++ b/third_party/chromium/base/values.cc @@ -0,0 +1,1113 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/values.h" + +#include <string.h> + +#include <algorithm> +#include <cmath> +#include <ostream> + +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/move.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversion_utils.h" + +namespace base { + +namespace { + +scoped_ptr<Value> CopyWithoutEmptyChildren(const Value& node); + +// Make a deep copy of |node|, but don't include empty lists or dictionaries +// in the copy. It's possible for this function to return NULL and it +// expects |node| to always be non-NULL. +scoped_ptr<ListValue> CopyListWithoutEmptyChildren(const ListValue& list) { + scoped_ptr<ListValue> copy; + for (ListValue::const_iterator it = list.begin(); it != list.end(); ++it) { + scoped_ptr<Value> child_copy = CopyWithoutEmptyChildren(**it); + if (child_copy) { + if (!copy) + copy.reset(new ListValue); + copy->Append(child_copy.Pass()); + } + } + return copy; +} + +scoped_ptr<DictionaryValue> CopyDictionaryWithoutEmptyChildren( + const DictionaryValue& dict) { + scoped_ptr<DictionaryValue> copy; + for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { + scoped_ptr<Value> child_copy = CopyWithoutEmptyChildren(it.value()); + if (child_copy) { + if (!copy) + copy.reset(new DictionaryValue); + copy->SetWithoutPathExpansion(it.key(), child_copy.Pass()); + } + } + return copy; +} + +scoped_ptr<Value> CopyWithoutEmptyChildren(const Value& node) { + switch (node.GetType()) { + case Value::TYPE_LIST: + return CopyListWithoutEmptyChildren(static_cast<const ListValue&>(node)); + + case Value::TYPE_DICTIONARY: + return CopyDictionaryWithoutEmptyChildren( + static_cast<const DictionaryValue&>(node)); + + default: + return node.CreateDeepCopy(); + } +} + +// A small functor for comparing Values for std::find_if and similar. +class ValueEquals { + public: + // Pass the value against which all consecutive calls of the () operator will + // compare their argument to. This Value object must not be destroyed while + // the ValueEquals is in use. + explicit ValueEquals(const Value* first) : first_(first) { } + + bool operator ()(const Value* second) const { + return first_->Equals(second); + } + + private: + const Value* first_; +}; + +} // namespace + +Value::~Value() { +} + +// static +scoped_ptr<Value> Value::CreateNullValue() { + return make_scoped_ptr(new Value(TYPE_NULL)); +} + +bool Value::GetAsBinary(const BinaryValue** out_value) const { + return false; +} + +bool Value::GetAsBoolean(bool* out_value) const { + return false; +} + +bool Value::GetAsInteger(int* out_value) const { + return false; +} + +bool Value::GetAsDouble(double* out_value) const { + return false; +} + +bool Value::GetAsString(std::string* out_value) const { + return false; +} + +bool Value::GetAsString(const StringValue** out_value) const { + return false; +} + +bool Value::GetAsList(ListValue** out_value) { + return false; +} + +bool Value::GetAsList(const ListValue** out_value) const { + return false; +} + +bool Value::GetAsDictionary(DictionaryValue** out_value) { + return false; +} + +bool Value::GetAsDictionary(const DictionaryValue** out_value) const { + return false; +} + +Value* Value::DeepCopy() const { + // This method should only be getting called for null Values--all subclasses + // need to provide their own implementation;. + DCHECK(IsType(TYPE_NULL)); + return CreateNullValue().release(); +} + +scoped_ptr<Value> Value::CreateDeepCopy() const { + return make_scoped_ptr(DeepCopy()); +} + +bool Value::Equals(const Value* other) const { + // This method should only be getting called for null Values--all subclasses + // need to provide their own implementation;. + DCHECK(IsType(TYPE_NULL)); + return other->IsType(TYPE_NULL); +} + +// static +bool Value::Equals(const Value* a, const Value* b) { + if ((a == NULL) && (b == NULL)) return true; + if ((a == NULL) ^ (b == NULL)) return false; + return a->Equals(b); +} + +Value::Value(Type type) : type_(type) {} + +Value::Value(const Value& that) : type_(that.type_) {} + +Value& Value::operator=(const Value& that) { + type_ = that.type_; + return *this; +} + +///////////////////// FundamentalValue //////////////////// + +FundamentalValue::FundamentalValue(bool in_value) + : Value(TYPE_BOOLEAN), boolean_value_(in_value) { +} + +FundamentalValue::FundamentalValue(int in_value) + : Value(TYPE_INTEGER), integer_value_(in_value) { +} + +FundamentalValue::FundamentalValue(double in_value) + : Value(TYPE_DOUBLE), double_value_(in_value) { + if (!std::isfinite(double_value_)) { + NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) " + << "values cannot be represented in JSON"; + double_value_ = 0.0; + } +} + +FundamentalValue::~FundamentalValue() { +} + +bool FundamentalValue::GetAsBoolean(bool* out_value) const { + if (out_value && IsType(TYPE_BOOLEAN)) + *out_value = boolean_value_; + return (IsType(TYPE_BOOLEAN)); +} + +bool FundamentalValue::GetAsInteger(int* out_value) const { + if (out_value && IsType(TYPE_INTEGER)) + *out_value = integer_value_; + return (IsType(TYPE_INTEGER)); +} + +bool FundamentalValue::GetAsDouble(double* out_value) const { + if (out_value && IsType(TYPE_DOUBLE)) + *out_value = double_value_; + else if (out_value && IsType(TYPE_INTEGER)) + *out_value = integer_value_; + return (IsType(TYPE_DOUBLE) || IsType(TYPE_INTEGER)); +} + +FundamentalValue* FundamentalValue::DeepCopy() const { + switch (GetType()) { + case TYPE_BOOLEAN: + return new FundamentalValue(boolean_value_); + + case TYPE_INTEGER: + return new FundamentalValue(integer_value_); + + case TYPE_DOUBLE: + return new FundamentalValue(double_value_); + + default: + NOTREACHED(); + return NULL; + } +} + +bool FundamentalValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + + switch (GetType()) { + case TYPE_BOOLEAN: { + bool lhs, rhs; + return GetAsBoolean(&lhs) && other->GetAsBoolean(&rhs) && lhs == rhs; + } + case TYPE_INTEGER: { + int lhs, rhs; + return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs; + } + case TYPE_DOUBLE: { + double lhs, rhs; + return GetAsDouble(&lhs) && other->GetAsDouble(&rhs) && lhs == rhs; + } + default: + NOTREACHED(); + return false; + } +} + +///////////////////// StringValue //////////////////// + +StringValue::StringValue(const std::string& in_value) + : Value(TYPE_STRING), + value_(in_value) { + DCHECK(IsStringUTF8(in_value)); +} + +StringValue::~StringValue() { +} + +std::string* StringValue::GetString() { + return &value_; +} + +const std::string& StringValue::GetString() const { + return value_; +} + +bool StringValue::GetAsString(std::string* out_value) const { + if (out_value) + *out_value = value_; + return true; +} + +bool StringValue::GetAsString(const StringValue** out_value) const { + if (out_value) + *out_value = this; + return true; +} + +StringValue* StringValue::DeepCopy() const { + return new StringValue(value_); +} + +bool StringValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + std::string lhs, rhs; + return GetAsString(&lhs) && other->GetAsString(&rhs) && lhs == rhs; +} + +///////////////////// BinaryValue //////////////////// + +BinaryValue::BinaryValue() + : Value(TYPE_BINARY), + size_(0) { +} + +BinaryValue::BinaryValue(scoped_ptr<char[]> buffer, size_t size) + : Value(TYPE_BINARY), + buffer_(buffer.Pass()), + size_(size) { +} + +BinaryValue::~BinaryValue() { +} + +// static +BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer, + size_t size) { + char* buffer_copy = new char[size]; + memcpy(buffer_copy, buffer, size); + scoped_ptr<char[]> scoped_buffer_copy(buffer_copy); + return new BinaryValue(scoped_buffer_copy.Pass(), size); +} + +bool BinaryValue::GetAsBinary(const BinaryValue** out_value) const { + if (out_value) + *out_value = this; + return true; +} + +BinaryValue* BinaryValue::DeepCopy() const { + return CreateWithCopiedBuffer(buffer_.get(), size_); +} + +bool BinaryValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + const BinaryValue* other_binary = static_cast<const BinaryValue*>(other); + if (other_binary->size_ != size_) + return false; + return !memcmp(GetBuffer(), other_binary->GetBuffer(), size_); +} + +///////////////////// DictionaryValue //////////////////// + +DictionaryValue::DictionaryValue() + : Value(TYPE_DICTIONARY) { +} + +DictionaryValue::~DictionaryValue() { + Clear(); +} + +bool DictionaryValue::GetAsDictionary(DictionaryValue** out_value) { + if (out_value) + *out_value = this; + return true; +} + +bool DictionaryValue::GetAsDictionary(const DictionaryValue** out_value) const { + if (out_value) + *out_value = this; + return true; +} + +bool DictionaryValue::HasKey(const std::string& key) const { + DCHECK(IsStringUTF8(key)); + ValueMap::const_iterator current_entry = dictionary_.find(key); + DCHECK((current_entry == dictionary_.end()) || current_entry->second); + return current_entry != dictionary_.end(); +} + +void DictionaryValue::Clear() { + ValueMap::iterator dict_iterator = dictionary_.begin(); + while (dict_iterator != dictionary_.end()) { + delete dict_iterator->second; + ++dict_iterator; + } + + dictionary_.clear(); +} + +void DictionaryValue::Set(const std::string& path, scoped_ptr<Value> in_value) { + DCHECK(IsStringUTF8(path)); + DCHECK(in_value); + + std::string current_path(path); + DictionaryValue* current_dictionary = this; + for (size_t delimiter_position = current_path.find('.'); + delimiter_position != std::string::npos; + delimiter_position = current_path.find('.')) { + // Assume that we're indexing into a dictionary. + std::string key(current_path, 0, delimiter_position); + DictionaryValue* child_dictionary = NULL; + if (!current_dictionary->GetDictionary(key, &child_dictionary)) { + child_dictionary = new DictionaryValue; + current_dictionary->SetWithoutPathExpansion(key, child_dictionary); + } + + current_dictionary = child_dictionary; + current_path.erase(0, delimiter_position + 1); + } + + current_dictionary->SetWithoutPathExpansion(current_path, in_value.Pass()); +} + +void DictionaryValue::Set(const std::string& path, Value* in_value) { + Set(path, make_scoped_ptr(in_value)); +} + +void DictionaryValue::SetBoolean(const std::string& path, bool in_value) { + Set(path, new FundamentalValue(in_value)); +} + +void DictionaryValue::SetInteger(const std::string& path, int in_value) { + Set(path, new FundamentalValue(in_value)); +} + +void DictionaryValue::SetDouble(const std::string& path, double in_value) { + Set(path, new FundamentalValue(in_value)); +} + +void DictionaryValue::SetString(const std::string& path, + const std::string& in_value) { + Set(path, new StringValue(in_value)); +} + +void DictionaryValue::SetWithoutPathExpansion(const std::string& key, + scoped_ptr<Value> in_value) { + Value* bare_ptr = in_value.release(); + // If there's an existing value here, we need to delete it, because + // we own all our children. + std::pair<ValueMap::iterator, bool> ins_res = + dictionary_.insert(std::make_pair(key, bare_ptr)); + if (!ins_res.second) { + DCHECK_NE(ins_res.first->second, bare_ptr); // This would be bogus + delete ins_res.first->second; + ins_res.first->second = bare_ptr; + } +} + +void DictionaryValue::SetWithoutPathExpansion(const std::string& key, + Value* in_value) { + SetWithoutPathExpansion(key, make_scoped_ptr(in_value)); +} + +void DictionaryValue::SetBooleanWithoutPathExpansion( + const std::string& path, bool in_value) { + SetWithoutPathExpansion(path, new FundamentalValue(in_value)); +} + +void DictionaryValue::SetIntegerWithoutPathExpansion( + const std::string& path, int in_value) { + SetWithoutPathExpansion(path, new FundamentalValue(in_value)); +} + +void DictionaryValue::SetDoubleWithoutPathExpansion( + const std::string& path, double in_value) { + SetWithoutPathExpansion(path, new FundamentalValue(in_value)); +} + +void DictionaryValue::SetStringWithoutPathExpansion( + const std::string& path, const std::string& in_value) { + SetWithoutPathExpansion(path, new StringValue(in_value)); +} + +bool DictionaryValue::Get(const std::string& path, + const Value** out_value) const { + DCHECK(IsStringUTF8(path)); + std::string current_path(path); + const DictionaryValue* current_dictionary = this; + for (size_t delimiter_position = current_path.find('.'); + delimiter_position != std::string::npos; + delimiter_position = current_path.find('.')) { + const DictionaryValue* child_dictionary = NULL; + if (!current_dictionary->GetDictionary( + current_path.substr(0, delimiter_position), &child_dictionary)) + return false; + + current_dictionary = child_dictionary; + current_path.erase(0, delimiter_position + 1); + } + + return current_dictionary->GetWithoutPathExpansion(current_path, out_value); +} + +bool DictionaryValue::Get(const std::string& path, Value** out_value) { + return static_cast<const DictionaryValue&>(*this).Get( + path, + const_cast<const Value**>(out_value)); +} + +bool DictionaryValue::GetBoolean(const std::string& path, + bool* bool_value) const { + const Value* value; + if (!Get(path, &value)) + return false; + + return value->GetAsBoolean(bool_value); +} + +bool DictionaryValue::GetInteger(const std::string& path, + int* out_value) const { + const Value* value; + if (!Get(path, &value)) + return false; + + return value->GetAsInteger(out_value); +} + +bool DictionaryValue::GetDouble(const std::string& path, + double* out_value) const { + const Value* value; + if (!Get(path, &value)) + return false; + + return value->GetAsDouble(out_value); +} + +bool DictionaryValue::GetString(const std::string& path, + std::string* out_value) const { + const Value* value; + if (!Get(path, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool DictionaryValue::GetStringASCII(const std::string& path, + std::string* out_value) const { + std::string out; + if (!GetString(path, &out)) + return false; + + if (!IsStringASCII(out)) { + NOTREACHED(); + return false; + } + + out_value->assign(out); + return true; +} + +bool DictionaryValue::GetBinary(const std::string& path, + const BinaryValue** out_value) const { + const Value* value; + bool result = Get(path, &value); + if (!result || !value->IsType(TYPE_BINARY)) + return false; + + if (out_value) + *out_value = static_cast<const BinaryValue*>(value); + + return true; +} + +bool DictionaryValue::GetBinary(const std::string& path, + BinaryValue** out_value) { + return static_cast<const DictionaryValue&>(*this).GetBinary( + path, + const_cast<const BinaryValue**>(out_value)); +} + +bool DictionaryValue::GetDictionary(const std::string& path, + const DictionaryValue** out_value) const { + const Value* value; + bool result = Get(path, &value); + if (!result || !value->IsType(TYPE_DICTIONARY)) + return false; + + if (out_value) + *out_value = static_cast<const DictionaryValue*>(value); + + return true; +} + +bool DictionaryValue::GetDictionary(const std::string& path, + DictionaryValue** out_value) { + return static_cast<const DictionaryValue&>(*this).GetDictionary( + path, + const_cast<const DictionaryValue**>(out_value)); +} + +bool DictionaryValue::GetList(const std::string& path, + const ListValue** out_value) const { + const Value* value; + bool result = Get(path, &value); + if (!result || !value->IsType(TYPE_LIST)) + return false; + + if (out_value) + *out_value = static_cast<const ListValue*>(value); + + return true; +} + +bool DictionaryValue::GetList(const std::string& path, ListValue** out_value) { + return static_cast<const DictionaryValue&>(*this).GetList( + path, + const_cast<const ListValue**>(out_value)); +} + +bool DictionaryValue::GetWithoutPathExpansion(const std::string& key, + const Value** out_value) const { + DCHECK(IsStringUTF8(key)); + ValueMap::const_iterator entry_iterator = dictionary_.find(key); + if (entry_iterator == dictionary_.end()) + return false; + + const Value* entry = entry_iterator->second; + if (out_value) + *out_value = entry; + return true; +} + +bool DictionaryValue::GetWithoutPathExpansion(const std::string& key, + Value** out_value) { + return static_cast<const DictionaryValue&>(*this).GetWithoutPathExpansion( + key, + const_cast<const Value**>(out_value)); +} + +bool DictionaryValue::GetBooleanWithoutPathExpansion(const std::string& key, + bool* out_value) const { + const Value* value; + if (!GetWithoutPathExpansion(key, &value)) + return false; + + return value->GetAsBoolean(out_value); +} + +bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key, + int* out_value) const { + const Value* value; + if (!GetWithoutPathExpansion(key, &value)) + return false; + + return value->GetAsInteger(out_value); +} + +bool DictionaryValue::GetDoubleWithoutPathExpansion(const std::string& key, + double* out_value) const { + const Value* value; + if (!GetWithoutPathExpansion(key, &value)) + return false; + + return value->GetAsDouble(out_value); +} + +bool DictionaryValue::GetStringWithoutPathExpansion( + const std::string& key, + std::string* out_value) const { + const Value* value; + if (!GetWithoutPathExpansion(key, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool DictionaryValue::GetDictionaryWithoutPathExpansion( + const std::string& key, + const DictionaryValue** out_value) const { + const Value* value; + bool result = GetWithoutPathExpansion(key, &value); + if (!result || !value->IsType(TYPE_DICTIONARY)) + return false; + + if (out_value) + *out_value = static_cast<const DictionaryValue*>(value); + + return true; +} + +bool DictionaryValue::GetDictionaryWithoutPathExpansion( + const std::string& key, + DictionaryValue** out_value) { + const DictionaryValue& const_this = + static_cast<const DictionaryValue&>(*this); + return const_this.GetDictionaryWithoutPathExpansion( + key, + const_cast<const DictionaryValue**>(out_value)); +} + +bool DictionaryValue::GetListWithoutPathExpansion( + const std::string& key, + const ListValue** out_value) const { + const Value* value; + bool result = GetWithoutPathExpansion(key, &value); + if (!result || !value->IsType(TYPE_LIST)) + return false; + + if (out_value) + *out_value = static_cast<const ListValue*>(value); + + return true; +} + +bool DictionaryValue::GetListWithoutPathExpansion(const std::string& key, + ListValue** out_value) { + return + static_cast<const DictionaryValue&>(*this).GetListWithoutPathExpansion( + key, + const_cast<const ListValue**>(out_value)); +} + +bool DictionaryValue::Remove(const std::string& path, + scoped_ptr<Value>* out_value) { + DCHECK(IsStringUTF8(path)); + std::string current_path(path); + DictionaryValue* current_dictionary = this; + size_t delimiter_position = current_path.rfind('.'); + if (delimiter_position != std::string::npos) { + if (!GetDictionary(current_path.substr(0, delimiter_position), + ¤t_dictionary)) + return false; + current_path.erase(0, delimiter_position + 1); + } + + return current_dictionary->RemoveWithoutPathExpansion(current_path, + out_value); +} + +bool DictionaryValue::RemoveWithoutPathExpansion(const std::string& key, + scoped_ptr<Value>* out_value) { + DCHECK(IsStringUTF8(key)); + ValueMap::iterator entry_iterator = dictionary_.find(key); + if (entry_iterator == dictionary_.end()) + return false; + + Value* entry = entry_iterator->second; + if (out_value) + out_value->reset(entry); + else + delete entry; + dictionary_.erase(entry_iterator); + return true; +} + +bool DictionaryValue::RemovePath(const std::string& path, + scoped_ptr<Value>* out_value) { + bool result = false; + size_t delimiter_position = path.find('.'); + + if (delimiter_position == std::string::npos) + return RemoveWithoutPathExpansion(path, out_value); + + const std::string subdict_path = path.substr(0, delimiter_position); + DictionaryValue* subdict = NULL; + if (!GetDictionary(subdict_path, &subdict)) + return false; + result = subdict->RemovePath(path.substr(delimiter_position + 1), + out_value); + if (result && subdict->empty()) + RemoveWithoutPathExpansion(subdict_path, NULL); + + return result; +} + +scoped_ptr<DictionaryValue> DictionaryValue::DeepCopyWithoutEmptyChildren() + const { + scoped_ptr<DictionaryValue> copy = CopyDictionaryWithoutEmptyChildren(*this); + if (!copy) + copy.reset(new DictionaryValue); + return copy; +} + +void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) { + for (DictionaryValue::Iterator it(*dictionary); !it.IsAtEnd(); it.Advance()) { + const Value* merge_value = &it.value(); + // Check whether we have to merge dictionaries. + if (merge_value->IsType(Value::TYPE_DICTIONARY)) { + DictionaryValue* sub_dict; + if (GetDictionaryWithoutPathExpansion(it.key(), &sub_dict)) { + sub_dict->MergeDictionary( + static_cast<const DictionaryValue*>(merge_value)); + continue; + } + } + // All other cases: Make a copy and hook it up. + SetWithoutPathExpansion(it.key(), merge_value->DeepCopy()); + } +} + +void DictionaryValue::Swap(DictionaryValue* other) { + dictionary_.swap(other->dictionary_); +} + +DictionaryValue::Iterator::Iterator(const DictionaryValue& target) + : target_(target), + it_(target.dictionary_.begin()) {} + +DictionaryValue::Iterator::~Iterator() {} + +DictionaryValue* DictionaryValue::DeepCopy() const { + DictionaryValue* result = new DictionaryValue; + + for (ValueMap::const_iterator current_entry(dictionary_.begin()); + current_entry != dictionary_.end(); ++current_entry) { + result->SetWithoutPathExpansion(current_entry->first, + current_entry->second->DeepCopy()); + } + + return result; +} + +scoped_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const { + return make_scoped_ptr(DeepCopy()); +} + +bool DictionaryValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + + const DictionaryValue* other_dict = + static_cast<const DictionaryValue*>(other); + Iterator lhs_it(*this); + Iterator rhs_it(*other_dict); + while (!lhs_it.IsAtEnd() && !rhs_it.IsAtEnd()) { + if (lhs_it.key() != rhs_it.key() || + !lhs_it.value().Equals(&rhs_it.value())) { + return false; + } + lhs_it.Advance(); + rhs_it.Advance(); + } + if (!lhs_it.IsAtEnd() || !rhs_it.IsAtEnd()) + return false; + + return true; +} + +///////////////////// ListValue //////////////////// + +ListValue::ListValue() : Value(TYPE_LIST) { +} + +ListValue::~ListValue() { + Clear(); +} + +void ListValue::Clear() { + for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) + delete *i; + list_.clear(); +} + +bool ListValue::Set(size_t index, Value* in_value) { + if (!in_value) + return false; + + if (index >= list_.size()) { + // Pad out any intermediate indexes with null settings + while (index > list_.size()) + Append(CreateNullValue()); + Append(in_value); + } else { + DCHECK(list_[index] != in_value); + delete list_[index]; + list_[index] = in_value; + } + return true; +} + +bool ListValue::Set(size_t index, scoped_ptr<Value> in_value) { + return Set(index, in_value.release()); +} + +bool ListValue::Get(size_t index, const Value** out_value) const { + if (index >= list_.size()) + return false; + + if (out_value) + *out_value = list_[index]; + + return true; +} + +bool ListValue::Get(size_t index, Value** out_value) { + return static_cast<const ListValue&>(*this).Get( + index, + const_cast<const Value**>(out_value)); +} + +bool ListValue::GetBoolean(size_t index, bool* bool_value) const { + const Value* value; + if (!Get(index, &value)) + return false; + + return value->GetAsBoolean(bool_value); +} + +bool ListValue::GetInteger(size_t index, int* out_value) const { + const Value* value; + if (!Get(index, &value)) + return false; + + return value->GetAsInteger(out_value); +} + +bool ListValue::GetDouble(size_t index, double* out_value) const { + const Value* value; + if (!Get(index, &value)) + return false; + + return value->GetAsDouble(out_value); +} + +bool ListValue::GetString(size_t index, std::string* out_value) const { + const Value* value; + if (!Get(index, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool ListValue::GetBinary(size_t index, const BinaryValue** out_value) const { + const Value* value; + bool result = Get(index, &value); + if (!result || !value->IsType(TYPE_BINARY)) + return false; + + if (out_value) + *out_value = static_cast<const BinaryValue*>(value); + + return true; +} + +bool ListValue::GetBinary(size_t index, BinaryValue** out_value) { + return static_cast<const ListValue&>(*this).GetBinary( + index, + const_cast<const BinaryValue**>(out_value)); +} + +bool ListValue::GetDictionary(size_t index, + const DictionaryValue** out_value) const { + const Value* value; + bool result = Get(index, &value); + if (!result || !value->IsType(TYPE_DICTIONARY)) + return false; + + if (out_value) + *out_value = static_cast<const DictionaryValue*>(value); + + return true; +} + +bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) { + return static_cast<const ListValue&>(*this).GetDictionary( + index, + const_cast<const DictionaryValue**>(out_value)); +} + +bool ListValue::GetList(size_t index, const ListValue** out_value) const { + const Value* value; + bool result = Get(index, &value); + if (!result || !value->IsType(TYPE_LIST)) + return false; + + if (out_value) + *out_value = static_cast<const ListValue*>(value); + + return true; +} + +bool ListValue::GetList(size_t index, ListValue** out_value) { + return static_cast<const ListValue&>(*this).GetList( + index, + const_cast<const ListValue**>(out_value)); +} + +bool ListValue::Remove(size_t index, scoped_ptr<Value>* out_value) { + if (index >= list_.size()) + return false; + + if (out_value) + out_value->reset(list_[index]); + else + delete list_[index]; + + list_.erase(list_.begin() + index); + return true; +} + +bool ListValue::Remove(const Value& value, size_t* index) { + for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) { + if ((*i)->Equals(&value)) { + size_t previous_index = i - list_.begin(); + delete *i; + list_.erase(i); + + if (index) + *index = previous_index; + return true; + } + } + return false; +} + +ListValue::iterator ListValue::Erase(iterator iter, + scoped_ptr<Value>* out_value) { + if (out_value) + out_value->reset(*iter); + else + delete *iter; + + return list_.erase(iter); +} + +void ListValue::Append(scoped_ptr<Value> in_value) { + Append(in_value.release()); +} + +void ListValue::Append(Value* in_value) { + DCHECK(in_value); + list_.push_back(in_value); +} + +void ListValue::AppendBoolean(bool in_value) { + Append(new FundamentalValue(in_value)); +} + +void ListValue::AppendInteger(int in_value) { + Append(new FundamentalValue(in_value)); +} + +void ListValue::AppendDouble(double in_value) { + Append(new FundamentalValue(in_value)); +} + +void ListValue::AppendString(const std::string& in_value) { + Append(new StringValue(in_value)); +} + +void ListValue::AppendStrings(const std::vector<std::string>& in_values) { + for (std::vector<std::string>::const_iterator it = in_values.begin(); + it != in_values.end(); ++it) { + AppendString(*it); + } +} + +bool ListValue::AppendIfNotPresent(Value* in_value) { + DCHECK(in_value); + for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) { + if ((*i)->Equals(in_value)) { + delete in_value; + return false; + } + } + list_.push_back(in_value); + return true; +} + +bool ListValue::Insert(size_t index, Value* in_value) { + DCHECK(in_value); + if (index > list_.size()) + return false; + + list_.insert(list_.begin() + index, in_value); + return true; +} + +ListValue::const_iterator ListValue::Find(const Value& value) const { + return std::find_if(list_.begin(), list_.end(), ValueEquals(&value)); +} + +void ListValue::Swap(ListValue* other) { + list_.swap(other->list_); +} + +bool ListValue::GetAsList(ListValue** out_value) { + if (out_value) + *out_value = this; + return true; +} + +bool ListValue::GetAsList(const ListValue** out_value) const { + if (out_value) + *out_value = this; + return true; +} + +ListValue* ListValue::DeepCopy() const { + ListValue* result = new ListValue; + + for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) + result->Append((*i)->DeepCopy()); + + return result; +} + +scoped_ptr<ListValue> ListValue::CreateDeepCopy() const { + return make_scoped_ptr(DeepCopy()); +} + +bool ListValue::Equals(const Value* other) const { + if (other->GetType() != GetType()) + return false; + + const ListValue* other_list = + static_cast<const ListValue*>(other); + const_iterator lhs_it, rhs_it; + for (lhs_it = begin(), rhs_it = other_list->begin(); + lhs_it != end() && rhs_it != other_list->end(); + ++lhs_it, ++rhs_it) { + if (!(*lhs_it)->Equals(*rhs_it)) + return false; + } + if (lhs_it != end() || rhs_it != other_list->end()) + return false; + + return true; +} + +std::ostream& operator<<(std::ostream& out, const Value& value) { + std::string json; + JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json); + return out << json; +} + +} // namespace base diff --git a/third_party/chromium/base/values.h b/third_party/chromium/base/values.h new file mode 100644 index 0000000..7ae52a9 --- /dev/null +++ b/third_party/chromium/base/values.h @@ -0,0 +1,519 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file specifies a recursive data storage class called Value intended for +// storing settings and other persistable data. +// +// A Value represents something that can be stored in JSON or passed to/from +// JavaScript. As such, it is NOT a generalized variant type, since only the +// types supported by JavaScript/JSON are supported. +// +// IN PARTICULAR this means that there is no support for int64 or unsigned +// numbers. Writing JSON with such types would violate the spec. If you need +// something like this, either use a double or make a string value containing +// the number you want. + +#ifndef BASE_VALUES_H_ +#define BASE_VALUES_H_ + +#include <stddef.h> + +#include <iosfwd> +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "base/base_export.h" +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" + +namespace base { + +class BinaryValue; +class DictionaryValue; +class FundamentalValue; +class ListValue; +class StringValue; +class Value; + +typedef std::vector<Value*> ValueVector; +typedef std::map<std::string, Value*> ValueMap; + +// The Value class is the base class for Values. A Value can be instantiated +// via the Create*Value() factory methods, or by directly creating instances of +// the subclasses. +// +// See the file-level comment above for more information. +class BASE_EXPORT Value { + public: + enum Type { + TYPE_NULL = 0, + TYPE_BOOLEAN, + TYPE_INTEGER, + TYPE_DOUBLE, + TYPE_STRING, + TYPE_BINARY, + TYPE_DICTIONARY, + TYPE_LIST + // Note: Do not add more types. See the file-level comment above for why. + }; + + virtual ~Value(); + + static scoped_ptr<Value> CreateNullValue(); + + // Returns the type of the value stored by the current Value object. + // Each type will be implemented by only one subclass of Value, so it's + // safe to use the Type to determine whether you can cast from + // Value* to (Implementing Class)*. Also, a Value object never changes + // its type after construction. + Type GetType() const { return type_; } + + // Returns true if the current object represents a given type. + bool IsType(Type type) const { return type == type_; } + + // These methods allow the convenient retrieval of the contents of the Value. + // If the current object can be converted into the given type, the value is + // returned through the |out_value| parameter and true is returned; + // otherwise, false is returned and |out_value| is unchanged. + virtual bool GetAsBoolean(bool* out_value) const; + virtual bool GetAsInteger(int* out_value) const; + virtual bool GetAsDouble(double* out_value) const; + virtual bool GetAsString(std::string* out_value) const; + virtual bool GetAsString(const StringValue** out_value) const; + virtual bool GetAsBinary(const BinaryValue** out_value) const; + virtual bool GetAsList(ListValue** out_value); + virtual bool GetAsList(const ListValue** out_value) const; + virtual bool GetAsDictionary(DictionaryValue** out_value); + virtual bool GetAsDictionary(const DictionaryValue** out_value) const; + // Note: Do not add more types. See the file-level comment above for why. + + // This creates a deep copy of the entire Value tree, and returns a pointer + // to the copy. The caller gets ownership of the copy, of course. + // + // Subclasses return their own type directly in their overrides; + // this works because C++ supports covariant return types. + virtual Value* DeepCopy() const; + // Preferred version of DeepCopy. TODO(estade): remove the above. + scoped_ptr<Value> CreateDeepCopy() const; + + // Compares if two Value objects have equal contents. + virtual bool Equals(const Value* other) const; + + // Compares if two Value objects have equal contents. Can handle NULLs. + // NULLs are considered equal but different from Value::CreateNullValue(). + static bool Equals(const Value* a, const Value* b); + + protected: + // These aren't safe for end-users, but they are useful for subclasses. + explicit Value(Type type); + Value(const Value& that); + Value& operator=(const Value& that); + + private: + Type type_; +}; + +// FundamentalValue represents the simple fundamental types of values. +class BASE_EXPORT FundamentalValue : public Value { + public: + explicit FundamentalValue(bool in_value); + explicit FundamentalValue(int in_value); + explicit FundamentalValue(double in_value); + ~FundamentalValue() override; + + // Overridden from Value: + bool GetAsBoolean(bool* out_value) const override; + bool GetAsInteger(int* out_value) const override; + // Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as + // doubles. + bool GetAsDouble(double* out_value) const override; + FundamentalValue* DeepCopy() const override; + bool Equals(const Value* other) const override; + + private: + union { + bool boolean_value_; + int integer_value_; + double double_value_; + }; +}; + +class BASE_EXPORT StringValue : public Value { + public: + // Initializes a StringValue with a UTF-8 narrow character string. + explicit StringValue(const std::string& in_value); + + ~StringValue() override; + + // Returns |value_| as a pointer or reference. + std::string* GetString(); + const std::string& GetString() const; + + // Overridden from Value: + bool GetAsString(std::string* out_value) const override; + bool GetAsString(const StringValue** out_value) const override; + StringValue* DeepCopy() const override; + bool Equals(const Value* other) const override; + + private: + std::string value_; +}; + +class BASE_EXPORT BinaryValue : public Value { + public: + // Creates a BinaryValue with a null buffer and size of 0. + BinaryValue(); + + // Creates a BinaryValue, taking ownership of the bytes pointed to by + // |buffer|. + BinaryValue(scoped_ptr<char[]> buffer, size_t size); + + ~BinaryValue() override; + + // For situations where you want to keep ownership of your buffer, this + // factory method creates a new BinaryValue by copying the contents of the + // buffer that's passed in. + static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size); + + size_t GetSize() const { return size_; } + + // May return NULL. + char* GetBuffer() { return buffer_.get(); } + const char* GetBuffer() const { return buffer_.get(); } + + // Overridden from Value: + bool GetAsBinary(const BinaryValue** out_value) const override; + BinaryValue* DeepCopy() const override; + bool Equals(const Value* other) const override; + + private: + scoped_ptr<char[]> buffer_; + size_t size_; + + DISALLOW_COPY_AND_ASSIGN(BinaryValue); +}; + +// DictionaryValue provides a key-value dictionary with (optional) "path" +// parsing for recursive access; see the comment at the top of the file. Keys +// are |std::string|s and should be UTF-8 encoded. +class BASE_EXPORT DictionaryValue : public Value { + public: + DictionaryValue(); + ~DictionaryValue() override; + + // Overridden from Value: + bool GetAsDictionary(DictionaryValue** out_value) override; + bool GetAsDictionary(const DictionaryValue** out_value) const override; + + // Returns true if the current dictionary has a value for the given key. + bool HasKey(const std::string& key) const; + + // Returns the number of Values in this dictionary. + size_t size() const { return dictionary_.size(); } + + // Returns whether the dictionary is empty. + bool empty() const { return dictionary_.empty(); } + + // Clears any current contents of this dictionary. + void Clear(); + + // Sets the Value associated with the given path starting from this object. + // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes + // into the next DictionaryValue down. Obviously, "." can't be used + // within a key, but there are no other restrictions on keys. + // If the key at any step of the way doesn't exist, or exists but isn't + // a DictionaryValue, a new DictionaryValue will be created and attached + // to the path in that location. |in_value| must be non-null. + void Set(const std::string& path, scoped_ptr<Value> in_value); + // Deprecated version of the above. TODO(estade): remove. + void Set(const std::string& path, Value* in_value); + + // Convenience forms of Set(). These methods will replace any existing + // value at that path, even if it has a different type. + void SetBoolean(const std::string& path, bool in_value); + void SetInteger(const std::string& path, int in_value); + void SetDouble(const std::string& path, double in_value); + void SetString(const std::string& path, const std::string& in_value); + + // Like Set(), but without special treatment of '.'. This allows e.g. URLs to + // be used as paths. + void SetWithoutPathExpansion(const std::string& key, + scoped_ptr<Value> in_value); + // Deprecated version of the above. TODO(estade): remove. + void SetWithoutPathExpansion(const std::string& key, Value* in_value); + + // Convenience forms of SetWithoutPathExpansion(). + void SetBooleanWithoutPathExpansion(const std::string& path, bool in_value); + void SetIntegerWithoutPathExpansion(const std::string& path, int in_value); + void SetDoubleWithoutPathExpansion(const std::string& path, double in_value); + void SetStringWithoutPathExpansion(const std::string& path, + const std::string& in_value); + + // Gets the Value associated with the given path starting from this object. + // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes + // into the next DictionaryValue down. If the path can be resolved + // successfully, the value for the last key in the path will be returned + // through the |out_value| parameter, and the function will return true. + // Otherwise, it will return false and |out_value| will be untouched. + // Note that the dictionary always owns the value that's returned. + // |out_value| is optional and will only be set if non-NULL. + bool Get(const std::string& path, const Value** out_value) const; + bool Get(const std::string& path, Value** out_value); + + // These are convenience forms of Get(). The value will be retrieved + // and the return value will be true if the path is valid and the value at + // the end of the path can be returned in the form specified. + // |out_value| is optional and will only be set if non-NULL. + bool GetBoolean(const std::string& path, bool* out_value) const; + bool GetInteger(const std::string& path, int* out_value) const; + // Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as + // doubles. + bool GetDouble(const std::string& path, double* out_value) const; + bool GetString(const std::string& path, std::string* out_value) const; + bool GetStringASCII(const std::string& path, std::string* out_value) const; + bool GetBinary(const std::string& path, const BinaryValue** out_value) const; + bool GetBinary(const std::string& path, BinaryValue** out_value); + bool GetDictionary(const std::string& path, + const DictionaryValue** out_value) const; + bool GetDictionary(const std::string& path, DictionaryValue** out_value); + bool GetList(const std::string& path, const ListValue** out_value) const; + bool GetList(const std::string& path, ListValue** out_value); + + // Like Get(), but without special treatment of '.'. This allows e.g. URLs to + // be used as paths. + bool GetWithoutPathExpansion(const std::string& key, + const Value** out_value) const; + bool GetWithoutPathExpansion(const std::string& key, Value** out_value); + bool GetBooleanWithoutPathExpansion(const std::string& key, + bool* out_value) const; + bool GetIntegerWithoutPathExpansion(const std::string& key, + int* out_value) const; + bool GetDoubleWithoutPathExpansion(const std::string& key, + double* out_value) const; + bool GetStringWithoutPathExpansion(const std::string& key, + std::string* out_value) const; + bool GetDictionaryWithoutPathExpansion( + const std::string& key, + const DictionaryValue** out_value) const; + bool GetDictionaryWithoutPathExpansion(const std::string& key, + DictionaryValue** out_value); + bool GetListWithoutPathExpansion(const std::string& key, + const ListValue** out_value) const; + bool GetListWithoutPathExpansion(const std::string& key, + ListValue** out_value); + + // Removes the Value with the specified path from this dictionary (or one + // of its child dictionaries, if the path is more than just a local key). + // If |out_value| is non-NULL, the removed Value will be passed out via + // |out_value|. If |out_value| is NULL, the removed value will be deleted. + // This method returns true if |path| is a valid path; otherwise it will + // return false and the DictionaryValue object will be unchanged. + virtual bool Remove(const std::string& path, scoped_ptr<Value>* out_value); + + // Like Remove(), but without special treatment of '.'. This allows e.g. URLs + // to be used as paths. + virtual bool RemoveWithoutPathExpansion(const std::string& key, + scoped_ptr<Value>* out_value); + + // Removes a path, clearing out all dictionaries on |path| that remain empty + // after removing the value at |path|. + virtual bool RemovePath(const std::string& path, + scoped_ptr<Value>* out_value); + + // Makes a copy of |this| but doesn't include empty dictionaries and lists in + // the copy. This never returns NULL, even if |this| itself is empty. + scoped_ptr<DictionaryValue> DeepCopyWithoutEmptyChildren() const; + + // Merge |dictionary| into this dictionary. This is done recursively, i.e. any + // sub-dictionaries will be merged as well. In case of key collisions, the + // passed in dictionary takes precedence and data already present will be + // replaced. Values within |dictionary| are deep-copied, so |dictionary| may + // be freed any time after this call. + void MergeDictionary(const DictionaryValue* dictionary); + + // Swaps contents with the |other| dictionary. + virtual void Swap(DictionaryValue* other); + + // This class provides an iterator over both keys and values in the + // dictionary. It can't be used to modify the dictionary. + class BASE_EXPORT Iterator { + public: + explicit Iterator(const DictionaryValue& target); + ~Iterator(); + + bool IsAtEnd() const { return it_ == target_.dictionary_.end(); } + void Advance() { ++it_; } + + const std::string& key() const { return it_->first; } + const Value& value() const { return *it_->second; } + + private: + const DictionaryValue& target_; + ValueMap::const_iterator it_; + }; + + // Overridden from Value: + DictionaryValue* DeepCopy() const override; + // Preferred version of DeepCopy. TODO(estade): remove the above. + scoped_ptr<DictionaryValue> CreateDeepCopy() const; + bool Equals(const Value* other) const override; + + private: + ValueMap dictionary_; + + DISALLOW_COPY_AND_ASSIGN(DictionaryValue); +}; + +// This type of Value represents a list of other Value values. +class BASE_EXPORT ListValue : public Value { + public: + typedef ValueVector::iterator iterator; + typedef ValueVector::const_iterator const_iterator; + + ListValue(); + ~ListValue() override; + + // Clears the contents of this ListValue + void Clear(); + + // Returns the number of Values in this list. + size_t GetSize() const { return list_.size(); } + + // Returns whether the list is empty. + bool empty() const { return list_.empty(); } + + // Sets the list item at the given index to be the Value specified by + // the value given. If the index beyond the current end of the list, null + // Values will be used to pad out the list. + // Returns true if successful, or false if the index was negative or + // the value is a null pointer. + bool Set(size_t index, Value* in_value); + // Preferred version of the above. TODO(estade): remove the above. + bool Set(size_t index, scoped_ptr<Value> in_value); + + // Gets the Value at the given index. Modifies |out_value| (and returns true) + // only if the index falls within the current list range. + // Note that the list always owns the Value passed out via |out_value|. + // |out_value| is optional and will only be set if non-NULL. + bool Get(size_t index, const Value** out_value) const; + bool Get(size_t index, Value** out_value); + + // Convenience forms of Get(). Modifies |out_value| (and returns true) + // only if the index is valid and the Value at that index can be returned + // in the specified form. + // |out_value| is optional and will only be set if non-NULL. + bool GetBoolean(size_t index, bool* out_value) const; + bool GetInteger(size_t index, int* out_value) const; + // Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as + // doubles. + bool GetDouble(size_t index, double* out_value) const; + bool GetString(size_t index, std::string* out_value) const; + bool GetBinary(size_t index, const BinaryValue** out_value) const; + bool GetBinary(size_t index, BinaryValue** out_value); + bool GetDictionary(size_t index, const DictionaryValue** out_value) const; + bool GetDictionary(size_t index, DictionaryValue** out_value); + bool GetList(size_t index, const ListValue** out_value) const; + bool GetList(size_t index, ListValue** out_value); + + // Removes the Value with the specified index from this list. + // If |out_value| is non-NULL, the removed Value AND ITS OWNERSHIP will be + // passed out via |out_value|. If |out_value| is NULL, the removed value will + // be deleted. This method returns true if |index| is valid; otherwise + // it will return false and the ListValue object will be unchanged. + virtual bool Remove(size_t index, scoped_ptr<Value>* out_value); + + // Removes the first instance of |value| found in the list, if any, and + // deletes it. |index| is the location where |value| was found. Returns false + // if not found. + bool Remove(const Value& value, size_t* index); + + // Removes the element at |iter|. If |out_value| is NULL, the value will be + // deleted, otherwise ownership of the value is passed back to the caller. + // Returns an iterator pointing to the location of the element that + // followed the erased element. + iterator Erase(iterator iter, scoped_ptr<Value>* out_value); + + // Appends a Value to the end of the list. + void Append(scoped_ptr<Value> in_value); + // Deprecated version of the above. TODO(estade): remove. + void Append(Value* in_value); + + // Convenience forms of Append. + void AppendBoolean(bool in_value); + void AppendInteger(int in_value); + void AppendDouble(double in_value); + void AppendString(const std::string& in_value); + void AppendStrings(const std::vector<std::string>& in_values); + + // Appends a Value if it's not already present. Takes ownership of the + // |in_value|. Returns true if successful, or false if the value was already + // present. If the value was already present the |in_value| is deleted. + bool AppendIfNotPresent(Value* in_value); + + // Insert a Value at index. + // Returns true if successful, or false if the index was out of range. + bool Insert(size_t index, Value* in_value); + + // Searches for the first instance of |value| in the list using the Equals + // method of the Value type. + // Returns a const_iterator to the found item or to end() if none exists. + const_iterator Find(const Value& value) const; + + // Swaps contents with the |other| list. + virtual void Swap(ListValue* other); + + // Iteration. + iterator begin() { return list_.begin(); } + iterator end() { return list_.end(); } + + const_iterator begin() const { return list_.begin(); } + const_iterator end() const { return list_.end(); } + + // Overridden from Value: + bool GetAsList(ListValue** out_value) override; + bool GetAsList(const ListValue** out_value) const override; + ListValue* DeepCopy() const override; + bool Equals(const Value* other) const override; + + // Preferred version of DeepCopy. TODO(estade): remove DeepCopy. + scoped_ptr<ListValue> CreateDeepCopy() const; + + private: + ValueVector list_; + + DISALLOW_COPY_AND_ASSIGN(ListValue); +}; + +// Stream operator so Values can be used in assertion statements. In order that +// gtest uses this operator to print readable output on test failures, we must +// override each specific type. Otherwise, the default template implementation +// is preferred over an upcast. +BASE_EXPORT std::ostream& operator<<(std::ostream& out, const Value& value); + +BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, + const FundamentalValue& value) { + return out << static_cast<const Value&>(value); +} + +BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, + const StringValue& value) { + return out << static_cast<const Value&>(value); +} + +BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, + const DictionaryValue& value) { + return out << static_cast<const Value&>(value); +} + +BASE_EXPORT inline std::ostream& operator<<(std::ostream& out, + const ListValue& value) { + return out << static_cast<const Value&>(value); +} + +} // namespace base + +#endif // BASE_VALUES_H_ diff --git a/third_party/chromium/base/values_unittest.cc b/third_party/chromium/base/values_unittest.cc new file mode 100644 index 0000000..d246691 --- /dev/null +++ b/third_party/chromium/base/values_unittest.cc @@ -0,0 +1,1070 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <limits> + +#include <gtest/gtest.h> + +#include "base/memory/scoped_ptr.h" +#include "base/strings/utf_string_conversion_utils.h" +#include "base/values.h" + +namespace base { + +TEST(ValuesTest, Basic) { + // Test basic dictionary getting/setting + DictionaryValue settings; + std::string homepage = "http://google.com"; + ASSERT_FALSE(settings.GetString("global.homepage", &homepage)); + ASSERT_EQ(std::string("http://google.com"), homepage); + + ASSERT_FALSE(settings.Get("global", NULL)); + settings.SetBoolean("global", true); + ASSERT_TRUE(settings.Get("global", NULL)); + settings.SetString("global.homepage", "http://scurvy.com"); + ASSERT_TRUE(settings.Get("global", NULL)); + homepage = "http://google.com"; + ASSERT_TRUE(settings.GetString("global.homepage", &homepage)); + ASSERT_EQ(std::string("http://scurvy.com"), homepage); + + // Test storing a dictionary in a list. + ListValue* toolbar_bookmarks; + ASSERT_FALSE( + settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks)); + + scoped_ptr<ListValue> new_toolbar_bookmarks(new ListValue); + settings.Set("global.toolbar.bookmarks", new_toolbar_bookmarks.Pass()); + ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks)); + + scoped_ptr<DictionaryValue> new_bookmark(new DictionaryValue); + new_bookmark->SetString("name", "Froogle"); + new_bookmark->SetString("url", "http://froogle.com"); + toolbar_bookmarks->Append(new_bookmark.Pass()); + + ListValue* bookmark_list; + ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list)); + DictionaryValue* bookmark; + ASSERT_EQ(1U, bookmark_list->GetSize()); + ASSERT_TRUE(bookmark_list->GetDictionary(0, &bookmark)); + std::string bookmark_name = "Unnamed"; + ASSERT_TRUE(bookmark->GetString("name", &bookmark_name)); + ASSERT_EQ(std::string("Froogle"), bookmark_name); + std::string bookmark_url; + ASSERT_TRUE(bookmark->GetString("url", &bookmark_url)); + ASSERT_EQ(std::string("http://froogle.com"), bookmark_url); +} + +TEST(ValuesTest, List) { + scoped_ptr<ListValue> mixed_list(new ListValue()); + mixed_list->Set(0, make_scoped_ptr(new FundamentalValue(true))); + mixed_list->Set(1, make_scoped_ptr(new FundamentalValue(42))); + mixed_list->Set(2, make_scoped_ptr(new FundamentalValue(88.8))); + mixed_list->Set(3, make_scoped_ptr(new StringValue("foo"))); + ASSERT_EQ(4u, mixed_list->GetSize()); + + Value *value = NULL; + bool bool_value = false; + int int_value = 0; + double double_value = 0.0; + std::string string_value; + + ASSERT_FALSE(mixed_list->Get(4, &value)); + + ASSERT_FALSE(mixed_list->GetInteger(0, &int_value)); + ASSERT_EQ(0, int_value); + ASSERT_FALSE(mixed_list->GetBoolean(1, &bool_value)); + ASSERT_FALSE(bool_value); + ASSERT_FALSE(mixed_list->GetString(2, &string_value)); + ASSERT_EQ("", string_value); + ASSERT_FALSE(mixed_list->GetInteger(2, &int_value)); + ASSERT_EQ(0, int_value); + ASSERT_FALSE(mixed_list->GetBoolean(3, &bool_value)); + ASSERT_FALSE(bool_value); + + ASSERT_TRUE(mixed_list->GetBoolean(0, &bool_value)); + ASSERT_TRUE(bool_value); + ASSERT_TRUE(mixed_list->GetInteger(1, &int_value)); + ASSERT_EQ(42, int_value); + // implicit conversion from Integer to Double should be possible. + ASSERT_TRUE(mixed_list->GetDouble(1, &double_value)); + ASSERT_EQ(42, double_value); + ASSERT_TRUE(mixed_list->GetDouble(2, &double_value)); + ASSERT_EQ(88.8, double_value); + ASSERT_TRUE(mixed_list->GetString(3, &string_value)); + ASSERT_EQ("foo", string_value); + + // Try searching in the mixed list. + base::FundamentalValue sought_value(42); + base::FundamentalValue not_found_value(false); + + ASSERT_NE(mixed_list->end(), mixed_list->Find(sought_value)); + ASSERT_TRUE((*mixed_list->Find(sought_value))->GetAsInteger(&int_value)); + ASSERT_EQ(42, int_value); + ASSERT_EQ(mixed_list->end(), mixed_list->Find(not_found_value)); +} + +TEST(ValuesTest, BinaryValue) { + // Default constructor creates a BinaryValue with a null buffer and size 0. + scoped_ptr<BinaryValue> binary(new BinaryValue()); + ASSERT_TRUE(binary.get()); + ASSERT_EQ(NULL, binary->GetBuffer()); + ASSERT_EQ(0U, binary->GetSize()); + + // Test the common case of a non-empty buffer + scoped_ptr<char[]> buffer(new char[15]); + char* original_buffer = buffer.get(); + binary.reset(new BinaryValue(buffer.Pass(), 15)); + ASSERT_TRUE(binary.get()); + ASSERT_TRUE(binary->GetBuffer()); + ASSERT_EQ(original_buffer, binary->GetBuffer()); + ASSERT_EQ(15U, binary->GetSize()); + + char stack_buffer[42]; + memset(stack_buffer, '!', 42); + binary.reset(BinaryValue::CreateWithCopiedBuffer(stack_buffer, 42)); + ASSERT_TRUE(binary.get()); + ASSERT_TRUE(binary->GetBuffer()); + ASSERT_NE(stack_buffer, binary->GetBuffer()); + ASSERT_EQ(42U, binary->GetSize()); + ASSERT_EQ(0, memcmp(stack_buffer, binary->GetBuffer(), binary->GetSize())); + + // Test overloaded GetAsBinary. + Value* narrow_value = binary.get(); + const BinaryValue* narrow_binary = NULL; + ASSERT_TRUE(narrow_value->GetAsBinary(&narrow_binary)); + EXPECT_EQ(binary.get(), narrow_binary); +} + +TEST(ValuesTest, StringValue) { + // Test overloaded StringValue constructor. + scoped_ptr<Value> narrow_value(new StringValue("narrow")); + ASSERT_TRUE(narrow_value.get()); + ASSERT_TRUE(narrow_value->IsType(Value::TYPE_STRING)); + + // Test overloaded GetAsString. + std::string narrow = "http://google.com"; + const StringValue* string_value = NULL; + ASSERT_TRUE(narrow_value->GetAsString(&narrow)); + ASSERT_TRUE(narrow_value->GetAsString(&string_value)); + ASSERT_EQ(std::string("narrow"), narrow); + ASSERT_EQ(string_value->GetString(), narrow); + + // Don't choke on NULL values. + ASSERT_TRUE(narrow_value->GetAsString(static_cast<std::string*>(NULL))); + ASSERT_TRUE(narrow_value->GetAsString( + static_cast<const StringValue**>(NULL))); +} + +// This is a Value object that allows us to tell if it's been +// properly deleted by modifying the value of external flag on destruction. +class DeletionTestValue : public Value { + public: + explicit DeletionTestValue(bool* deletion_flag) : Value(TYPE_NULL) { + Init(deletion_flag); // Separate function so that we can use ASSERT_* + } + + void Init(bool* deletion_flag) { + ASSERT_TRUE(deletion_flag); + deletion_flag_ = deletion_flag; + *deletion_flag_ = false; + } + + ~DeletionTestValue() override { *deletion_flag_ = true; } + + private: + bool* deletion_flag_; +}; + +TEST(ValuesTest, ListDeletion) { + bool deletion_flag = true; + + { + ListValue list; + list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + } + EXPECT_TRUE(deletion_flag); + + { + ListValue list; + list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + list.Clear(); + EXPECT_TRUE(deletion_flag); + } + + { + ListValue list; + list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + EXPECT_TRUE(list.Set(0, Value::CreateNullValue())); + EXPECT_TRUE(deletion_flag); + } +} + +TEST(ValuesTest, ListRemoval) { + bool deletion_flag = true; + scoped_ptr<Value> removed_item; + + { + ListValue list; + list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + EXPECT_EQ(1U, list.GetSize()); + EXPECT_FALSE(list.Remove(std::numeric_limits<size_t>::max(), + &removed_item)); + EXPECT_FALSE(list.Remove(1, &removed_item)); + EXPECT_TRUE(list.Remove(0, &removed_item)); + ASSERT_TRUE(removed_item); + EXPECT_EQ(0U, list.GetSize()); + } + EXPECT_FALSE(deletion_flag); + removed_item.reset(); + EXPECT_TRUE(deletion_flag); + + { + ListValue list; + list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + EXPECT_TRUE(list.Remove(0, NULL)); + EXPECT_TRUE(deletion_flag); + EXPECT_EQ(0U, list.GetSize()); + } + + { + ListValue list; + scoped_ptr<DeletionTestValue> value(new DeletionTestValue(&deletion_flag)); + DeletionTestValue* original_value = value.get(); + list.Append(value.Pass()); + EXPECT_FALSE(deletion_flag); + size_t index = 0; + list.Remove(*original_value, &index); + EXPECT_EQ(0U, index); + EXPECT_TRUE(deletion_flag); + EXPECT_EQ(0U, list.GetSize()); + } +} + +TEST(ValuesTest, DictionaryDeletion) { + std::string key = "test"; + bool deletion_flag = true; + + { + DictionaryValue dict; + dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + } + EXPECT_TRUE(deletion_flag); + + { + DictionaryValue dict; + dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + dict.Clear(); + EXPECT_TRUE(deletion_flag); + } + + { + DictionaryValue dict; + dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + dict.Set(key, Value::CreateNullValue()); + EXPECT_TRUE(deletion_flag); + } +} + +TEST(ValuesTest, DictionaryRemoval) { + std::string key = "test"; + bool deletion_flag = true; + scoped_ptr<Value> removed_item; + + { + DictionaryValue dict; + dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + EXPECT_TRUE(dict.HasKey(key)); + EXPECT_FALSE(dict.Remove("absent key", &removed_item)); + EXPECT_TRUE(dict.Remove(key, &removed_item)); + EXPECT_FALSE(dict.HasKey(key)); + ASSERT_TRUE(removed_item); + } + EXPECT_FALSE(deletion_flag); + removed_item.reset(); + EXPECT_TRUE(deletion_flag); + + { + DictionaryValue dict; + dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag))); + EXPECT_FALSE(deletion_flag); + EXPECT_TRUE(dict.HasKey(key)); + EXPECT_TRUE(dict.Remove(key, NULL)); + EXPECT_TRUE(deletion_flag); + EXPECT_FALSE(dict.HasKey(key)); + } +} + +TEST(ValuesTest, DictionaryWithoutPathExpansion) { + DictionaryValue dict; + dict.Set("this.is.expanded", Value::CreateNullValue()); + dict.SetWithoutPathExpansion("this.isnt.expanded", Value::CreateNullValue()); + + EXPECT_FALSE(dict.HasKey("this.is.expanded")); + EXPECT_TRUE(dict.HasKey("this")); + Value* value1; + EXPECT_TRUE(dict.Get("this", &value1)); + DictionaryValue* value2; + ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2)); + EXPECT_EQ(value1, value2); + EXPECT_EQ(1U, value2->size()); + + EXPECT_TRUE(dict.HasKey("this.isnt.expanded")); + Value* value3; + EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3)); + Value* value4; + ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4)); + EXPECT_EQ(Value::TYPE_NULL, value4->GetType()); +} + +// Tests the deprecated version of SetWithoutPathExpansion. +// TODO(estade): remove. +TEST(ValuesTest, DictionaryWithoutPathExpansionDeprecated) { + DictionaryValue dict; + dict.Set("this.is.expanded", Value::CreateNullValue()); + dict.SetWithoutPathExpansion("this.isnt.expanded", Value::CreateNullValue()); + + EXPECT_FALSE(dict.HasKey("this.is.expanded")); + EXPECT_TRUE(dict.HasKey("this")); + Value* value1; + EXPECT_TRUE(dict.Get("this", &value1)); + DictionaryValue* value2; + ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2)); + EXPECT_EQ(value1, value2); + EXPECT_EQ(1U, value2->size()); + + EXPECT_TRUE(dict.HasKey("this.isnt.expanded")); + Value* value3; + EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3)); + Value* value4; + ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4)); + EXPECT_EQ(Value::TYPE_NULL, value4->GetType()); +} + +TEST(ValuesTest, DictionaryRemovePath) { + DictionaryValue dict; + dict.SetInteger("a.long.way.down", 1); + dict.SetBoolean("a.long.key.path", true); + + scoped_ptr<Value> removed_item; + EXPECT_TRUE(dict.RemovePath("a.long.way.down", &removed_item)); + ASSERT_TRUE(removed_item); + EXPECT_TRUE(removed_item->IsType(base::Value::TYPE_INTEGER)); + EXPECT_FALSE(dict.HasKey("a.long.way.down")); + EXPECT_FALSE(dict.HasKey("a.long.way")); + EXPECT_TRUE(dict.Get("a.long.key.path", NULL)); + + removed_item.reset(); + EXPECT_FALSE(dict.RemovePath("a.long.way.down", &removed_item)); + EXPECT_FALSE(removed_item); + EXPECT_TRUE(dict.Get("a.long.key.path", NULL)); + + removed_item.reset(); + EXPECT_TRUE(dict.RemovePath("a.long.key.path", &removed_item)); + ASSERT_TRUE(removed_item); + EXPECT_TRUE(removed_item->IsType(base::Value::TYPE_BOOLEAN)); + EXPECT_TRUE(dict.empty()); +} + +TEST(ValuesTest, DeepCopy) { + DictionaryValue original_dict; + scoped_ptr<Value> scoped_null = Value::CreateNullValue(); + Value* original_null = scoped_null.get(); + original_dict.Set("null", scoped_null.Pass()); + scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true)); + FundamentalValue* original_bool = scoped_bool.get(); + original_dict.Set("bool", scoped_bool.Pass()); + scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42)); + FundamentalValue* original_int = scoped_int.get(); + original_dict.Set("int", scoped_int.Pass()); + scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14)); + FundamentalValue* original_double = scoped_double.get(); + original_dict.Set("double", scoped_double.Pass()); + scoped_ptr<StringValue> scoped_string(new StringValue("hello")); + StringValue* original_string = scoped_string.get(); + original_dict.Set("string", scoped_string.Pass()); + + scoped_ptr<char[]> original_buffer(new char[42]); + memset(original_buffer.get(), '!', 42); + scoped_ptr<BinaryValue> scoped_binary( + new BinaryValue(original_buffer.Pass(), 42)); + BinaryValue* original_binary = scoped_binary.get(); + original_dict.Set("binary", scoped_binary.Pass()); + + scoped_ptr<ListValue> scoped_list(new ListValue()); + Value* original_list = scoped_list.get(); + scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0)); + Value* original_list_element_0 = scoped_list_element_0.get(); + scoped_list->Append(scoped_list_element_0.Pass()); + scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1)); + Value* original_list_element_1 = scoped_list_element_1.get(); + scoped_list->Append(scoped_list_element_1.Pass()); + original_dict.Set("list", scoped_list.Pass()); + + scoped_ptr<DictionaryValue> scoped_nested_dictionary(new DictionaryValue()); + Value* original_nested_dictionary = scoped_nested_dictionary.get(); + scoped_nested_dictionary->SetString("key", "value"); + original_dict.Set("dictionary", scoped_nested_dictionary.Pass()); + + scoped_ptr<DictionaryValue> copy_dict = original_dict.CreateDeepCopy(); + ASSERT_TRUE(copy_dict.get()); + ASSERT_NE(copy_dict.get(), &original_dict); + + Value* copy_null = NULL; + ASSERT_TRUE(copy_dict->Get("null", ©_null)); + ASSERT_TRUE(copy_null); + ASSERT_NE(copy_null, original_null); + ASSERT_TRUE(copy_null->IsType(Value::TYPE_NULL)); + + Value* copy_bool = NULL; + ASSERT_TRUE(copy_dict->Get("bool", ©_bool)); + ASSERT_TRUE(copy_bool); + ASSERT_NE(copy_bool, original_bool); + ASSERT_TRUE(copy_bool->IsType(Value::TYPE_BOOLEAN)); + bool copy_bool_value = false; + ASSERT_TRUE(copy_bool->GetAsBoolean(©_bool_value)); + ASSERT_TRUE(copy_bool_value); + + Value* copy_int = NULL; + ASSERT_TRUE(copy_dict->Get("int", ©_int)); + ASSERT_TRUE(copy_int); + ASSERT_NE(copy_int, original_int); + ASSERT_TRUE(copy_int->IsType(Value::TYPE_INTEGER)); + int copy_int_value = 0; + ASSERT_TRUE(copy_int->GetAsInteger(©_int_value)); + ASSERT_EQ(42, copy_int_value); + + Value* copy_double = NULL; + ASSERT_TRUE(copy_dict->Get("double", ©_double)); + ASSERT_TRUE(copy_double); + ASSERT_NE(copy_double, original_double); + ASSERT_TRUE(copy_double->IsType(Value::TYPE_DOUBLE)); + double copy_double_value = 0; + ASSERT_TRUE(copy_double->GetAsDouble(©_double_value)); + ASSERT_EQ(3.14, copy_double_value); + + Value* copy_string = NULL; + ASSERT_TRUE(copy_dict->Get("string", ©_string)); + ASSERT_TRUE(copy_string); + ASSERT_NE(copy_string, original_string); + ASSERT_TRUE(copy_string->IsType(Value::TYPE_STRING)); + std::string copy_string_value; + + Value* copy_binary = NULL; + ASSERT_TRUE(copy_dict->Get("binary", ©_binary)); + ASSERT_TRUE(copy_binary); + ASSERT_NE(copy_binary, original_binary); + ASSERT_TRUE(copy_binary->IsType(Value::TYPE_BINARY)); + ASSERT_NE(original_binary->GetBuffer(), + static_cast<BinaryValue*>(copy_binary)->GetBuffer()); + ASSERT_EQ(original_binary->GetSize(), + static_cast<BinaryValue*>(copy_binary)->GetSize()); + ASSERT_EQ(0, memcmp(original_binary->GetBuffer(), + static_cast<BinaryValue*>(copy_binary)->GetBuffer(), + original_binary->GetSize())); + + Value* copy_value = NULL; + ASSERT_TRUE(copy_dict->Get("list", ©_value)); + ASSERT_TRUE(copy_value); + ASSERT_NE(copy_value, original_list); + ASSERT_TRUE(copy_value->IsType(Value::TYPE_LIST)); + ListValue* copy_list = NULL; + ASSERT_TRUE(copy_value->GetAsList(©_list)); + ASSERT_TRUE(copy_list); + ASSERT_EQ(2U, copy_list->GetSize()); + + Value* copy_list_element_0; + ASSERT_TRUE(copy_list->Get(0, ©_list_element_0)); + ASSERT_TRUE(copy_list_element_0); + ASSERT_NE(copy_list_element_0, original_list_element_0); + int copy_list_element_0_value; + ASSERT_TRUE(copy_list_element_0->GetAsInteger(©_list_element_0_value)); + ASSERT_EQ(0, copy_list_element_0_value); + + Value* copy_list_element_1; + ASSERT_TRUE(copy_list->Get(1, ©_list_element_1)); + ASSERT_TRUE(copy_list_element_1); + ASSERT_NE(copy_list_element_1, original_list_element_1); + int copy_list_element_1_value; + ASSERT_TRUE(copy_list_element_1->GetAsInteger(©_list_element_1_value)); + ASSERT_EQ(1, copy_list_element_1_value); + + copy_value = NULL; + ASSERT_TRUE(copy_dict->Get("dictionary", ©_value)); + ASSERT_TRUE(copy_value); + ASSERT_NE(copy_value, original_nested_dictionary); + ASSERT_TRUE(copy_value->IsType(Value::TYPE_DICTIONARY)); + DictionaryValue* copy_nested_dictionary = NULL; + ASSERT_TRUE(copy_value->GetAsDictionary(©_nested_dictionary)); + ASSERT_TRUE(copy_nested_dictionary); + EXPECT_TRUE(copy_nested_dictionary->HasKey("key")); +} + +TEST(ValuesTest, Equals) { + scoped_ptr<Value> null1(Value::CreateNullValue()); + scoped_ptr<Value> null2(Value::CreateNullValue()); + EXPECT_NE(null1.get(), null2.get()); + EXPECT_TRUE(null1->Equals(null2.get())); + + FundamentalValue boolean(false); + EXPECT_FALSE(null1->Equals(&boolean)); + + DictionaryValue dv; + dv.SetBoolean("a", false); + dv.SetInteger("b", 2); + dv.SetDouble("c", 2.5); + dv.SetString("d1", "string"); + dv.Set("e", Value::CreateNullValue()); + + scoped_ptr<DictionaryValue> copy = dv.CreateDeepCopy(); + EXPECT_TRUE(dv.Equals(copy.get())); + + scoped_ptr<ListValue> list(new ListValue); + ListValue* original_list = list.get(); + list->Append(Value::CreateNullValue()); + list->Append(make_scoped_ptr(new DictionaryValue)); + scoped_ptr<Value> list_copy(list->CreateDeepCopy()); + + dv.Set("f", list.Pass()); + EXPECT_FALSE(dv.Equals(copy.get())); + copy->Set("f", list_copy.Pass()); + EXPECT_TRUE(dv.Equals(copy.get())); + + original_list->Append(make_scoped_ptr(new FundamentalValue(true))); + EXPECT_FALSE(dv.Equals(copy.get())); + + // Check if Equals detects differences in only the keys. + copy = dv.CreateDeepCopy(); + EXPECT_TRUE(dv.Equals(copy.get())); + copy->Remove("a", NULL); + copy->SetBoolean("aa", false); + EXPECT_FALSE(dv.Equals(copy.get())); +} + +TEST(ValuesTest, StaticEquals) { + scoped_ptr<Value> null1(Value::CreateNullValue()); + scoped_ptr<Value> null2(Value::CreateNullValue()); + EXPECT_TRUE(Value::Equals(null1.get(), null2.get())); + EXPECT_TRUE(Value::Equals(NULL, NULL)); + + scoped_ptr<Value> i42(new FundamentalValue(42)); + scoped_ptr<Value> j42(new FundamentalValue(42)); + scoped_ptr<Value> i17(new FundamentalValue(17)); + EXPECT_TRUE(Value::Equals(i42.get(), i42.get())); + EXPECT_TRUE(Value::Equals(j42.get(), i42.get())); + EXPECT_TRUE(Value::Equals(i42.get(), j42.get())); + EXPECT_FALSE(Value::Equals(i42.get(), i17.get())); + EXPECT_FALSE(Value::Equals(i42.get(), NULL)); + EXPECT_FALSE(Value::Equals(NULL, i42.get())); + + // NULL and Value::CreateNullValue() are intentionally different: We need + // support for NULL as a return value for "undefined" without caring for + // ownership of the pointer. + EXPECT_FALSE(Value::Equals(null1.get(), NULL)); + EXPECT_FALSE(Value::Equals(NULL, null1.get())); +} + +TEST(ValuesTest, DeepCopyCovariantReturnTypes) { + DictionaryValue original_dict; + scoped_ptr<Value> scoped_null(Value::CreateNullValue()); + Value* original_null = scoped_null.get(); + original_dict.Set("null", scoped_null.Pass()); + scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true)); + Value* original_bool = scoped_bool.get(); + original_dict.Set("bool", scoped_bool.Pass()); + scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42)); + Value* original_int = scoped_int.get(); + original_dict.Set("int", scoped_int.Pass()); + scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14)); + Value* original_double = scoped_double.get(); + original_dict.Set("double", scoped_double.Pass()); + scoped_ptr<StringValue> scoped_string(new StringValue("hello")); + Value* original_string = scoped_string.get(); + original_dict.Set("string", scoped_string.Pass()); + + scoped_ptr<char[]> original_buffer(new char[42]); + memset(original_buffer.get(), '!', 42); + scoped_ptr<BinaryValue> scoped_binary( + new BinaryValue(original_buffer.Pass(), 42)); + Value* original_binary = scoped_binary.get(); + original_dict.Set("binary", scoped_binary.Pass()); + + scoped_ptr<ListValue> scoped_list(new ListValue()); + Value* original_list = scoped_list.get(); + scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0)); + scoped_list->Append(scoped_list_element_0.Pass()); + scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1)); + scoped_list->Append(scoped_list_element_1.Pass()); + original_dict.Set("list", scoped_list.Pass()); + + scoped_ptr<Value> copy_dict = original_dict.CreateDeepCopy(); + scoped_ptr<Value> copy_null = original_null->CreateDeepCopy(); + scoped_ptr<Value> copy_bool = original_bool->CreateDeepCopy(); + scoped_ptr<Value> copy_int = original_int->CreateDeepCopy(); + scoped_ptr<Value> copy_double = original_double->CreateDeepCopy(); + scoped_ptr<Value> copy_string = original_string->CreateDeepCopy(); + scoped_ptr<Value> copy_binary = original_binary->CreateDeepCopy(); + scoped_ptr<Value> copy_list = original_list->CreateDeepCopy(); + + EXPECT_TRUE(original_dict.Equals(copy_dict.get())); + EXPECT_TRUE(original_null->Equals(copy_null.get())); + EXPECT_TRUE(original_bool->Equals(copy_bool.get())); + EXPECT_TRUE(original_int->Equals(copy_int.get())); + EXPECT_TRUE(original_double->Equals(copy_double.get())); + EXPECT_TRUE(original_string->Equals(copy_string.get())); + EXPECT_TRUE(original_binary->Equals(copy_binary.get())); + EXPECT_TRUE(original_list->Equals(copy_list.get())); +} + +TEST(ValuesTest, RemoveEmptyChildren) { + scoped_ptr<DictionaryValue> root(new DictionaryValue); + // Remove empty lists and dictionaries. + root->Set("empty_dict", make_scoped_ptr(new DictionaryValue)); + root->Set("empty_list", make_scoped_ptr(new ListValue)); + root->SetWithoutPathExpansion("a.b.c.d.e", + make_scoped_ptr(new DictionaryValue)); + root = root->DeepCopyWithoutEmptyChildren(); + EXPECT_TRUE(root->empty()); + + // Make sure we don't prune too much. + root->SetBoolean("bool", true); + root->Set("empty_dict", make_scoped_ptr(new DictionaryValue)); + root->SetString("empty_string", std::string()); + root = root->DeepCopyWithoutEmptyChildren(); + EXPECT_EQ(2U, root->size()); + + // Should do nothing. + root = root->DeepCopyWithoutEmptyChildren(); + EXPECT_EQ(2U, root->size()); + + // Nested test cases. These should all reduce back to the bool and string + // set above. + { + root->Set("a.b.c.d.e", make_scoped_ptr(new DictionaryValue)); + root = root->DeepCopyWithoutEmptyChildren(); + EXPECT_EQ(2U, root->size()); + } + { + scoped_ptr<DictionaryValue> inner(new DictionaryValue); + inner->Set("empty_dict", make_scoped_ptr(new DictionaryValue)); + inner->Set("empty_list", make_scoped_ptr(new ListValue)); + root->Set("dict_with_empty_children", inner.Pass()); + root = root->DeepCopyWithoutEmptyChildren(); + EXPECT_EQ(2U, root->size()); + } + { + scoped_ptr<ListValue> inner(new ListValue); + inner->Append(make_scoped_ptr(new DictionaryValue)); + inner->Append(make_scoped_ptr(new ListValue)); + root->Set("list_with_empty_children", inner.Pass()); + root = root->DeepCopyWithoutEmptyChildren(); + EXPECT_EQ(2U, root->size()); + } + + // Nested with siblings. + { + scoped_ptr<ListValue> inner(new ListValue()); + inner->Append(make_scoped_ptr(new DictionaryValue)); + inner->Append(make_scoped_ptr(new ListValue)); + root->Set("list_with_empty_children", inner.Pass()); + scoped_ptr<DictionaryValue> inner2(new DictionaryValue); + inner2->Set("empty_dict", make_scoped_ptr(new DictionaryValue)); + inner2->Set("empty_list", make_scoped_ptr(new ListValue)); + root->Set("dict_with_empty_children", inner2.Pass()); + root = root->DeepCopyWithoutEmptyChildren(); + EXPECT_EQ(2U, root->size()); + } + + // Make sure nested values don't get pruned. + { + scoped_ptr<ListValue> inner(new ListValue); + scoped_ptr<ListValue> inner2(new ListValue); + inner2->Append(make_scoped_ptr(new StringValue("hello"))); + inner->Append(make_scoped_ptr(new DictionaryValue)); + inner->Append(inner2.Pass()); + root->Set("list_with_empty_children", inner.Pass()); + root = root->DeepCopyWithoutEmptyChildren(); + EXPECT_EQ(3U, root->size()); + + ListValue* inner_value, *inner_value2; + EXPECT_TRUE(root->GetList("list_with_empty_children", &inner_value)); + EXPECT_EQ(1U, inner_value->GetSize()); // Dictionary was pruned. + EXPECT_TRUE(inner_value->GetList(0, &inner_value2)); + EXPECT_EQ(1U, inner_value2->GetSize()); + } +} + +TEST(ValuesTest, MergeDictionary) { + scoped_ptr<DictionaryValue> base(new DictionaryValue); + base->SetString("base_key", "base_key_value_base"); + base->SetString("collide_key", "collide_key_value_base"); + scoped_ptr<DictionaryValue> base_sub_dict(new DictionaryValue); + base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base"); + base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base"); + base->Set("sub_dict_key", base_sub_dict.Pass()); + + scoped_ptr<DictionaryValue> merge(new DictionaryValue); + merge->SetString("merge_key", "merge_key_value_merge"); + merge->SetString("collide_key", "collide_key_value_merge"); + scoped_ptr<DictionaryValue> merge_sub_dict(new DictionaryValue); + merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge"); + merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge"); + merge->Set("sub_dict_key", merge_sub_dict.Pass()); + + base->MergeDictionary(merge.get()); + + EXPECT_EQ(4U, base->size()); + std::string base_key_value; + EXPECT_TRUE(base->GetString("base_key", &base_key_value)); + EXPECT_EQ("base_key_value_base", base_key_value); // Base value preserved. + std::string collide_key_value; + EXPECT_TRUE(base->GetString("collide_key", &collide_key_value)); + EXPECT_EQ("collide_key_value_merge", collide_key_value); // Replaced. + std::string merge_key_value; + EXPECT_TRUE(base->GetString("merge_key", &merge_key_value)); + EXPECT_EQ("merge_key_value_merge", merge_key_value); // Merged in. + + DictionaryValue* res_sub_dict; + EXPECT_TRUE(base->GetDictionary("sub_dict_key", &res_sub_dict)); + EXPECT_EQ(3U, res_sub_dict->size()); + std::string sub_base_key_value; + EXPECT_TRUE(res_sub_dict->GetString("sub_base_key", &sub_base_key_value)); + EXPECT_EQ("sub_base_key_value_base", sub_base_key_value); // Preserved. + std::string sub_collide_key_value; + EXPECT_TRUE(res_sub_dict->GetString("sub_collide_key", + &sub_collide_key_value)); + EXPECT_EQ("sub_collide_key_value_merge", sub_collide_key_value); // Replaced. + std::string sub_merge_key_value; + EXPECT_TRUE(res_sub_dict->GetString("sub_merge_key", &sub_merge_key_value)); + EXPECT_EQ("sub_merge_key_value_merge", sub_merge_key_value); // Merged in. +} + +TEST(ValuesTest, MergeDictionaryDeepCopy) { + scoped_ptr<DictionaryValue> child(new DictionaryValue); + DictionaryValue* original_child = child.get(); + child->SetString("test", "value"); + EXPECT_EQ(1U, child->size()); + + std::string value; + EXPECT_TRUE(child->GetString("test", &value)); + EXPECT_EQ("value", value); + + scoped_ptr<DictionaryValue> base(new DictionaryValue); + base->Set("dict", child.Pass()); + EXPECT_EQ(1U, base->size()); + + DictionaryValue* ptr; + EXPECT_TRUE(base->GetDictionary("dict", &ptr)); + EXPECT_EQ(original_child, ptr); + + scoped_ptr<DictionaryValue> merged(new DictionaryValue); + merged->MergeDictionary(base.get()); + EXPECT_EQ(1U, merged->size()); + EXPECT_TRUE(merged->GetDictionary("dict", &ptr)); + EXPECT_NE(original_child, ptr); + EXPECT_TRUE(ptr->GetString("test", &value)); + EXPECT_EQ("value", value); + + original_child->SetString("test", "overwrite"); + base.reset(); + EXPECT_TRUE(ptr->GetString("test", &value)); + EXPECT_EQ("value", value); +} + +TEST(ValuesTest, DictionaryIterator) { + DictionaryValue dict; + for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { + ADD_FAILURE(); + } + + StringValue value1("value1"); + dict.Set("key1", value1.CreateDeepCopy()); + bool seen1 = false; + for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { + EXPECT_FALSE(seen1); + EXPECT_EQ("key1", it.key()); + EXPECT_TRUE(value1.Equals(&it.value())); + seen1 = true; + } + EXPECT_TRUE(seen1); + + StringValue value2("value2"); + dict.Set("key2", value2.CreateDeepCopy()); + bool seen2 = seen1 = false; + for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { + if (it.key() == "key1") { + EXPECT_FALSE(seen1); + EXPECT_TRUE(value1.Equals(&it.value())); + seen1 = true; + } else if (it.key() == "key2") { + EXPECT_FALSE(seen2); + EXPECT_TRUE(value2.Equals(&it.value())); + seen2 = true; + } else { + ADD_FAILURE(); + } + } + EXPECT_TRUE(seen1); + EXPECT_TRUE(seen2); +} + +// DictionaryValue/ListValue's Get*() methods should accept NULL as an out-value +// and still return true/false based on success. +TEST(ValuesTest, GetWithNullOutValue) { + DictionaryValue main_dict; + ListValue main_list; + + FundamentalValue bool_value(false); + FundamentalValue int_value(1234); + FundamentalValue double_value(12.34567); + StringValue string_value("foo"); + BinaryValue binary_value; + DictionaryValue dict_value; + ListValue list_value; + + main_dict.Set("bool", bool_value.CreateDeepCopy()); + main_dict.Set("int", int_value.CreateDeepCopy()); + main_dict.Set("double", double_value.CreateDeepCopy()); + main_dict.Set("string", string_value.CreateDeepCopy()); + main_dict.Set("binary", binary_value.CreateDeepCopy()); + main_dict.Set("dict", dict_value.CreateDeepCopy()); + main_dict.Set("list", list_value.CreateDeepCopy()); + + main_list.Append(bool_value.CreateDeepCopy()); + main_list.Append(int_value.CreateDeepCopy()); + main_list.Append(double_value.CreateDeepCopy()); + main_list.Append(string_value.CreateDeepCopy()); + main_list.Append(binary_value.CreateDeepCopy()); + main_list.Append(dict_value.CreateDeepCopy()); + main_list.Append(list_value.CreateDeepCopy()); + + EXPECT_TRUE(main_dict.Get("bool", NULL)); + EXPECT_TRUE(main_dict.Get("int", NULL)); + EXPECT_TRUE(main_dict.Get("double", NULL)); + EXPECT_TRUE(main_dict.Get("string", NULL)); + EXPECT_TRUE(main_dict.Get("binary", NULL)); + EXPECT_TRUE(main_dict.Get("dict", NULL)); + EXPECT_TRUE(main_dict.Get("list", NULL)); + EXPECT_FALSE(main_dict.Get("DNE", NULL)); + + EXPECT_TRUE(main_dict.GetBoolean("bool", NULL)); + EXPECT_FALSE(main_dict.GetBoolean("int", NULL)); + EXPECT_FALSE(main_dict.GetBoolean("double", NULL)); + EXPECT_FALSE(main_dict.GetBoolean("string", NULL)); + EXPECT_FALSE(main_dict.GetBoolean("binary", NULL)); + EXPECT_FALSE(main_dict.GetBoolean("dict", NULL)); + EXPECT_FALSE(main_dict.GetBoolean("list", NULL)); + EXPECT_FALSE(main_dict.GetBoolean("DNE", NULL)); + + EXPECT_FALSE(main_dict.GetInteger("bool", NULL)); + EXPECT_TRUE(main_dict.GetInteger("int", NULL)); + EXPECT_FALSE(main_dict.GetInteger("double", NULL)); + EXPECT_FALSE(main_dict.GetInteger("string", NULL)); + EXPECT_FALSE(main_dict.GetInteger("binary", NULL)); + EXPECT_FALSE(main_dict.GetInteger("dict", NULL)); + EXPECT_FALSE(main_dict.GetInteger("list", NULL)); + EXPECT_FALSE(main_dict.GetInteger("DNE", NULL)); + + // Both int and double values can be obtained from GetDouble. + EXPECT_FALSE(main_dict.GetDouble("bool", NULL)); + EXPECT_TRUE(main_dict.GetDouble("int", NULL)); + EXPECT_TRUE(main_dict.GetDouble("double", NULL)); + EXPECT_FALSE(main_dict.GetDouble("string", NULL)); + EXPECT_FALSE(main_dict.GetDouble("binary", NULL)); + EXPECT_FALSE(main_dict.GetDouble("dict", NULL)); + EXPECT_FALSE(main_dict.GetDouble("list", NULL)); + EXPECT_FALSE(main_dict.GetDouble("DNE", NULL)); + + EXPECT_FALSE(main_dict.GetString("bool", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetString("int", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetString("double", static_cast<std::string*>(NULL))); + EXPECT_TRUE(main_dict.GetString("string", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetString("binary", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetString("dict", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetString("list", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetString("DNE", static_cast<std::string*>(NULL))); + + EXPECT_FALSE(main_dict.GetBinary("bool", NULL)); + EXPECT_FALSE(main_dict.GetBinary("int", NULL)); + EXPECT_FALSE(main_dict.GetBinary("double", NULL)); + EXPECT_FALSE(main_dict.GetBinary("string", NULL)); + EXPECT_TRUE(main_dict.GetBinary("binary", NULL)); + EXPECT_FALSE(main_dict.GetBinary("dict", NULL)); + EXPECT_FALSE(main_dict.GetBinary("list", NULL)); + EXPECT_FALSE(main_dict.GetBinary("DNE", NULL)); + + EXPECT_FALSE(main_dict.GetDictionary("bool", NULL)); + EXPECT_FALSE(main_dict.GetDictionary("int", NULL)); + EXPECT_FALSE(main_dict.GetDictionary("double", NULL)); + EXPECT_FALSE(main_dict.GetDictionary("string", NULL)); + EXPECT_FALSE(main_dict.GetDictionary("binary", NULL)); + EXPECT_TRUE(main_dict.GetDictionary("dict", NULL)); + EXPECT_FALSE(main_dict.GetDictionary("list", NULL)); + EXPECT_FALSE(main_dict.GetDictionary("DNE", NULL)); + + EXPECT_FALSE(main_dict.GetList("bool", NULL)); + EXPECT_FALSE(main_dict.GetList("int", NULL)); + EXPECT_FALSE(main_dict.GetList("double", NULL)); + EXPECT_FALSE(main_dict.GetList("string", NULL)); + EXPECT_FALSE(main_dict.GetList("binary", NULL)); + EXPECT_FALSE(main_dict.GetList("dict", NULL)); + EXPECT_TRUE(main_dict.GetList("list", NULL)); + EXPECT_FALSE(main_dict.GetList("DNE", NULL)); + + EXPECT_TRUE(main_dict.GetWithoutPathExpansion("bool", NULL)); + EXPECT_TRUE(main_dict.GetWithoutPathExpansion("int", NULL)); + EXPECT_TRUE(main_dict.GetWithoutPathExpansion("double", NULL)); + EXPECT_TRUE(main_dict.GetWithoutPathExpansion("string", NULL)); + EXPECT_TRUE(main_dict.GetWithoutPathExpansion("binary", NULL)); + EXPECT_TRUE(main_dict.GetWithoutPathExpansion("dict", NULL)); + EXPECT_TRUE(main_dict.GetWithoutPathExpansion("list", NULL)); + EXPECT_FALSE(main_dict.GetWithoutPathExpansion("DNE", NULL)); + + EXPECT_TRUE(main_dict.GetBooleanWithoutPathExpansion("bool", NULL)); + EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("int", NULL)); + EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("double", NULL)); + EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("string", NULL)); + EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("binary", NULL)); + EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("dict", NULL)); + EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("list", NULL)); + EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("DNE", NULL)); + + EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("bool", NULL)); + EXPECT_TRUE(main_dict.GetIntegerWithoutPathExpansion("int", NULL)); + EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("double", NULL)); + EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("string", NULL)); + EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("binary", NULL)); + EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("dict", NULL)); + EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("list", NULL)); + EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("DNE", NULL)); + + EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("bool", NULL)); + EXPECT_TRUE(main_dict.GetDoubleWithoutPathExpansion("int", NULL)); + EXPECT_TRUE(main_dict.GetDoubleWithoutPathExpansion("double", NULL)); + EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("string", NULL)); + EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("binary", NULL)); + EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("dict", NULL)); + EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("list", NULL)); + EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("DNE", NULL)); + + EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( + "bool", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( + "int", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( + "double", static_cast<std::string*>(NULL))); + EXPECT_TRUE(main_dict.GetStringWithoutPathExpansion( + "string", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( + "binary", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( + "dict", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( + "list", static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion( + "DNE", static_cast<std::string*>(NULL))); + + // There is no GetBinaryWithoutPathExpansion for some reason, but if there + // were it should be tested here... + + EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("bool", NULL)); + EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("int", NULL)); + EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("double", NULL)); + EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("string", NULL)); + EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("binary", NULL)); + EXPECT_TRUE(main_dict.GetDictionaryWithoutPathExpansion("dict", NULL)); + EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("list", NULL)); + EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("DNE", NULL)); + + EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("bool", NULL)); + EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("int", NULL)); + EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("double", NULL)); + EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("string", NULL)); + EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("binary", NULL)); + EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("dict", NULL)); + EXPECT_TRUE(main_dict.GetListWithoutPathExpansion("list", NULL)); + EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("DNE", NULL)); + + EXPECT_TRUE(main_list.Get(0, NULL)); + EXPECT_TRUE(main_list.Get(1, NULL)); + EXPECT_TRUE(main_list.Get(2, NULL)); + EXPECT_TRUE(main_list.Get(3, NULL)); + EXPECT_TRUE(main_list.Get(4, NULL)); + EXPECT_TRUE(main_list.Get(5, NULL)); + EXPECT_TRUE(main_list.Get(6, NULL)); + EXPECT_FALSE(main_list.Get(7, NULL)); + + EXPECT_TRUE(main_list.GetBoolean(0, NULL)); + EXPECT_FALSE(main_list.GetBoolean(1, NULL)); + EXPECT_FALSE(main_list.GetBoolean(2, NULL)); + EXPECT_FALSE(main_list.GetBoolean(3, NULL)); + EXPECT_FALSE(main_list.GetBoolean(4, NULL)); + EXPECT_FALSE(main_list.GetBoolean(5, NULL)); + EXPECT_FALSE(main_list.GetBoolean(6, NULL)); + EXPECT_FALSE(main_list.GetBoolean(7, NULL)); + + EXPECT_FALSE(main_list.GetInteger(0, NULL)); + EXPECT_TRUE(main_list.GetInteger(1, NULL)); + EXPECT_FALSE(main_list.GetInteger(2, NULL)); + EXPECT_FALSE(main_list.GetInteger(3, NULL)); + EXPECT_FALSE(main_list.GetInteger(4, NULL)); + EXPECT_FALSE(main_list.GetInteger(5, NULL)); + EXPECT_FALSE(main_list.GetInteger(6, NULL)); + EXPECT_FALSE(main_list.GetInteger(7, NULL)); + + EXPECT_FALSE(main_list.GetDouble(0, NULL)); + EXPECT_TRUE(main_list.GetDouble(1, NULL)); + EXPECT_TRUE(main_list.GetDouble(2, NULL)); + EXPECT_FALSE(main_list.GetDouble(3, NULL)); + EXPECT_FALSE(main_list.GetDouble(4, NULL)); + EXPECT_FALSE(main_list.GetDouble(5, NULL)); + EXPECT_FALSE(main_list.GetDouble(6, NULL)); + EXPECT_FALSE(main_list.GetDouble(7, NULL)); + + EXPECT_FALSE(main_list.GetString(0, static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_list.GetString(1, static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_list.GetString(2, static_cast<std::string*>(NULL))); + EXPECT_TRUE(main_list.GetString(3, static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_list.GetString(4, static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_list.GetString(5, static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_list.GetString(6, static_cast<std::string*>(NULL))); + EXPECT_FALSE(main_list.GetString(7, static_cast<std::string*>(NULL))); + + EXPECT_FALSE(main_list.GetBinary(0, NULL)); + EXPECT_FALSE(main_list.GetBinary(1, NULL)); + EXPECT_FALSE(main_list.GetBinary(2, NULL)); + EXPECT_FALSE(main_list.GetBinary(3, NULL)); + EXPECT_TRUE(main_list.GetBinary(4, NULL)); + EXPECT_FALSE(main_list.GetBinary(5, NULL)); + EXPECT_FALSE(main_list.GetBinary(6, NULL)); + EXPECT_FALSE(main_list.GetBinary(7, NULL)); + + EXPECT_FALSE(main_list.GetDictionary(0, NULL)); + EXPECT_FALSE(main_list.GetDictionary(1, NULL)); + EXPECT_FALSE(main_list.GetDictionary(2, NULL)); + EXPECT_FALSE(main_list.GetDictionary(3, NULL)); + EXPECT_FALSE(main_list.GetDictionary(4, NULL)); + EXPECT_TRUE(main_list.GetDictionary(5, NULL)); + EXPECT_FALSE(main_list.GetDictionary(6, NULL)); + EXPECT_FALSE(main_list.GetDictionary(7, NULL)); + + EXPECT_FALSE(main_list.GetList(0, NULL)); + EXPECT_FALSE(main_list.GetList(1, NULL)); + EXPECT_FALSE(main_list.GetList(2, NULL)); + EXPECT_FALSE(main_list.GetList(3, NULL)); + EXPECT_FALSE(main_list.GetList(4, NULL)); + EXPECT_FALSE(main_list.GetList(5, NULL)); + EXPECT_TRUE(main_list.GetList(6, NULL)); + EXPECT_FALSE(main_list.GetList(7, NULL)); +} + +} // namespace base diff --git a/third_party/chromium/crypto/p224.cc b/third_party/chromium/crypto/p224.cc new file mode 100644 index 0000000..81bce3a --- /dev/null +++ b/third_party/chromium/crypto/p224.cc @@ -0,0 +1,768 @@ +// Copyright 2012 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is an implementation of the P224 elliptic curve group. It's written to +// be short and simple rather than fast, although it's still constant-time. +// +// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. + +#include "third_party/chromium/crypto/p224.h" + +#include <string.h> + +namespace crypto { +namespace p224 { + +namespace { + +inline uint32 ByteSwap(uint32 x) { + return ((x & 0x000000fful) << 24) | ((x & 0x0000ff00ul) << 8) | + ((x & 0x00ff0000ul) >> 8) | ((x & 0xff000000ul) >> 24); +} + +inline uint32 HostToNet32(uint32 x) { +#if defined(ARCH_CPU_LITTLE_ENDIAN) + return ByteSwap(x); +#else + return x; +#endif +} + +inline uint32 NetToHost32(uint32 x) { +#if defined(ARCH_CPU_LITTLE_ENDIAN) + return ByteSwap(x); +#else + return x; +#endif +} + +// Field element functions. +// +// The field that we're dealing with is ℤ/pℤ where p = 2**224 - 2**96 + 1. +// +// Field elements are represented by a FieldElement, which is a typedef to an +// array of 8 uint32's. The value of a FieldElement, a, is: +// a[0] + 2**28·a[1] + 2**56·a[1] + ... + 2**196·a[7] +// +// Using 28-bit limbs means that there's only 4 bits of headroom, which is less +// than we would really like. But it has the useful feature that we hit 2**224 +// exactly, making the reflections during a reduce much nicer. + +// kP is the P224 prime. +const FieldElement kP = { + 1, 0, 0, 268431360, + 268435455, 268435455, 268435455, 268435455, +}; + +void Contract(FieldElement* inout); + +// IsZero returns 0xffffffff if a == 0 mod p and 0 otherwise. +uint32 IsZero(const FieldElement& a) { + FieldElement minimal; + memcpy(&minimal, &a, sizeof(minimal)); + Contract(&minimal); + + uint32 is_zero = 0, is_p = 0; + for (unsigned i = 0; i < 8; i++) { + is_zero |= minimal[i]; + is_p |= minimal[i] - kP[i]; + } + + // If either is_zero or is_p is 0, then we should return 1. + is_zero |= is_zero >> 16; + is_zero |= is_zero >> 8; + is_zero |= is_zero >> 4; + is_zero |= is_zero >> 2; + is_zero |= is_zero >> 1; + + is_p |= is_p >> 16; + is_p |= is_p >> 8; + is_p |= is_p >> 4; + is_p |= is_p >> 2; + is_p |= is_p >> 1; + + // For is_zero and is_p, the LSB is 0 iff all the bits are zero. + is_zero &= is_p & 1; + is_zero = (~is_zero) << 31; + is_zero = static_cast<int32>(is_zero) >> 31; + return is_zero; +} + +// Add computes *out = a+b +// +// a[i] + b[i] < 2**32 +void Add(FieldElement* out, const FieldElement& a, const FieldElement& b) { + for (int i = 0; i < 8; i++) { + (*out)[i] = a[i] + b[i]; + } +} + +static const uint32 kTwo31p3 = (1u << 31) + (1u << 3); +static const uint32 kTwo31m3 = (1u << 31) - (1u << 3); +static const uint32 kTwo31m15m3 = (1u << 31) - (1u << 15) - (1u << 3); +// kZero31ModP is 0 mod p where bit 31 is set in all limbs so that we can +// subtract smaller amounts without underflow. See the section "Subtraction" in +// [1] for why. +static const FieldElement kZero31ModP = { + kTwo31p3, kTwo31m3, kTwo31m3, kTwo31m15m3, + kTwo31m3, kTwo31m3, kTwo31m3, kTwo31m3 +}; + +// Subtract computes *out = a-b +// +// a[i], b[i] < 2**30 +// out[i] < 2**32 +void Subtract(FieldElement* out, const FieldElement& a, const FieldElement& b) { + for (int i = 0; i < 8; i++) { + // See the section on "Subtraction" in [1] for details. + (*out)[i] = a[i] + kZero31ModP[i] - b[i]; + } +} + +static const uint64 kTwo63p35 = (1ull<<63) + (1ull<<35); +static const uint64 kTwo63m35 = (1ull<<63) - (1ull<<35); +static const uint64 kTwo63m35m19 = (1ull<<63) - (1ull<<35) - (1ull<<19); +// kZero63ModP is 0 mod p where bit 63 is set in all limbs. See the section +// "Subtraction" in [1] for why. +static const uint64 kZero63ModP[8] = { + kTwo63p35, kTwo63m35, kTwo63m35, kTwo63m35, + kTwo63m35m19, kTwo63m35, kTwo63m35, kTwo63m35, +}; + +static const uint32 kBottom28Bits = 0xfffffff; + +// LargeFieldElement also represents an element of the field. The limbs are +// still spaced 28-bits apart and in little-endian order. So the limbs are at +// 0, 28, 56, ..., 392 bits, each 64-bits wide. +typedef uint64 LargeFieldElement[15]; + +// ReduceLarge converts a LargeFieldElement to a FieldElement. +// +// in[i] < 2**62 + +// GCC 4.9 incorrectly vectorizes the first coefficient elimination loop, so +// disable that optimization via pragma. Don't use the pragma under Clang, since +// clang doesn't understand it. +// TODO(wez): Remove this when crbug.com/439566 is fixed. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC optimize("no-tree-vectorize") +#endif + +void ReduceLarge(FieldElement* out, LargeFieldElement* inptr) { + LargeFieldElement& in(*inptr); + + for (int i = 0; i < 8; i++) { + in[i] += kZero63ModP[i]; + } + + // Eliminate the coefficients at 2**224 and greater while maintaining the + // same value mod p. + for (int i = 14; i >= 8; i--) { + in[i-8] -= in[i]; // reflection off the "+1" term of p. + in[i-5] += (in[i] & 0xffff) << 12; // part of the "-2**96" reflection. + in[i-4] += in[i] >> 16; // the rest of the "-2**96" reflection. + } + in[8] = 0; + // in[0..8] < 2**64 + + // As the values become small enough, we start to store them in |out| and use + // 32-bit operations. + for (int i = 1; i < 8; i++) { + in[i+1] += in[i] >> 28; + (*out)[i] = static_cast<uint32>(in[i] & kBottom28Bits); + } + // Eliminate the term at 2*224 that we introduced while keeping the same + // value mod p. + in[0] -= in[8]; // reflection off the "+1" term of p. + (*out)[3] += static_cast<uint32>(in[8] & 0xffff) << 12; // "-2**96" term + (*out)[4] += static_cast<uint32>(in[8] >> 16); // rest of "-2**96" term + // in[0] < 2**64 + // out[3] < 2**29 + // out[4] < 2**29 + // out[1,2,5..7] < 2**28 + + (*out)[0] = static_cast<uint32>(in[0] & kBottom28Bits); + (*out)[1] += static_cast<uint32>((in[0] >> 28) & kBottom28Bits); + (*out)[2] += static_cast<uint32>(in[0] >> 56); + // out[0] < 2**28 + // out[1..4] < 2**29 + // out[5..7] < 2**28 +} + +// TODO(wez): Remove this when crbug.com/439566 is fixed. +#if defined(__GNUC__) && !defined(__clang__) +// Reenable "tree-vectorize" optimization if it got disabled for ReduceLarge. +#pragma GCC reset_options +#endif + +// Mul computes *out = a*b +// +// a[i] < 2**29, b[i] < 2**30 (or vice versa) +// out[i] < 2**29 +void Mul(FieldElement* out, const FieldElement& a, const FieldElement& b) { + LargeFieldElement tmp; + memset(&tmp, 0, sizeof(tmp)); + + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + tmp[i+j] += static_cast<uint64>(a[i]) * static_cast<uint64>(b[j]); + } + } + + ReduceLarge(out, &tmp); +} + +// Square computes *out = a*a +// +// a[i] < 2**29 +// out[i] < 2**29 +void Square(FieldElement* out, const FieldElement& a) { + LargeFieldElement tmp; + memset(&tmp, 0, sizeof(tmp)); + + for (int i = 0; i < 8; i++) { + for (int j = 0; j <= i; j++) { + uint64 r = static_cast<uint64>(a[i]) * static_cast<uint64>(a[j]); + if (i == j) { + tmp[i+j] += r; + } else { + tmp[i+j] += r << 1; + } + } + } + + ReduceLarge(out, &tmp); +} + +// Reduce reduces the coefficients of in_out to smaller bounds. +// +// On entry: a[i] < 2**31 + 2**30 +// On exit: a[i] < 2**29 +void Reduce(FieldElement* in_out) { + FieldElement& a = *in_out; + + for (int i = 0; i < 7; i++) { + a[i+1] += a[i] >> 28; + a[i] &= kBottom28Bits; + } + uint32 top = a[7] >> 28; + a[7] &= kBottom28Bits; + + // top < 2**4 + // Constant-time: mask = (top != 0) ? 0xffffffff : 0 + uint32 mask = top; + mask |= mask >> 2; + mask |= mask >> 1; + mask <<= 31; + mask = static_cast<uint32>(static_cast<int32>(mask) >> 31); + + // Eliminate top while maintaining the same value mod p. + a[0] -= top; + a[3] += top << 12; + + // We may have just made a[0] negative but, if we did, then we must + // have added something to a[3], thus it's > 2**12. Therefore we can + // carry down to a[0]. + a[3] -= 1 & mask; + a[2] += mask & ((1<<28) - 1); + a[1] += mask & ((1<<28) - 1); + a[0] += mask & (1<<28); +} + +// Invert calcuates *out = in**-1 by computing in**(2**224 - 2**96 - 1), i.e. +// Fermat's little theorem. +void Invert(FieldElement* out, const FieldElement& in) { + FieldElement f1, f2, f3, f4; + + Square(&f1, in); // 2 + Mul(&f1, f1, in); // 2**2 - 1 + Square(&f1, f1); // 2**3 - 2 + Mul(&f1, f1, in); // 2**3 - 1 + Square(&f2, f1); // 2**4 - 2 + Square(&f2, f2); // 2**5 - 4 + Square(&f2, f2); // 2**6 - 8 + Mul(&f1, f1, f2); // 2**6 - 1 + Square(&f2, f1); // 2**7 - 2 + for (int i = 0; i < 5; i++) { // 2**12 - 2**6 + Square(&f2, f2); + } + Mul(&f2, f2, f1); // 2**12 - 1 + Square(&f3, f2); // 2**13 - 2 + for (int i = 0; i < 11; i++) { // 2**24 - 2**12 + Square(&f3, f3); + } + Mul(&f2, f3, f2); // 2**24 - 1 + Square(&f3, f2); // 2**25 - 2 + for (int i = 0; i < 23; i++) { // 2**48 - 2**24 + Square(&f3, f3); + } + Mul(&f3, f3, f2); // 2**48 - 1 + Square(&f4, f3); // 2**49 - 2 + for (int i = 0; i < 47; i++) { // 2**96 - 2**48 + Square(&f4, f4); + } + Mul(&f3, f3, f4); // 2**96 - 1 + Square(&f4, f3); // 2**97 - 2 + for (int i = 0; i < 23; i++) { // 2**120 - 2**24 + Square(&f4, f4); + } + Mul(&f2, f4, f2); // 2**120 - 1 + for (int i = 0; i < 6; i++) { // 2**126 - 2**6 + Square(&f2, f2); + } + Mul(&f1, f1, f2); // 2**126 - 1 + Square(&f1, f1); // 2**127 - 2 + Mul(&f1, f1, in); // 2**127 - 1 + for (int i = 0; i < 97; i++) { // 2**224 - 2**97 + Square(&f1, f1); + } + Mul(out, f1, f3); // 2**224 - 2**96 - 1 +} + +// Contract converts a FieldElement to its minimal, distinguished form. +// +// On entry, in[i] < 2**29 +// On exit, in[i] < 2**28 +void Contract(FieldElement* inout) { + FieldElement& out = *inout; + + // Reduce the coefficients to < 2**28. + for (int i = 0; i < 7; i++) { + out[i+1] += out[i] >> 28; + out[i] &= kBottom28Bits; + } + uint32 top = out[7] >> 28; + out[7] &= kBottom28Bits; + + // Eliminate top while maintaining the same value mod p. + out[0] -= top; + out[3] += top << 12; + + // We may just have made out[0] negative. So we carry down. If we made + // out[0] negative then we know that out[3] is sufficiently positive + // because we just added to it. + for (int i = 0; i < 3; i++) { + uint32 mask = static_cast<uint32>(static_cast<int32>(out[i]) >> 31); + out[i] += (1 << 28) & mask; + out[i+1] -= 1 & mask; + } + + // We might have pushed out[3] over 2**28 so we perform another, partial + // carry chain. + for (int i = 3; i < 7; i++) { + out[i+1] += out[i] >> 28; + out[i] &= kBottom28Bits; + } + top = out[7] >> 28; + out[7] &= kBottom28Bits; + + // Eliminate top while maintaining the same value mod p. + out[0] -= top; + out[3] += top << 12; + + // There are two cases to consider for out[3]: + // 1) The first time that we eliminated top, we didn't push out[3] over + // 2**28. In this case, the partial carry chain didn't change any values + // and top is zero. + // 2) We did push out[3] over 2**28 the first time that we eliminated top. + // The first value of top was in [0..16), therefore, prior to eliminating + // the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after + // overflowing and being reduced by the second carry chain, out[3] <= + // 0xf000. Thus it cannot have overflowed when we eliminated top for the + // second time. + + // Again, we may just have made out[0] negative, so do the same carry down. + // As before, if we made out[0] negative then we know that out[3] is + // sufficiently positive. + for (int i = 0; i < 3; i++) { + uint32 mask = static_cast<uint32>(static_cast<int32>(out[i]) >> 31); + out[i] += (1 << 28) & mask; + out[i+1] -= 1 & mask; + } + + // The value is < 2**224, but maybe greater than p. In order to reduce to a + // unique, minimal value we see if the value is >= p and, if so, subtract p. + + // First we build a mask from the top four limbs, which must all be + // equal to bottom28Bits if the whole value is >= p. If top_4_all_ones + // ends up with any zero bits in the bottom 28 bits, then this wasn't + // true. + uint32 top_4_all_ones = 0xffffffffu; + for (int i = 4; i < 8; i++) { + top_4_all_ones &= out[i]; + } + top_4_all_ones |= 0xf0000000; + // Now we replicate any zero bits to all the bits in top_4_all_ones. + top_4_all_ones &= top_4_all_ones >> 16; + top_4_all_ones &= top_4_all_ones >> 8; + top_4_all_ones &= top_4_all_ones >> 4; + top_4_all_ones &= top_4_all_ones >> 2; + top_4_all_ones &= top_4_all_ones >> 1; + top_4_all_ones = + static_cast<uint32>(static_cast<int32>(top_4_all_ones << 31) >> 31); + + // Now we test whether the bottom three limbs are non-zero. + uint32 bottom_3_non_zero = out[0] | out[1] | out[2]; + bottom_3_non_zero |= bottom_3_non_zero >> 16; + bottom_3_non_zero |= bottom_3_non_zero >> 8; + bottom_3_non_zero |= bottom_3_non_zero >> 4; + bottom_3_non_zero |= bottom_3_non_zero >> 2; + bottom_3_non_zero |= bottom_3_non_zero >> 1; + bottom_3_non_zero = + static_cast<uint32>(static_cast<int32>(bottom_3_non_zero) >> 31); + + // Everything depends on the value of out[3]. + // If it's > 0xffff000 and top_4_all_ones != 0 then the whole value is >= p + // If it's = 0xffff000 and top_4_all_ones != 0 and bottom_3_non_zero != 0, + // then the whole value is >= p + // If it's < 0xffff000, then the whole value is < p + uint32 n = out[3] - 0xffff000; + uint32 out_3_equal = n; + out_3_equal |= out_3_equal >> 16; + out_3_equal |= out_3_equal >> 8; + out_3_equal |= out_3_equal >> 4; + out_3_equal |= out_3_equal >> 2; + out_3_equal |= out_3_equal >> 1; + out_3_equal = + ~static_cast<uint32>(static_cast<int32>(out_3_equal << 31) >> 31); + + // If out[3] > 0xffff000 then n's MSB will be zero. + uint32 out_3_gt = ~static_cast<uint32>(static_cast<int32>(n << 31) >> 31); + + uint32 mask = top_4_all_ones & ((out_3_equal & bottom_3_non_zero) | out_3_gt); + out[0] -= 1 & mask; + out[3] -= 0xffff000 & mask; + out[4] -= 0xfffffff & mask; + out[5] -= 0xfffffff & mask; + out[6] -= 0xfffffff & mask; + out[7] -= 0xfffffff & mask; +} + + +// Group element functions. +// +// These functions deal with group elements. The group is an elliptic curve +// group with a = -3 defined in FIPS 186-3, section D.2.2. + +// kB is parameter of the elliptic curve. +const FieldElement kB = { + 55967668, 11768882, 265861671, 185302395, + 39211076, 180311059, 84673715, 188764328, +}; + +void CopyConditional(Point* out, const Point& a, uint32 mask); +void DoubleJacobian(Point* out, const Point& a); + +// AddJacobian computes *out = a+b where a != b. +void AddJacobian(Point *out, + const Point& a, + const Point& b) { + // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl + FieldElement z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v; + + uint32 z1_is_zero = IsZero(a.z); + uint32 z2_is_zero = IsZero(b.z); + + // Z1Z1 = Z1² + Square(&z1z1, a.z); + + // Z2Z2 = Z2² + Square(&z2z2, b.z); + + // U1 = X1*Z2Z2 + Mul(&u1, a.x, z2z2); + + // U2 = X2*Z1Z1 + Mul(&u2, b.x, z1z1); + + // S1 = Y1*Z2*Z2Z2 + Mul(&s1, b.z, z2z2); + Mul(&s1, a.y, s1); + + // S2 = Y2*Z1*Z1Z1 + Mul(&s2, a.z, z1z1); + Mul(&s2, b.y, s2); + + // H = U2-U1 + Subtract(&h, u2, u1); + Reduce(&h); + uint32 x_equal = IsZero(h); + + // I = (2*H)² + for (int k = 0; k < 8; k++) { + i[k] = h[k] << 1; + } + Reduce(&i); + Square(&i, i); + + // J = H*I + Mul(&j, h, i); + // r = 2*(S2-S1) + Subtract(&r, s2, s1); + Reduce(&r); + uint32 y_equal = IsZero(r); + + if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) { + // The two input points are the same therefore we must use the dedicated + // doubling function as the slope of the line is undefined. + DoubleJacobian(out, a); + return; + } + + for (int k = 0; k < 8; k++) { + r[k] <<= 1; + } + Reduce(&r); + + // V = U1*I + Mul(&v, u1, i); + + // Z3 = ((Z1+Z2)²-Z1Z1-Z2Z2)*H + Add(&z1z1, z1z1, z2z2); + Add(&z2z2, a.z, b.z); + Reduce(&z2z2); + Square(&z2z2, z2z2); + Subtract(&out->z, z2z2, z1z1); + Reduce(&out->z); + Mul(&out->z, out->z, h); + + // X3 = r²-J-2*V + for (int k = 0; k < 8; k++) { + z1z1[k] = v[k] << 1; + } + Add(&z1z1, j, z1z1); + Reduce(&z1z1); + Square(&out->x, r); + Subtract(&out->x, out->x, z1z1); + Reduce(&out->x); + + // Y3 = r*(V-X3)-2*S1*J + for (int k = 0; k < 8; k++) { + s1[k] <<= 1; + } + Mul(&s1, s1, j); + Subtract(&z1z1, v, out->x); + Reduce(&z1z1); + Mul(&z1z1, z1z1, r); + Subtract(&out->y, z1z1, s1); + Reduce(&out->y); + + CopyConditional(out, a, z2_is_zero); + CopyConditional(out, b, z1_is_zero); +} + +// DoubleJacobian computes *out = a+a. +void DoubleJacobian(Point* out, const Point& a) { + // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + FieldElement delta, gamma, beta, alpha, t; + + Square(&delta, a.z); + Square(&gamma, a.y); + Mul(&beta, a.x, gamma); + + // alpha = 3*(X1-delta)*(X1+delta) + Add(&t, a.x, delta); + for (int i = 0; i < 8; i++) { + t[i] += t[i] << 1; + } + Reduce(&t); + Subtract(&alpha, a.x, delta); + Reduce(&alpha); + Mul(&alpha, alpha, t); + + // Z3 = (Y1+Z1)²-gamma-delta + Add(&out->z, a.y, a.z); + Reduce(&out->z); + Square(&out->z, out->z); + Subtract(&out->z, out->z, gamma); + Reduce(&out->z); + Subtract(&out->z, out->z, delta); + Reduce(&out->z); + + // X3 = alpha²-8*beta + for (int i = 0; i < 8; i++) { + delta[i] = beta[i] << 3; + } + Reduce(&delta); + Square(&out->x, alpha); + Subtract(&out->x, out->x, delta); + Reduce(&out->x); + + // Y3 = alpha*(4*beta-X3)-8*gamma² + for (int i = 0; i < 8; i++) { + beta[i] <<= 2; + } + Reduce(&beta); + Subtract(&beta, beta, out->x); + Reduce(&beta); + Square(&gamma, gamma); + for (int i = 0; i < 8; i++) { + gamma[i] <<= 3; + } + Reduce(&gamma); + Mul(&out->y, alpha, beta); + Subtract(&out->y, out->y, gamma); + Reduce(&out->y); +} + +// CopyConditional sets *out=a if mask is 0xffffffff. mask must be either 0 of +// 0xffffffff. +void CopyConditional(Point* out, + const Point& a, + uint32 mask) { + for (int i = 0; i < 8; i++) { + out->x[i] ^= mask & (a.x[i] ^ out->x[i]); + out->y[i] ^= mask & (a.y[i] ^ out->y[i]); + out->z[i] ^= mask & (a.z[i] ^ out->z[i]); + } +} + +// ScalarMult calculates *out = a*scalar where scalar is a big-endian number of +// length scalar_len and != 0. +void ScalarMult(Point* out, const Point& a, + const uint8* scalar, size_t scalar_len) { + memset(out, 0, sizeof(*out)); + Point tmp; + + for (size_t i = 0; i < scalar_len; i++) { + for (unsigned int bit_num = 0; bit_num < 8; bit_num++) { + DoubleJacobian(out, *out); + uint32 bit = static_cast<uint32>(static_cast<int32>( + (((scalar[i] >> (7 - bit_num)) & 1) << 31) >> 31)); + AddJacobian(&tmp, a, *out); + CopyConditional(out, tmp, bit); + } + } +} + +// Get224Bits reads 7 words from in and scatters their contents in +// little-endian form into 8 words at out, 28 bits per output word. +void Get224Bits(uint32* out, const uint32* in) { + out[0] = NetToHost32(in[6]) & kBottom28Bits; + out[1] = ((NetToHost32(in[5]) << 4) | + (NetToHost32(in[6]) >> 28)) & kBottom28Bits; + out[2] = ((NetToHost32(in[4]) << 8) | + (NetToHost32(in[5]) >> 24)) & kBottom28Bits; + out[3] = ((NetToHost32(in[3]) << 12) | + (NetToHost32(in[4]) >> 20)) & kBottom28Bits; + out[4] = ((NetToHost32(in[2]) << 16) | + (NetToHost32(in[3]) >> 16)) & kBottom28Bits; + out[5] = ((NetToHost32(in[1]) << 20) | + (NetToHost32(in[2]) >> 12)) & kBottom28Bits; + out[6] = ((NetToHost32(in[0]) << 24) | + (NetToHost32(in[1]) >> 8)) & kBottom28Bits; + out[7] = (NetToHost32(in[0]) >> 4) & kBottom28Bits; +} + +// Put224Bits performs the inverse operation to Get224Bits: taking 28 bits from +// each of 8 input words and writing them in big-endian order to 7 words at +// out. +void Put224Bits(uint32* out, const uint32* in) { + out[6] = HostToNet32((in[0] >> 0) | (in[1] << 28)); + out[5] = HostToNet32((in[1] >> 4) | (in[2] << 24)); + out[4] = HostToNet32((in[2] >> 8) | (in[3] << 20)); + out[3] = HostToNet32((in[3] >> 12) | (in[4] << 16)); + out[2] = HostToNet32((in[4] >> 16) | (in[5] << 12)); + out[1] = HostToNet32((in[5] >> 20) | (in[6] << 8)); + out[0] = HostToNet32((in[6] >> 24) | (in[7] << 4)); +} + +} // anonymous namespace + +bool Point::SetFromString(const std::string& in) { + if (in.size() != 2*28) + return false; + const uint32* inwords = reinterpret_cast<const uint32*>(in.data()); + Get224Bits(x, inwords); + Get224Bits(y, inwords + 7); + memset(&z, 0, sizeof(z)); + z[0] = 1; + + // Check that the point is on the curve, i.e. that y² = x³ - 3x + b. + FieldElement lhs; + Square(&lhs, y); + Contract(&lhs); + + FieldElement rhs; + Square(&rhs, x); + Mul(&rhs, x, rhs); + + FieldElement three_x; + for (int i = 0; i < 8; i++) { + three_x[i] = x[i] * 3; + } + Reduce(&three_x); + Subtract(&rhs, rhs, three_x); + Reduce(&rhs); + + Add(&rhs, rhs, kB); + Contract(&rhs); + return memcmp(&lhs, &rhs, sizeof(lhs)) == 0; +} + +std::string Point::ToString() const { + FieldElement zinv, zinv_sq, xx, yy; + + // If this is the point at infinity we return a string of all zeros. + if (IsZero(this->z)) { + static const char zeros[56] = {0}; + return std::string(zeros, sizeof(zeros)); + } + + Invert(&zinv, this->z); + Square(&zinv_sq, zinv); + Mul(&xx, x, zinv_sq); + Mul(&zinv_sq, zinv_sq, zinv); + Mul(&yy, y, zinv_sq); + + Contract(&xx); + Contract(&yy); + + uint32 outwords[14]; + Put224Bits(outwords, xx); + Put224Bits(outwords + 7, yy); + return std::string(reinterpret_cast<const char*>(outwords), sizeof(outwords)); +} + +void ScalarMult(const Point& in, const uint8* scalar, Point* out) { + ScalarMult(out, in, scalar, 28); +} + +// kBasePoint is the base point (generator) of the elliptic curve group. +static const Point kBasePoint = { + {22813985, 52956513, 34677300, 203240812, + 12143107, 133374265, 225162431, 191946955}, + {83918388, 223877528, 122119236, 123340192, + 266784067, 263504429, 146143011, 198407736}, + {1, 0, 0, 0, 0, 0, 0, 0}, +}; + +void ScalarBaseMult(const uint8* scalar, Point* out) { + ScalarMult(out, kBasePoint, scalar, 28); +} + +void Add(const Point& a, const Point& b, Point* out) { + AddJacobian(out, a, b); +} + +void Negate(const Point& in, Point* out) { + // Guide to elliptic curve cryptography, page 89 suggests that (X : X+Y : Z) + // is the negative in Jacobian coordinates, but it doesn't actually appear to + // be true in testing so this performs the negation in affine coordinates. + FieldElement zinv, zinv_sq, y; + Invert(&zinv, in.z); + Square(&zinv_sq, zinv); + Mul(&out->x, in.x, zinv_sq); + Mul(&zinv_sq, zinv_sq, zinv); + Mul(&y, in.y, zinv_sq); + + Subtract(&out->y, kP, y); + Reduce(&out->y); + + memset(&out->z, 0, sizeof(out->z)); + out->z[0] = 1; +} + +} // namespace p224 +} // namespace crypto diff --git a/third_party/chromium/crypto/p224.h b/third_party/chromium/crypto/p224.h new file mode 100644 index 0000000..7574389 --- /dev/null +++ b/third_party/chromium/crypto/p224.h @@ -0,0 +1,57 @@ +// Copyright 2012 The Chromium OS 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 LIBWEAVE_THIRD_PARTY_CHROMIUM_P224_H_ +#define LIBWEAVE_THIRD_PARTY_CHROMIUM_P224_H_ + +#include <string> + +#include <base/basictypes.h> + +namespace crypto { + +// P224 implements an elliptic curve group, commonly known as P224 and defined +// in FIPS 186-3, section D.2.2. +namespace p224 { + +// An element of the field (ℤ/pℤ) is represented with 8, 28-bit limbs in +// little endian order. +typedef uint32 FieldElement[8]; + +struct Point { + // SetFromString the value of the point from the 56 byte, external + // representation. The external point representation is an (x, y) pair of a + // point on the curve. Each field element is represented as a big-endian + // number < p. + bool SetFromString(const std::string& in); + + // ToString returns an external representation of the Point. + std::string ToString() const; + + // An Point is represented in Jacobian form (x/z², y/z³). + FieldElement x, y, z; +}; + +// kScalarBytes is the number of bytes needed to represent an element of the +// P224 field. +static const size_t kScalarBytes = 28; + +// ScalarMult computes *out = in*scalar where scalar is a 28-byte, big-endian +// number. +void ScalarMult(const Point& in, const uint8* scalar, Point* out); + +// ScalarBaseMult computes *out = g*scalar where g is the base point of the +// curve and scalar is a 28-byte, big-endian number. +void ScalarBaseMult(const uint8* scalar, Point* out); + +// Add computes *out = a+b. +void Add(const Point& a, const Point& b, Point* out); + +// Negate calculates out = -a; +void Negate(const Point& a, Point* out); + +} // namespace p224 +} // namespace crypto + +#endif // LIBWEAVE_THIRD_PARTY_CHROMIUM_P224_H_ diff --git a/third_party/chromium/crypto/p224_spake.cc b/third_party/chromium/crypto/p224_spake.cc new file mode 100644 index 0000000..6d82322 --- /dev/null +++ b/third_party/chromium/crypto/p224_spake.cc @@ -0,0 +1,284 @@ +// Copyright 2012 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This code implements SPAKE2, a variant of EKE: +// http://www.di.ens.fr/~pointche/pub.php?reference=AbPo04 + +#include "third_party/chromium/crypto/p224_spake.h" + +#include <algorithm> + +#include <base/logging.h> +#include <base/rand_util.h> + +#include "third_party/chromium/crypto/p224.h" + +namespace crypto { + +namespace { + +// The following two points (M and N in the protocol) are verifiable random +// points on the curve and can be generated with the following code: + +// #include <stdint.h> +// #include <stdio.h> +// #include <string.h> +// +// #include <openssl/ec.h> +// #include <openssl/obj_mac.h> +// #include <openssl/sha.h> +// +// static const char kSeed1[] = "P224 point generation seed (M)"; +// static const char kSeed2[] = "P224 point generation seed (N)"; +// +// void find_seed(const char* seed) { +// SHA256_CTX sha256; +// uint8_t digest[SHA256_DIGEST_LENGTH]; +// +// SHA256_Init(&sha256); +// SHA256_Update(&sha256, seed, strlen(seed)); +// SHA256_Final(digest, &sha256); +// +// BIGNUM x, y; +// EC_GROUP* p224 = EC_GROUP_new_by_curve_name(NID_secp224r1); +// EC_POINT* p = EC_POINT_new(p224); +// +// for (unsigned i = 0;; i++) { +// BN_init(&x); +// BN_bin2bn(digest, 28, &x); +// +// if (EC_POINT_set_compressed_coordinates_GFp( +// p224, p, &x, digest[28] & 1, NULL)) { +// BN_init(&y); +// EC_POINT_get_affine_coordinates_GFp(p224, p, &x, &y, NULL); +// char* x_str = BN_bn2hex(&x); +// char* y_str = BN_bn2hex(&y); +// printf("Found after %u iterations:\n%s\n%s\n", i, x_str, y_str); +// OPENSSL_free(x_str); +// OPENSSL_free(y_str); +// BN_free(&x); +// BN_free(&y); +// break; +// } +// +// SHA256_Init(&sha256); +// SHA256_Update(&sha256, digest, sizeof(digest)); +// SHA256_Final(digest, &sha256); +// +// BN_free(&x); +// } +// +// EC_POINT_free(p); +// EC_GROUP_free(p224); +// } +// +// int main() { +// find_seed(kSeed1); +// find_seed(kSeed2); +// return 0; +// } + +const p224::Point kM = { + {174237515, 77186811, 235213682, 33849492, + 33188520, 48266885, 177021753, 81038478}, + {104523827, 245682244, 266509668, 236196369, + 28372046, 145351378, 198520366, 113345994}, + {1, 0, 0, 0, 0, 0, 0, 0}, +}; + +const p224::Point kN = { + {136176322, 263523628, 251628795, 229292285, + 5034302, 185981975, 171998428, 11653062}, + {197567436, 51226044, 60372156, 175772188, + 42075930, 8083165, 160827401, 65097570}, + {1, 0, 0, 0, 0, 0, 0, 0}, +}; + +// Performs a constant-time comparison of two strings, returning true if the +// strings are equal. +// +// For cryptographic operations, comparison functions such as memcmp() may +// expose side-channel information about input, allowing an attacker to +// perform timing analysis to determine what the expected bits should be. In +// order to avoid such attacks, the comparison must execute in constant time, +// so as to not to reveal to the attacker where the difference(s) are. +// For an example attack, see +// http://groups.google.com/group/keyczar-discuss/browse_thread/thread/5571eca0948b2a13 +bool SecureMemEqual(const uint8_t* s1_ptr, const uint8_t* s2_ptr, size_t n) { + uint8_t tmp = 0; + for (size_t i = 0; i < n; ++i, ++s1_ptr, ++s2_ptr) + tmp |= *s1_ptr ^ *s2_ptr; + return (tmp == 0); +} + +} // anonymous namespace + +P224EncryptedKeyExchange::P224EncryptedKeyExchange(PeerType peer_type, + const std::string& password) + : state_(kStateInitial), is_server_(peer_type == kPeerTypeServer) { + memset(&x_, 0, sizeof(x_)); + memset(&expected_authenticator_, 0, sizeof(expected_authenticator_)); + + // x_ is a random scalar. + base::RandBytes(x_, sizeof(x_)); + + // Calculate |password| hash to get SPAKE password value. + SHA256HashString(std::string(password.data(), password.length()), + pw_, sizeof(pw_)); + + Init(); +} + +void P224EncryptedKeyExchange::Init() { + // X = g**x_ + p224::Point X; + p224::ScalarBaseMult(x_, &X); + + // The client masks the Diffie-Hellman value, X, by adding M**pw and the + // server uses N**pw. + p224::Point MNpw; + p224::ScalarMult(is_server_ ? kN : kM, pw_, &MNpw); + + // X* = X + (N|M)**pw + p224::Point Xstar; + p224::Add(X, MNpw, &Xstar); + + next_message_ = Xstar.ToString(); +} + +const std::string& P224EncryptedKeyExchange::GetNextMessage() { + if (state_ == kStateInitial) { + state_ = kStateRecvDH; + return next_message_; + } else if (state_ == kStateSendHash) { + state_ = kStateRecvHash; + return next_message_; + } + + LOG(FATAL) << "P224EncryptedKeyExchange::GetNextMessage called in" + " bad state " << state_; + next_message_ = ""; + return next_message_; +} + +P224EncryptedKeyExchange::Result P224EncryptedKeyExchange::ProcessMessage( + const std::string& message) { + if (state_ == kStateRecvHash) { + // This is the final state of the protocol: we are reading the peer's + // authentication hash and checking that it matches the one that we expect. + if (message.size() != sizeof(expected_authenticator_)) { + error_ = "peer's hash had an incorrect size"; + return kResultFailed; + } + if (!SecureMemEqual(reinterpret_cast<const uint8_t*>(message.data()), + expected_authenticator_, message.size())) { + error_ = "peer's hash had incorrect value"; + return kResultFailed; + } + state_ = kStateDone; + return kResultSuccess; + } + + if (state_ != kStateRecvDH) { + LOG(FATAL) << "P224EncryptedKeyExchange::ProcessMessage called in" + " bad state " << state_; + error_ = "internal error"; + return kResultFailed; + } + + // Y* is the other party's masked, Diffie-Hellman value. + p224::Point Ystar; + if (!Ystar.SetFromString(message)) { + error_ = "failed to parse peer's masked Diffie-Hellman value"; + return kResultFailed; + } + + // We calculate the mask value: (N|M)**pw + p224::Point MNpw, minus_MNpw, Y, k; + p224::ScalarMult(is_server_ ? kM : kN, pw_, &MNpw); + p224::Negate(MNpw, &minus_MNpw); + + // Y = Y* - (N|M)**pw + p224::Add(Ystar, minus_MNpw, &Y); + + // K = Y**x_ + p224::ScalarMult(Y, x_, &k); + + // If everything worked out, then K is the same for both parties. + key_ = k.ToString(); + + std::string client_masked_dh, server_masked_dh; + if (is_server_) { + client_masked_dh = message; + server_masked_dh = next_message_; + } else { + client_masked_dh = next_message_; + server_masked_dh = message; + } + + // Now we calculate the hashes that each side will use to prove to the other + // that they derived the correct value for K. + uint8 client_hash[kSHA256Length], server_hash[kSHA256Length]; + CalculateHash(kPeerTypeClient, client_masked_dh, server_masked_dh, key_, + client_hash); + CalculateHash(kPeerTypeServer, client_masked_dh, server_masked_dh, key_, + server_hash); + + const uint8* my_hash = is_server_ ? server_hash : client_hash; + const uint8* their_hash = is_server_ ? client_hash : server_hash; + + next_message_ = + std::string(reinterpret_cast<const char*>(my_hash), kSHA256Length); + memcpy(expected_authenticator_, their_hash, kSHA256Length); + state_ = kStateSendHash; + return kResultPending; +} + +void P224EncryptedKeyExchange::CalculateHash( + PeerType peer_type, + const std::string& client_masked_dh, + const std::string& server_masked_dh, + const std::string& k, + uint8* out_digest) { + std::string hash_contents; + + if (peer_type == kPeerTypeServer) { + hash_contents = "server"; + } else { + hash_contents = "client"; + } + + hash_contents += client_masked_dh; + hash_contents += server_masked_dh; + hash_contents += + std::string(reinterpret_cast<const char *>(pw_), sizeof(pw_)); + hash_contents += k; + + SHA256HashString(hash_contents, out_digest, kSHA256Length); +} + +const std::string& P224EncryptedKeyExchange::error() const { + return error_; +} + +const std::string& P224EncryptedKeyExchange::GetKey() const { + DCHECK_EQ(state_, kStateDone); + return GetUnverifiedKey(); +} + +const std::string& P224EncryptedKeyExchange::GetUnverifiedKey() const { + // Key is already final when state is kStateSendHash. Subsequent states are + // used only for verification of the key. Some users may combine verification + // with sending verifiable data instead of |expected_authenticator_|. + DCHECK_GE(state_, kStateSendHash); + return key_; +} + +void P224EncryptedKeyExchange::SetXForTesting(const std::string& x) { + memset(&x_, 0, sizeof(x_)); + memcpy(&x_, x.data(), std::min(x.size(), sizeof(x_))); + Init(); +} + +} // namespace crypto diff --git a/third_party/chromium/crypto/p224_spake.h b/third_party/chromium/crypto/p224_spake.h new file mode 100644 index 0000000..dcfd0fe --- /dev/null +++ b/third_party/chromium/crypto/p224_spake.h @@ -0,0 +1,126 @@ +// Copyright 2012 The Chromium OS 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 LIBWEAVE_THIRD_PARTY_CHROMIUM_P224_SPAKE_H_ + +#include <string> + +#include <base/gtest_prod_util.h> + +#include "third_party/chromium/crypto/p224.h" +#include "third_party/chromium/crypto/sha2.h" + +namespace crypto { + +// P224EncryptedKeyExchange implements SPAKE2, a variant of Encrypted +// Key Exchange. It allows two parties that have a secret common +// password to establish a common secure key by exchanging messages +// over an insecure channel without disclosing the password. +// +// The password can be low entropy as authenticating with an attacker only +// gives the attacker a one-shot password oracle. No other information about +// the password is leaked. (However, you must be sure to limit the number of +// permitted authentication attempts otherwise they get many one-shot oracles.) +// +// The protocol requires several RTTs (actually two, but you shouldn't assume +// that.) To use the object, call GetNextMessage() and pass that message to the +// peer. Get a message from the peer and feed it into ProcessMessage. Then +// examine the return value of ProcessMessage: +// kResultPending: Another round is required. Call GetNextMessage and repeat. +// kResultFailed: The authentication has failed. You can get a human readable +// error message by calling error(). +// kResultSuccess: The authentication was successful. +// +// In each exchange, each peer always sends a message. +class P224EncryptedKeyExchange { + public: + enum Result { + kResultPending, + kResultFailed, + kResultSuccess, + }; + + // PeerType's values are named client and server due to convention. But + // they could be called "A" and "B" as far as the protocol is concerned so + // long as the two parties don't both get the same label. + enum PeerType { + kPeerTypeClient, + kPeerTypeServer, + }; + + // peer_type: the type of the local authentication party. + // password: secret session password. Both parties to the + // authentication must pass the same value. For the case of a + // TLS connection, see RFC 5705. + P224EncryptedKeyExchange(PeerType peer_type, const std::string& password); + + // GetNextMessage returns a byte string which must be passed to the other + // party in the authentication. + const std::string& GetNextMessage(); + + // ProcessMessage processes a message which must have been generated by a + // call to GetNextMessage() by the other party. + Result ProcessMessage(const std::string& message); + + // In the event that ProcessMessage() returns kResultFailed, error will + // return a human readable error message. + const std::string& error() const; + + // The key established as result of the key exchange. Must be called + // at then end after ProcessMessage() returns kResultSuccess. + const std::string& GetKey() const; + + // The key established as result of the key exchange. Can be called after + // the first ProcessMessage() + const std::string& GetUnverifiedKey() const; + + private: + // The authentication state machine is very simple and each party proceeds + // through each of these states, in order. + enum State { + kStateInitial, + kStateRecvDH, + kStateSendHash, + kStateRecvHash, + kStateDone, + }; + + FRIEND_TEST_ALL_PREFIXES(MutualAuth, ExpectedValues); + + void Init(); + + // Sets internal random scalar. Should be used by tests only. + void SetXForTesting(const std::string& x); + + State state_; + const bool is_server_; + // next_message_ contains a value for GetNextMessage() to return. + std::string next_message_; + std::string error_; + + // CalculateHash computes the verification hash for the given peer and writes + // |kSHA256Length| bytes at |out_digest|. + void CalculateHash( + PeerType peer_type, + const std::string& client_masked_dh, + const std::string& server_masked_dh, + const std::string& k, + uint8* out_digest); + + // x_ is the secret Diffie-Hellman exponent (see paper referenced in .cc + // file). + uint8 x_[p224::kScalarBytes]; + // pw_ is SHA256(P(password), P(session))[:28] where P() prepends a uint32, + // big-endian length prefix (see paper referenced in .cc file). + uint8 pw_[p224::kScalarBytes]; + // expected_authenticator_ is used to store the hash value expected from the + // other party. + uint8 expected_authenticator_[kSHA256Length]; + + std::string key_; +}; + +} // namespace crypto + +#endif // LIBWEAVE_THIRD_PARTY_CHROMIUM_P224_SPAKE_H_ diff --git a/third_party/chromium/crypto/p224_spake_unittest.cc b/third_party/chromium/crypto/p224_spake_unittest.cc new file mode 100644 index 0000000..9a9f9d2 --- /dev/null +++ b/third_party/chromium/crypto/p224_spake_unittest.cc @@ -0,0 +1,174 @@ +// Copyright 2011 The Chromium OS 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 "third_party/chromium/crypto/p224_spake.h" + +#include <string> + +#include <base/logging.h> +#include <base/strings/string_number_conversions.h> +#include <gtest/gtest.h> + +namespace crypto { + +namespace { + +std::string HexEncodeString(const std::string& binary_data) { + return base::HexEncode(binary_data.c_str(), binary_data.size()); +} + +bool RunExchange(P224EncryptedKeyExchange* client, + P224EncryptedKeyExchange* server, + bool is_password_same) { + for (;;) { + std::string client_message, server_message; + client_message = client->GetNextMessage(); + server_message = server->GetNextMessage(); + + P224EncryptedKeyExchange::Result client_result, server_result; + client_result = client->ProcessMessage(server_message); + server_result = server->ProcessMessage(client_message); + + // Check that we never hit the case where only one succeeds. + EXPECT_EQ(client_result == P224EncryptedKeyExchange::kResultSuccess, + server_result == P224EncryptedKeyExchange::kResultSuccess); + + if (client_result == P224EncryptedKeyExchange::kResultFailed || + server_result == P224EncryptedKeyExchange::kResultFailed) { + return false; + } + + EXPECT_EQ(is_password_same, + client->GetUnverifiedKey() == server->GetUnverifiedKey()); + + if (client_result == P224EncryptedKeyExchange::kResultSuccess && + server_result == P224EncryptedKeyExchange::kResultSuccess) { + return true; + } + + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, client_result); + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, server_result); + } +} + +const char kPassword[] = "foo"; + +} // namespace + +TEST(MutualAuth, CorrectAuth) { + P224EncryptedKeyExchange client( + P224EncryptedKeyExchange::kPeerTypeClient, kPassword); + P224EncryptedKeyExchange server( + P224EncryptedKeyExchange::kPeerTypeServer, kPassword); + + EXPECT_TRUE(RunExchange(&client, &server, true)); + EXPECT_EQ(client.GetKey(), server.GetKey()); +} + +TEST(MutualAuth, IncorrectPassword) { + P224EncryptedKeyExchange client( + P224EncryptedKeyExchange::kPeerTypeClient, + kPassword); + P224EncryptedKeyExchange server( + P224EncryptedKeyExchange::kPeerTypeServer, + "wrongpassword"); + + EXPECT_FALSE(RunExchange(&client, &server, false)); +} + +TEST(MutualAuth, ExpectedValues) { + P224EncryptedKeyExchange client(P224EncryptedKeyExchange::kPeerTypeClient, + kPassword); + client.SetXForTesting("Client x"); + P224EncryptedKeyExchange server(P224EncryptedKeyExchange::kPeerTypeServer, + kPassword); + server.SetXForTesting("Server x"); + + std::string client_message = client.GetNextMessage(); + EXPECT_EQ( + "3508EF7DECC8AB9F9C439FBB0154288BBECC0A82E8448F4CF29554EB" + "BE9D486686226255EAD1D077C635B1A41F46AC91D7F7F32CED9EC3E0", + HexEncodeString(client_message)); + + std::string server_message = server.GetNextMessage(); + EXPECT_EQ( + "A3088C18B75D2C2B107105661AEC85424777475EB29F1DDFB8C14AFB" + "F1603D0DF38413A00F420ACF2059E7997C935F5A957A193D09A2B584", + HexEncodeString(server_message)); + + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, + client.ProcessMessage(server_message)); + EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, + server.ProcessMessage(client_message)); + + EXPECT_EQ(client.GetUnverifiedKey(), server.GetUnverifiedKey()); + // Must stay the same. External implementations should be able to pair with. + EXPECT_EQ( + "CE7CCFC435CDA4F01EC8826788B1F8B82EF7D550A34696B371096E64" + "C487D4FE193F7D1A6FF6820BC7F807796BA3889E8F999BBDEFC32FFA", + HexEncodeString(server.GetUnverifiedKey())); + + EXPECT_TRUE(RunExchange(&client, &server, true)); + EXPECT_EQ(client.GetKey(), server.GetKey()); +} + +TEST(MutualAuth, Fuzz) { + static const unsigned kIterations = 40; + + for (unsigned i = 0; i < kIterations; i++) { + P224EncryptedKeyExchange client( + P224EncryptedKeyExchange::kPeerTypeClient, kPassword); + P224EncryptedKeyExchange server( + P224EncryptedKeyExchange::kPeerTypeServer, kPassword); + + // We'll only be testing small values of i, but we don't want that to bias + // the test coverage. So we disperse the value of i by multiplying by the + // FNV, 32-bit prime, producing a poor-man's PRNG. + const uint32 rand = i * 16777619; + + for (unsigned round = 0;; round++) { + std::string client_message, server_message; + client_message = client.GetNextMessage(); + server_message = server.GetNextMessage(); + + if ((rand & 1) == round) { + const bool server_or_client = rand & 2; + std::string* m = server_or_client ? &server_message : &client_message; + if (rand & 4) { + // Truncate + *m = m->substr(0, (i >> 3) % m->size()); + } else { + // Corrupt + const size_t bits = m->size() * 8; + const size_t bit_to_corrupt = (rand >> 3) % bits; + const_cast<char*>(m->data())[bit_to_corrupt / 8] ^= + 1 << (bit_to_corrupt % 8); + } + } + + P224EncryptedKeyExchange::Result client_result, server_result; + client_result = client.ProcessMessage(server_message); + server_result = server.ProcessMessage(client_message); + + // If we have corrupted anything, we expect the authentication to fail, + // although one side can succeed if we happen to corrupt the second round + // message to the other. + ASSERT_FALSE( + client_result == P224EncryptedKeyExchange::kResultSuccess && + server_result == P224EncryptedKeyExchange::kResultSuccess); + + if (client_result == P224EncryptedKeyExchange::kResultFailed || + server_result == P224EncryptedKeyExchange::kResultFailed) { + break; + } + + ASSERT_EQ(P224EncryptedKeyExchange::kResultPending, + client_result); + ASSERT_EQ(P224EncryptedKeyExchange::kResultPending, + server_result); + } + } +} + +} // namespace crypto diff --git a/third_party/chromium/crypto/p224_unittest.cc b/third_party/chromium/crypto/p224_unittest.cc new file mode 100644 index 0000000..0540dbb --- /dev/null +++ b/third_party/chromium/crypto/p224_unittest.cc @@ -0,0 +1,824 @@ +// Copyright 2012 The Chromium OS 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 "third_party/chromium/crypto/p224.h" + +#include <stdio.h> +#include <string.h> + +#include <gtest/gtest.h> + +namespace crypto { + +using p224::Point; + +// kBasePointExternal is the P224 base point in external representation. +static const uint8 kBasePointExternal[56] = { + 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, + 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, + 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, + 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, + 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, + 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, + 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34, +}; + +// TestVector represents a test of scalar multiplication of the base point. +// |scalar| is a big-endian scalar and |affine| is the external representation +// of g*scalar. +struct TestVector { + uint8 scalar[28]; + uint8 affine[28*2]; +}; + +static const int kNumNISTTestVectors = 52; + +// kNISTTestVectors are the NIST test vectors for P224. +static const TestVector kNISTTestVectors[kNumNISTTestVectors] = { + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01}, + {0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, + 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, + 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, + 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, + 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, + 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, + 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34 + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, }, + + {0x70, 0x6a, 0x46, 0xdc, 0x76, 0xdc, 0xb7, 0x67, + 0x98, 0xe6, 0x0e, 0x6d, 0x89, 0x47, 0x47, 0x88, + 0xd1, 0x6d, 0xc1, 0x80, 0x32, 0xd2, 0x68, 0xfd, + 0x1a, 0x70, 0x4f, 0xa6, 0x1c, 0x2b, 0x76, 0xa7, + 0xbc, 0x25, 0xe7, 0x70, 0x2a, 0x70, 0x4f, 0xa9, + 0x86, 0x89, 0x28, 0x49, 0xfc, 0xa6, 0x29, 0x48, + 0x7a, 0xcf, 0x37, 0x09, 0xd2, 0xe4, 0xe8, 0xbb, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, }, + {0xdf, 0x1b, 0x1d, 0x66, 0xa5, 0x51, 0xd0, 0xd3, + 0x1e, 0xff, 0x82, 0x25, 0x58, 0xb9, 0xd2, 0xcc, + 0x75, 0xc2, 0x18, 0x02, 0x79, 0xfe, 0x0d, 0x08, + 0xfd, 0x89, 0x6d, 0x04, 0xa3, 0xf7, 0xf0, 0x3c, + 0xad, 0xd0, 0xbe, 0x44, 0x4c, 0x0a, 0xa5, 0x68, + 0x30, 0x13, 0x0d, 0xdf, 0x77, 0xd3, 0x17, 0x34, + 0x4e, 0x1a, 0xf3, 0x59, 0x19, 0x81, 0xa9, 0x25, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, }, + {0xae, 0x99, 0xfe, 0xeb, 0xb5, 0xd2, 0x69, 0x45, + 0xb5, 0x48, 0x92, 0x09, 0x2a, 0x8a, 0xee, 0x02, + 0x91, 0x29, 0x30, 0xfa, 0x41, 0xcd, 0x11, 0x4e, + 0x40, 0x44, 0x73, 0x01, 0x04, 0x82, 0x58, 0x0a, + 0x0e, 0xc5, 0xbc, 0x47, 0xe8, 0x8b, 0xc8, 0xc3, + 0x78, 0x63, 0x2c, 0xd1, 0x96, 0xcb, 0x3f, 0xa0, + 0x58, 0xa7, 0x11, 0x4e, 0xb0, 0x30, 0x54, 0xc9, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, }, + {0x31, 0xc4, 0x9a, 0xe7, 0x5b, 0xce, 0x78, 0x07, + 0xcd, 0xff, 0x22, 0x05, 0x5d, 0x94, 0xee, 0x90, + 0x21, 0xfe, 0xdb, 0xb5, 0xab, 0x51, 0xc5, 0x75, + 0x26, 0xf0, 0x11, 0xaa, 0x27, 0xe8, 0xbf, 0xf1, + 0x74, 0x56, 0x35, 0xec, 0x5b, 0xa0, 0xc9, 0xf1, + 0xc2, 0xed, 0xe1, 0x54, 0x14, 0xc6, 0x50, 0x7d, + 0x29, 0xff, 0xe3, 0x7e, 0x79, 0x0a, 0x07, 0x9b, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, }, + {0x1f, 0x24, 0x83, 0xf8, 0x25, 0x72, 0x25, 0x1f, + 0xca, 0x97, 0x5f, 0xea, 0x40, 0xdb, 0x82, 0x1d, + 0xf8, 0xad, 0x82, 0xa3, 0xc0, 0x02, 0xee, 0x6c, + 0x57, 0x11, 0x24, 0x08, 0x89, 0xfa, 0xf0, 0xcc, + 0xb7, 0x50, 0xd9, 0x9b, 0x55, 0x3c, 0x57, 0x4f, + 0xad, 0x7e, 0xcf, 0xb0, 0x43, 0x85, 0x86, 0xeb, + 0x39, 0x52, 0xaf, 0x5b, 0x4b, 0x15, 0x3c, 0x7e, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, }, + {0xdb, 0x2f, 0x6b, 0xe6, 0x30, 0xe2, 0x46, 0xa5, + 0xcf, 0x7d, 0x99, 0xb8, 0x51, 0x94, 0xb1, 0x23, + 0xd4, 0x87, 0xe2, 0xd4, 0x66, 0xb9, 0x4b, 0x24, + 0xa0, 0x3c, 0x3e, 0x28, 0x0f, 0x3a, 0x30, 0x08, + 0x54, 0x97, 0xf2, 0xf6, 0x11, 0xee, 0x25, 0x17, + 0xb1, 0x63, 0xef, 0x8c, 0x53, 0xb7, 0x15, 0xd1, + 0x8b, 0xb4, 0xe4, 0x80, 0x8d, 0x02, 0xb9, 0x63, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, }, + {0x85, 0x8e, 0x6f, 0x9c, 0xc6, 0xc1, 0x2c, 0x31, + 0xf5, 0xdf, 0x12, 0x4a, 0xa7, 0x77, 0x67, 0xb0, + 0x5c, 0x8b, 0xc0, 0x21, 0xbd, 0x68, 0x3d, 0x2b, + 0x55, 0x57, 0x15, 0x50, 0x04, 0x6d, 0xcd, 0x3e, + 0xa5, 0xc4, 0x38, 0x98, 0xc5, 0xc5, 0xfc, 0x4f, + 0xda, 0xc7, 0xdb, 0x39, 0xc2, 0xf0, 0x2e, 0xbe, + 0xe4, 0xe3, 0x54, 0x1d, 0x1e, 0x78, 0x04, 0x7a, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, }, + {0x2f, 0xdc, 0xcc, 0xfe, 0xe7, 0x20, 0xa7, 0x7e, + 0xf6, 0xcb, 0x3b, 0xfb, 0xb4, 0x47, 0xf9, 0x38, + 0x31, 0x17, 0xe3, 0xda, 0xa4, 0xa0, 0x7e, 0x36, + 0xed, 0x15, 0xf7, 0x8d, 0x37, 0x17, 0x32, 0xe4, + 0xf4, 0x1b, 0xf4, 0xf7, 0x88, 0x30, 0x35, 0xe6, + 0xa7, 0x9f, 0xce, 0xdc, 0x0e, 0x19, 0x6e, 0xb0, + 0x7b, 0x48, 0x17, 0x16, 0x97, 0x51, 0x74, 0x63, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, }, + {0xae, 0xa9, 0xe1, 0x7a, 0x30, 0x65, 0x17, 0xeb, + 0x89, 0x15, 0x2a, 0xa7, 0x09, 0x6d, 0x2c, 0x38, + 0x1e, 0xc8, 0x13, 0xc5, 0x1a, 0xa8, 0x80, 0xe7, + 0xbe, 0xe2, 0xc0, 0xfd, 0x39, 0xbb, 0x30, 0xea, + 0xb3, 0x37, 0xe0, 0xa5, 0x21, 0xb6, 0xcb, 0xa1, + 0xab, 0xe4, 0xb2, 0xb3, 0xa3, 0xe5, 0x24, 0xc1, + 0x4a, 0x3f, 0xe3, 0xeb, 0x11, 0x6b, 0x65, 0x5f, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0b, }, + {0xef, 0x53, 0xb6, 0x29, 0x4a, 0xca, 0x43, 0x1f, + 0x0f, 0x3c, 0x22, 0xdc, 0x82, 0xeb, 0x90, 0x50, + 0x32, 0x4f, 0x1d, 0x88, 0xd3, 0x77, 0xe7, 0x16, + 0x44, 0x8e, 0x50, 0x7c, 0x20, 0xb5, 0x10, 0x00, + 0x40, 0x92, 0xe9, 0x66, 0x36, 0xcf, 0xb7, 0xe3, + 0x2e, 0xfd, 0xed, 0x82, 0x65, 0xc2, 0x66, 0xdf, + 0xb7, 0x54, 0xfa, 0x6d, 0x64, 0x91, 0xa6, 0xda, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, }, + {0x6e, 0x31, 0xee, 0x1d, 0xc1, 0x37, 0xf8, 0x1b, + 0x05, 0x67, 0x52, 0xe4, 0xde, 0xab, 0x14, 0x43, + 0xa4, 0x81, 0x03, 0x3e, 0x9b, 0x4c, 0x93, 0xa3, + 0x04, 0x4f, 0x4f, 0x7a, 0x20, 0x7d, 0xdd, 0xf0, + 0x38, 0x5b, 0xfd, 0xea, 0xb6, 0xe9, 0xac, 0xda, + 0x8d, 0xa0, 0x6b, 0x3b, 0xbe, 0xf2, 0x24, 0xa9, + 0x3a, 0xb1, 0xe9, 0xe0, 0x36, 0x10, 0x9d, 0x13, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0d, }, + {0x34, 0xe8, 0xe1, 0x7a, 0x43, 0x0e, 0x43, 0x28, + 0x97, 0x93, 0xc3, 0x83, 0xfa, 0xc9, 0x77, 0x42, + 0x47, 0xb4, 0x0e, 0x9e, 0xbd, 0x33, 0x66, 0x98, + 0x1f, 0xcf, 0xae, 0xca, 0x25, 0x28, 0x19, 0xf7, + 0x1c, 0x7f, 0xb7, 0xfb, 0xcb, 0x15, 0x9b, 0xe3, + 0x37, 0xd3, 0x7d, 0x33, 0x36, 0xd7, 0xfe, 0xb9, + 0x63, 0x72, 0x4f, 0xdf, 0xb0, 0xec, 0xb7, 0x67, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0e, }, + {0xa5, 0x36, 0x40, 0xc8, 0x3d, 0xc2, 0x08, 0x60, + 0x3d, 0xed, 0x83, 0xe4, 0xec, 0xf7, 0x58, 0xf2, + 0x4c, 0x35, 0x7d, 0x7c, 0xf4, 0x80, 0x88, 0xb2, + 0xce, 0x01, 0xe9, 0xfa, 0xd5, 0x81, 0x4c, 0xd7, + 0x24, 0x19, 0x9c, 0x4a, 0x5b, 0x97, 0x4a, 0x43, + 0x68, 0x5f, 0xbf, 0x5b, 0x8b, 0xac, 0x69, 0x45, + 0x9c, 0x94, 0x69, 0xbc, 0x8f, 0x23, 0xcc, 0xaf, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, }, + {0xba, 0xa4, 0xd8, 0x63, 0x55, 0x11, 0xa7, 0xd2, + 0x88, 0xae, 0xbe, 0xed, 0xd1, 0x2c, 0xe5, 0x29, + 0xff, 0x10, 0x2c, 0x91, 0xf9, 0x7f, 0x86, 0x7e, + 0x21, 0x91, 0x6b, 0xf9, 0x97, 0x9a, 0x5f, 0x47, + 0x59, 0xf8, 0x0f, 0x4f, 0xb4, 0xec, 0x2e, 0x34, + 0xf5, 0x56, 0x6d, 0x59, 0x56, 0x80, 0xa1, 0x17, + 0x35, 0xe7, 0xb6, 0x10, 0x46, 0x12, 0x79, 0x89, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, }, + {0x0b, 0x6e, 0xc4, 0xfe, 0x17, 0x77, 0x38, 0x24, + 0x04, 0xef, 0x67, 0x99, 0x97, 0xba, 0x8d, 0x1c, + 0xc5, 0xcd, 0x8e, 0x85, 0x34, 0x92, 0x59, 0xf5, + 0x90, 0xc4, 0xc6, 0x6d, 0x33, 0x99, 0xd4, 0x64, + 0x34, 0x59, 0x06, 0xb1, 0x1b, 0x00, 0xe3, 0x63, + 0xef, 0x42, 0x92, 0x21, 0xf2, 0xec, 0x72, 0x0d, + 0x2f, 0x66, 0x5d, 0x7d, 0xea, 0xd5, 0xb4, 0x82, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x11, }, + {0xb8, 0x35, 0x7c, 0x3a, 0x6c, 0xee, 0xf2, 0x88, + 0x31, 0x0e, 0x17, 0xb8, 0xbf, 0xef, 0xf9, 0x20, + 0x08, 0x46, 0xca, 0x8c, 0x19, 0x42, 0x49, 0x7c, + 0x48, 0x44, 0x03, 0xbc, 0xff, 0x14, 0x9e, 0xfa, + 0x66, 0x06, 0xa6, 0xbd, 0x20, 0xef, 0x7d, 0x1b, + 0x06, 0xbd, 0x92, 0xf6, 0x90, 0x46, 0x39, 0xdc, + 0xe5, 0x17, 0x4d, 0xb6, 0xcc, 0x55, 0x4a, 0x26, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x12, }, + {0xc9, 0xff, 0x61, 0xb0, 0x40, 0x87, 0x4c, 0x05, + 0x68, 0x47, 0x92, 0x16, 0x82, 0x4a, 0x15, 0xea, + 0xb1, 0xa8, 0x38, 0xa7, 0x97, 0xd1, 0x89, 0x74, + 0x62, 0x26, 0xe4, 0xcc, 0xea, 0x98, 0xd6, 0x0e, + 0x5f, 0xfc, 0x9b, 0x8f, 0xcf, 0x99, 0x9f, 0xab, + 0x1d, 0xf7, 0xe7, 0xef, 0x70, 0x84, 0xf2, 0x0d, + 0xdb, 0x61, 0xbb, 0x04, 0x5a, 0x6c, 0xe0, 0x02, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x13, }, + {0xa1, 0xe8, 0x1c, 0x04, 0xf3, 0x0c, 0xe2, 0x01, + 0xc7, 0xc9, 0xac, 0xe7, 0x85, 0xed, 0x44, 0xcc, + 0x33, 0xb4, 0x55, 0xa0, 0x22, 0xf2, 0xac, 0xdb, + 0xc6, 0xca, 0xe8, 0x3c, 0xdc, 0xf1, 0xf6, 0xc3, + 0xdb, 0x09, 0xc7, 0x0a, 0xcc, 0x25, 0x39, 0x1d, + 0x49, 0x2f, 0xe2, 0x5b, 0x4a, 0x18, 0x0b, 0xab, + 0xd6, 0xce, 0xa3, 0x56, 0xc0, 0x47, 0x19, 0xcd, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x14, }, + {0xfc, 0xc7, 0xf2, 0xb4, 0x5d, 0xf1, 0xcd, 0x5a, + 0x3c, 0x0c, 0x07, 0x31, 0xca, 0x47, 0xa8, 0xaf, + 0x75, 0xcf, 0xb0, 0x34, 0x7e, 0x83, 0x54, 0xee, + 0xfe, 0x78, 0x24, 0x55, 0x0d, 0x5d, 0x71, 0x10, + 0x27, 0x4c, 0xba, 0x7c, 0xde, 0xe9, 0x0e, 0x1a, + 0x8b, 0x0d, 0x39, 0x4c, 0x37, 0x6a, 0x55, 0x73, + 0xdb, 0x6b, 0xe0, 0xbf, 0x27, 0x47, 0xf5, 0x30, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x8e, 0xbb, 0xb9, + 0x5e, 0xed, 0x0e, 0x13, }, + {0x61, 0xf0, 0x77, 0xc6, 0xf6, 0x2e, 0xd8, 0x02, + 0xda, 0xd7, 0xc2, 0xf3, 0x8f, 0x5c, 0x67, 0xf2, + 0xcc, 0x45, 0x36, 0x01, 0xe6, 0x1b, 0xd0, 0x76, + 0xbb, 0x46, 0x17, 0x9e, 0x22, 0x72, 0xf9, 0xe9, + 0xf5, 0x93, 0x3e, 0x70, 0x38, 0x8e, 0xe6, 0x52, + 0x51, 0x34, 0x43, 0xb5, 0xe2, 0x89, 0xdd, 0x13, + 0x5d, 0xcc, 0x0d, 0x02, 0x99, 0xb2, 0x25, 0xe4, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x9d, 0x89, + 0x3d, 0x4c, 0xdd, 0x74, 0x72, 0x46, 0xcd, 0xca, + 0x43, 0x59, 0x0e, 0x13, }, + {0x02, 0x98, 0x95, 0xf0, 0xaf, 0x49, 0x6b, 0xfc, + 0x62, 0xb6, 0xef, 0x8d, 0x8a, 0x65, 0xc8, 0x8c, + 0x61, 0x39, 0x49, 0xb0, 0x36, 0x68, 0xaa, 0xb4, + 0xf0, 0x42, 0x9e, 0x35, 0x3e, 0xa6, 0xe5, 0x3f, + 0x9a, 0x84, 0x1f, 0x20, 0x19, 0xec, 0x24, 0xbd, + 0xe1, 0xa7, 0x56, 0x77, 0xaa, 0x9b, 0x59, 0x02, + 0xe6, 0x10, 0x81, 0xc0, 0x10, 0x64, 0xde, 0x93, + }, + }, + { + {0x41, 0xff, 0xc1, 0xff, 0xff, 0xfe, 0x01, 0xff, + 0xfc, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x07, 0xc0, + 0x01, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xf0, 0x7f, + 0xfe, 0x00, 0x07, 0xc0, }, + {0xab, 0x68, 0x99, 0x30, 0xbc, 0xae, 0x4a, 0x4a, + 0xa5, 0xf5, 0xcb, 0x08, 0x5e, 0x82, 0x3e, 0x8a, + 0xe3, 0x0f, 0xd3, 0x65, 0xeb, 0x1d, 0xa4, 0xab, + 0xa9, 0xcf, 0x03, 0x79, 0x33, 0x45, 0xa1, 0x21, + 0xbb, 0xd2, 0x33, 0x54, 0x8a, 0xf0, 0xd2, 0x10, + 0x65, 0x4e, 0xb4, 0x0b, 0xab, 0x78, 0x8a, 0x03, + 0x66, 0x64, 0x19, 0xbe, 0x6f, 0xbd, 0x34, 0xe7, + }, + }, + { + {0x7f, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xc0, 0x03, + 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0xff, }, + {0xbd, 0xb6, 0xa8, 0x81, 0x7c, 0x1f, 0x89, 0xda, + 0x1c, 0x2f, 0x3d, 0xd8, 0xe9, 0x7f, 0xeb, 0x44, + 0x94, 0xf2, 0xed, 0x30, 0x2a, 0x4c, 0xe2, 0xbc, + 0x7f, 0x5f, 0x40, 0x25, 0x4c, 0x70, 0x20, 0xd5, + 0x7c, 0x00, 0x41, 0x18, 0x89, 0x46, 0x2d, 0x77, + 0xa5, 0x43, 0x8b, 0xb4, 0xe9, 0x7d, 0x17, 0x77, + 0x00, 0xbf, 0x72, 0x43, 0xa0, 0x7f, 0x16, 0x80, + }, + }, + { + {0x7f, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xf8, 0xff, 0xff, + 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, + 0x00, 0x0f, 0xff, 0xff, }, + {0xd5, 0x8b, 0x61, 0xaa, 0x41, 0xc3, 0x2d, 0xd5, + 0xeb, 0xa4, 0x62, 0x64, 0x7d, 0xba, 0x75, 0xc5, + 0xd6, 0x7c, 0x83, 0x60, 0x6c, 0x0a, 0xf2, 0xbd, + 0x92, 0x84, 0x46, 0xa9, 0xd2, 0x4b, 0xa6, 0xa8, + 0x37, 0xbe, 0x04, 0x60, 0xdd, 0x10, 0x7a, 0xe7, + 0x77, 0x25, 0x69, 0x6d, 0x21, 0x14, 0x46, 0xc5, + 0x60, 0x9b, 0x45, 0x95, 0x97, 0x6b, 0x16, 0xbd, + }, + }, + { + {0x7f, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xfe, 0x3f, + 0xff, 0xfc, 0x10, 0x00, 0x00, 0x20, 0x00, 0x3f, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x3f, 0xff, 0xff, 0xff, }, + {0xdc, 0x9f, 0xa7, 0x79, 0x78, 0xa0, 0x05, 0x51, + 0x09, 0x80, 0xe9, 0x29, 0xa1, 0x48, 0x5f, 0x63, + 0x71, 0x6d, 0xf6, 0x95, 0xd7, 0xa0, 0xc1, 0x8b, + 0xb5, 0x18, 0xdf, 0x03, 0xed, 0xe2, 0xb0, 0x16, + 0xf2, 0xdd, 0xff, 0xc2, 0xa8, 0xc0, 0x15, 0xb1, + 0x34, 0x92, 0x82, 0x75, 0xce, 0x09, 0xe5, 0x66, + 0x1b, 0x7a, 0xb1, 0x4c, 0xe0, 0xd1, 0xd4, 0x03, + }, + }, + { + {0x70, 0x01, 0xf0, 0x00, 0x1c, 0x00, 0x01, 0xc0, + 0x00, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x00, 0x00, + 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xc0, 0x00, + 0x00, 0x01, 0xfc, 0x00, }, + {0x49, 0x9d, 0x8b, 0x28, 0x29, 0xcf, 0xb8, 0x79, + 0xc9, 0x01, 0xf7, 0xd8, 0x5d, 0x35, 0x70, 0x45, + 0xed, 0xab, 0x55, 0x02, 0x88, 0x24, 0xd0, 0xf0, + 0x5b, 0xa2, 0x79, 0xba, 0xbf, 0x92, 0x95, 0x37, + 0xb0, 0x6e, 0x40, 0x15, 0x91, 0x96, 0x39, 0xd9, + 0x4f, 0x57, 0x83, 0x8f, 0xa3, 0x3f, 0xc3, 0xd9, + 0x52, 0x59, 0x8d, 0xcd, 0xbb, 0x44, 0xd6, 0x38, + }, + }, + { + {0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, + 0x00, 0xff, 0xf0, 0x30, 0x00, 0x1f, 0x00, 0x00, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, }, + {0x82, 0x46, 0xc9, 0x99, 0x13, 0x71, 0x86, 0x63, + 0x2c, 0x5f, 0x9e, 0xdd, 0xf3, 0xb1, 0xb0, 0xe1, + 0x76, 0x4c, 0x5e, 0x8b, 0xd0, 0xe0, 0xd8, 0xa5, + 0x54, 0xb9, 0xcb, 0x77, 0xe8, 0x0e, 0xd8, 0x66, + 0x0b, 0xc1, 0xcb, 0x17, 0xac, 0x7d, 0x84, 0x5b, + 0xe4, 0x0a, 0x7a, 0x02, 0x2d, 0x33, 0x06, 0xf1, + 0x16, 0xae, 0x9f, 0x81, 0xfe, 0xa6, 0x59, 0x47, + }, + }, + { + {0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xfe, 0x08, 0x00, 0x00, 0x1f, + 0xf0, 0x00, 0x1f, 0xff, }, + {0x66, 0x70, 0xc2, 0x0a, 0xfc, 0xce, 0xae, 0xa6, + 0x72, 0xc9, 0x7f, 0x75, 0xe2, 0xe9, 0xdd, 0x5c, + 0x84, 0x60, 0xe5, 0x4b, 0xb3, 0x85, 0x38, 0xeb, + 0xb4, 0xbd, 0x30, 0xeb, 0xf2, 0x80, 0xd8, 0x00, + 0x8d, 0x07, 0xa4, 0xca, 0xf5, 0x42, 0x71, 0xf9, + 0x93, 0x52, 0x7d, 0x46, 0xff, 0x3f, 0xf4, 0x6f, + 0xd1, 0x19, 0x0a, 0x3f, 0x1f, 0xaa, 0x4f, 0x74, + }, + }, + { + {0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, }, + {0x00, 0x0e, 0xca, 0x93, 0x42, 0x47, 0x42, 0x5c, + 0xfd, 0x94, 0x9b, 0x79, 0x5c, 0xb5, 0xce, 0x1e, + 0xff, 0x40, 0x15, 0x50, 0x38, 0x6e, 0x28, 0xd1, + 0xa4, 0xc5, 0xa8, 0xeb, 0xd4, 0xc0, 0x10, 0x40, + 0xdb, 0xa1, 0x96, 0x28, 0x93, 0x1b, 0xc8, 0x85, + 0x53, 0x70, 0x31, 0x7c, 0x72, 0x2c, 0xbd, 0x9c, + 0xa6, 0x15, 0x69, 0x85, 0xf1, 0xc2, 0xe9, 0xce, + }, + }, + { + {0x7f, 0xff, 0xfc, 0x03, 0xff, 0x80, 0x7f, 0xff, + 0xe0, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x0f, 0xff, + 0x80, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, + 0xff, 0xfe, 0x00, 0x1f, }, + {0xef, 0x35, 0x3b, 0xf5, 0xc7, 0x3c, 0xd5, 0x51, + 0xb9, 0x6d, 0x59, 0x6f, 0xbc, 0x9a, 0x67, 0xf1, + 0x6d, 0x61, 0xdd, 0x9f, 0xe5, 0x6a, 0xf1, 0x9d, + 0xe1, 0xfb, 0xa9, 0xcd, 0x21, 0x77, 0x1b, 0x9c, + 0xdc, 0xe3, 0xe8, 0x43, 0x0c, 0x09, 0xb3, 0x83, + 0x8b, 0xe7, 0x0b, 0x48, 0xc2, 0x1e, 0x15, 0xbc, + 0x09, 0xee, 0x1f, 0x2d, 0x79, 0x45, 0xb9, 0x1f, + }, + }, + { + {0x00, 0x00, 0x00, 0x07, 0xff, 0xc0, 0x7f, 0xff, + 0xff, 0xff, 0x01, 0xff, 0xfe, 0x03, 0xff, 0xfe, + 0x40, 0x00, 0x38, 0x00, 0x07, 0xe0, 0x00, 0x3f, + 0xfe, 0x00, 0x00, 0x00, }, + {0x40, 0x36, 0x05, 0x2a, 0x30, 0x91, 0xeb, 0x48, + 0x10, 0x46, 0xad, 0x32, 0x89, 0xc9, 0x5d, 0x3a, + 0xc9, 0x05, 0xca, 0x00, 0x23, 0xde, 0x2c, 0x03, + 0xec, 0xd4, 0x51, 0xcf, 0xd7, 0x68, 0x16, 0x5a, + 0x38, 0xa2, 0xb9, 0x6f, 0x81, 0x25, 0x86, 0xa9, + 0xd5, 0x9d, 0x41, 0x36, 0x03, 0x5d, 0x9c, 0x85, + 0x3a, 0x5b, 0xf2, 0xe1, 0xc8, 0x6a, 0x49, 0x93, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x29, }, + {0xfc, 0xc7, 0xf2, 0xb4, 0x5d, 0xf1, 0xcd, 0x5a, + 0x3c, 0x0c, 0x07, 0x31, 0xca, 0x47, 0xa8, 0xaf, + 0x75, 0xcf, 0xb0, 0x34, 0x7e, 0x83, 0x54, 0xee, + 0xfe, 0x78, 0x24, 0x55, 0xf2, 0xa2, 0x8e, 0xef, + 0xd8, 0xb3, 0x45, 0x83, 0x21, 0x16, 0xf1, 0xe5, + 0x74, 0xf2, 0xc6, 0xb2, 0xc8, 0x95, 0xaa, 0x8c, + 0x24, 0x94, 0x1f, 0x40, 0xd8, 0xb8, 0x0a, 0xd1, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x2a, }, + {0xa1, 0xe8, 0x1c, 0x04, 0xf3, 0x0c, 0xe2, 0x01, + 0xc7, 0xc9, 0xac, 0xe7, 0x85, 0xed, 0x44, 0xcc, + 0x33, 0xb4, 0x55, 0xa0, 0x22, 0xf2, 0xac, 0xdb, + 0xc6, 0xca, 0xe8, 0x3c, 0x23, 0x0e, 0x09, 0x3c, + 0x24, 0xf6, 0x38, 0xf5, 0x33, 0xda, 0xc6, 0xe2, + 0xb6, 0xd0, 0x1d, 0xa3, 0xb5, 0xe7, 0xf4, 0x54, + 0x29, 0x31, 0x5c, 0xa9, 0x3f, 0xb8, 0xe6, 0x34, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x2b, }, + {0xc9, 0xff, 0x61, 0xb0, 0x40, 0x87, 0x4c, 0x05, + 0x68, 0x47, 0x92, 0x16, 0x82, 0x4a, 0x15, 0xea, + 0xb1, 0xa8, 0x38, 0xa7, 0x97, 0xd1, 0x89, 0x74, + 0x62, 0x26, 0xe4, 0xcc, 0x15, 0x67, 0x29, 0xf1, + 0xa0, 0x03, 0x64, 0x70, 0x30, 0x66, 0x60, 0x54, + 0xe2, 0x08, 0x18, 0x0f, 0x8f, 0x7b, 0x0d, 0xf2, + 0x24, 0x9e, 0x44, 0xfb, 0xa5, 0x93, 0x1f, 0xff, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x2c, }, + {0xb8, 0x35, 0x7c, 0x3a, 0x6c, 0xee, 0xf2, 0x88, + 0x31, 0x0e, 0x17, 0xb8, 0xbf, 0xef, 0xf9, 0x20, + 0x08, 0x46, 0xca, 0x8c, 0x19, 0x42, 0x49, 0x7c, + 0x48, 0x44, 0x03, 0xbc, 0x00, 0xeb, 0x61, 0x05, + 0x99, 0xf9, 0x59, 0x42, 0xdf, 0x10, 0x82, 0xe4, + 0xf9, 0x42, 0x6d, 0x08, 0x6f, 0xb9, 0xc6, 0x23, + 0x1a, 0xe8, 0xb2, 0x49, 0x33, 0xaa, 0xb5, 0xdb, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x2d, }, + {0x0b, 0x6e, 0xc4, 0xfe, 0x17, 0x77, 0x38, 0x24, + 0x04, 0xef, 0x67, 0x99, 0x97, 0xba, 0x8d, 0x1c, + 0xc5, 0xcd, 0x8e, 0x85, 0x34, 0x92, 0x59, 0xf5, + 0x90, 0xc4, 0xc6, 0x6d, 0xcc, 0x66, 0x2b, 0x9b, + 0xcb, 0xa6, 0xf9, 0x4e, 0xe4, 0xff, 0x1c, 0x9c, + 0x10, 0xbd, 0x6d, 0xdd, 0x0d, 0x13, 0x8d, 0xf2, + 0xd0, 0x99, 0xa2, 0x82, 0x15, 0x2a, 0x4b, 0x7f, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x2e, }, + {0xba, 0xa4, 0xd8, 0x63, 0x55, 0x11, 0xa7, 0xd2, + 0x88, 0xae, 0xbe, 0xed, 0xd1, 0x2c, 0xe5, 0x29, + 0xff, 0x10, 0x2c, 0x91, 0xf9, 0x7f, 0x86, 0x7e, + 0x21, 0x91, 0x6b, 0xf9, 0x68, 0x65, 0xa0, 0xb8, + 0xa6, 0x07, 0xf0, 0xb0, 0x4b, 0x13, 0xd1, 0xcb, + 0x0a, 0xa9, 0x92, 0xa5, 0xa9, 0x7f, 0x5e, 0xe8, + 0xca, 0x18, 0x49, 0xef, 0xb9, 0xed, 0x86, 0x78, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x2f, }, + {0xa5, 0x36, 0x40, 0xc8, 0x3d, 0xc2, 0x08, 0x60, + 0x3d, 0xed, 0x83, 0xe4, 0xec, 0xf7, 0x58, 0xf2, + 0x4c, 0x35, 0x7d, 0x7c, 0xf4, 0x80, 0x88, 0xb2, + 0xce, 0x01, 0xe9, 0xfa, 0x2a, 0x7e, 0xb3, 0x28, + 0xdb, 0xe6, 0x63, 0xb5, 0xa4, 0x68, 0xb5, 0xbc, + 0x97, 0xa0, 0x40, 0xa3, 0x74, 0x53, 0x96, 0xba, + 0x63, 0x6b, 0x96, 0x43, 0x70, 0xdc, 0x33, 0x52, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x30, }, + {0x34, 0xe8, 0xe1, 0x7a, 0x43, 0x0e, 0x43, 0x28, + 0x97, 0x93, 0xc3, 0x83, 0xfa, 0xc9, 0x77, 0x42, + 0x47, 0xb4, 0x0e, 0x9e, 0xbd, 0x33, 0x66, 0x98, + 0x1f, 0xcf, 0xae, 0xca, 0xda, 0xd7, 0xe6, 0x08, + 0xe3, 0x80, 0x48, 0x04, 0x34, 0xea, 0x64, 0x1c, + 0xc8, 0x2c, 0x82, 0xcb, 0xc9, 0x28, 0x01, 0x46, + 0x9c, 0x8d, 0xb0, 0x20, 0x4f, 0x13, 0x48, 0x9a, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x31, }, + {0x6e, 0x31, 0xee, 0x1d, 0xc1, 0x37, 0xf8, 0x1b, + 0x05, 0x67, 0x52, 0xe4, 0xde, 0xab, 0x14, 0x43, + 0xa4, 0x81, 0x03, 0x3e, 0x9b, 0x4c, 0x93, 0xa3, + 0x04, 0x4f, 0x4f, 0x7a, 0xdf, 0x82, 0x22, 0x0f, + 0xc7, 0xa4, 0x02, 0x15, 0x49, 0x16, 0x53, 0x25, + 0x72, 0x5f, 0x94, 0xc3, 0x41, 0x0d, 0xdb, 0x56, + 0xc5, 0x4e, 0x16, 0x1f, 0xc9, 0xef, 0x62, 0xee, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x32, }, + {0xef, 0x53, 0xb6, 0x29, 0x4a, 0xca, 0x43, 0x1f, + 0x0f, 0x3c, 0x22, 0xdc, 0x82, 0xeb, 0x90, 0x50, + 0x32, 0x4f, 0x1d, 0x88, 0xd3, 0x77, 0xe7, 0x16, + 0x44, 0x8e, 0x50, 0x7c, 0xdf, 0x4a, 0xef, 0xff, + 0xbf, 0x6d, 0x16, 0x99, 0xc9, 0x30, 0x48, 0x1c, + 0xd1, 0x02, 0x12, 0x7c, 0x9a, 0x3d, 0x99, 0x20, + 0x48, 0xab, 0x05, 0x92, 0x9b, 0x6e, 0x59, 0x27, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x33, }, + {0xae, 0xa9, 0xe1, 0x7a, 0x30, 0x65, 0x17, 0xeb, + 0x89, 0x15, 0x2a, 0xa7, 0x09, 0x6d, 0x2c, 0x38, + 0x1e, 0xc8, 0x13, 0xc5, 0x1a, 0xa8, 0x80, 0xe7, + 0xbe, 0xe2, 0xc0, 0xfd, 0xc6, 0x44, 0xcf, 0x15, + 0x4c, 0xc8, 0x1f, 0x5a, 0xde, 0x49, 0x34, 0x5e, + 0x54, 0x1b, 0x4d, 0x4b, 0x5c, 0x1a, 0xdb, 0x3e, + 0xb5, 0xc0, 0x1c, 0x14, 0xee, 0x94, 0x9a, 0xa2, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x34, }, + {0x2f, 0xdc, 0xcc, 0xfe, 0xe7, 0x20, 0xa7, 0x7e, + 0xf6, 0xcb, 0x3b, 0xfb, 0xb4, 0x47, 0xf9, 0x38, + 0x31, 0x17, 0xe3, 0xda, 0xa4, 0xa0, 0x7e, 0x36, + 0xed, 0x15, 0xf7, 0x8d, 0xc8, 0xe8, 0xcd, 0x1b, + 0x0b, 0xe4, 0x0b, 0x08, 0x77, 0xcf, 0xca, 0x19, + 0x58, 0x60, 0x31, 0x22, 0xf1, 0xe6, 0x91, 0x4f, + 0x84, 0xb7, 0xe8, 0xe9, 0x68, 0xae, 0x8b, 0x9e, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x35, }, + {0x85, 0x8e, 0x6f, 0x9c, 0xc6, 0xc1, 0x2c, 0x31, + 0xf5, 0xdf, 0x12, 0x4a, 0xa7, 0x77, 0x67, 0xb0, + 0x5c, 0x8b, 0xc0, 0x21, 0xbd, 0x68, 0x3d, 0x2b, + 0x55, 0x57, 0x15, 0x50, 0xfb, 0x92, 0x32, 0xc1, + 0x5a, 0x3b, 0xc7, 0x67, 0x3a, 0x3a, 0x03, 0xb0, + 0x25, 0x38, 0x24, 0xc5, 0x3d, 0x0f, 0xd1, 0x41, + 0x1b, 0x1c, 0xab, 0xe2, 0xe1, 0x87, 0xfb, 0x87, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x36, }, + {0xdb, 0x2f, 0x6b, 0xe6, 0x30, 0xe2, 0x46, 0xa5, + 0xcf, 0x7d, 0x99, 0xb8, 0x51, 0x94, 0xb1, 0x23, + 0xd4, 0x87, 0xe2, 0xd4, 0x66, 0xb9, 0x4b, 0x24, + 0xa0, 0x3c, 0x3e, 0x28, 0xf0, 0xc5, 0xcf, 0xf7, + 0xab, 0x68, 0x0d, 0x09, 0xee, 0x11, 0xda, 0xe8, + 0x4e, 0x9c, 0x10, 0x72, 0xac, 0x48, 0xea, 0x2e, + 0x74, 0x4b, 0x1b, 0x7f, 0x72, 0xfd, 0x46, 0x9e, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x37, }, + {0x1f, 0x24, 0x83, 0xf8, 0x25, 0x72, 0x25, 0x1f, + 0xca, 0x97, 0x5f, 0xea, 0x40, 0xdb, 0x82, 0x1d, + 0xf8, 0xad, 0x82, 0xa3, 0xc0, 0x02, 0xee, 0x6c, + 0x57, 0x11, 0x24, 0x08, 0x76, 0x05, 0x0f, 0x33, + 0x48, 0xaf, 0x26, 0x64, 0xaa, 0xc3, 0xa8, 0xb0, + 0x52, 0x81, 0x30, 0x4e, 0xbc, 0x7a, 0x79, 0x14, + 0xc6, 0xad, 0x50, 0xa4, 0xb4, 0xea, 0xc3, 0x83, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x38, }, + {0x31, 0xc4, 0x9a, 0xe7, 0x5b, 0xce, 0x78, 0x07, + 0xcd, 0xff, 0x22, 0x05, 0x5d, 0x94, 0xee, 0x90, + 0x21, 0xfe, 0xdb, 0xb5, 0xab, 0x51, 0xc5, 0x75, + 0x26, 0xf0, 0x11, 0xaa, 0xd8, 0x17, 0x40, 0x0e, + 0x8b, 0xa9, 0xca, 0x13, 0xa4, 0x5f, 0x36, 0x0e, + 0x3d, 0x12, 0x1e, 0xaa, 0xeb, 0x39, 0xaf, 0x82, + 0xd6, 0x00, 0x1c, 0x81, 0x86, 0xf5, 0xf8, 0x66, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x39, }, + {0xae, 0x99, 0xfe, 0xeb, 0xb5, 0xd2, 0x69, 0x45, + 0xb5, 0x48, 0x92, 0x09, 0x2a, 0x8a, 0xee, 0x02, + 0x91, 0x29, 0x30, 0xfa, 0x41, 0xcd, 0x11, 0x4e, + 0x40, 0x44, 0x73, 0x01, 0xfb, 0x7d, 0xa7, 0xf5, + 0xf1, 0x3a, 0x43, 0xb8, 0x17, 0x74, 0x37, 0x3c, + 0x87, 0x9c, 0xd3, 0x2d, 0x69, 0x34, 0xc0, 0x5f, + 0xa7, 0x58, 0xee, 0xb1, 0x4f, 0xcf, 0xab, 0x38, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x3a, }, + {0xdf, 0x1b, 0x1d, 0x66, 0xa5, 0x51, 0xd0, 0xd3, + 0x1e, 0xff, 0x82, 0x25, 0x58, 0xb9, 0xd2, 0xcc, + 0x75, 0xc2, 0x18, 0x02, 0x79, 0xfe, 0x0d, 0x08, + 0xfd, 0x89, 0x6d, 0x04, 0x5c, 0x08, 0x0f, 0xc3, + 0x52, 0x2f, 0x41, 0xbb, 0xb3, 0xf5, 0x5a, 0x97, + 0xcf, 0xec, 0xf2, 0x1f, 0x88, 0x2c, 0xe8, 0xcb, + 0xb1, 0xe5, 0x0c, 0xa6, 0xe6, 0x7e, 0x56, 0xdc, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x3b, }, + {0x70, 0x6a, 0x46, 0xdc, 0x76, 0xdc, 0xb7, 0x67, + 0x98, 0xe6, 0x0e, 0x6d, 0x89, 0x47, 0x47, 0x88, + 0xd1, 0x6d, 0xc1, 0x80, 0x32, 0xd2, 0x68, 0xfd, + 0x1a, 0x70, 0x4f, 0xa6, 0xe3, 0xd4, 0x89, 0x58, + 0x43, 0xda, 0x18, 0x8f, 0xd5, 0x8f, 0xb0, 0x56, + 0x79, 0x76, 0xd7, 0xb5, 0x03, 0x59, 0xd6, 0xb7, + 0x85, 0x30, 0xc8, 0xf6, 0x2d, 0x1b, 0x17, 0x46, + }, + }, + { + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, + 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, + 0x5c, 0x5c, 0x2a, 0x3c, }, + {0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, + 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, + 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, + 0x11, 0x5c, 0x1d, 0x21, 0x42, 0xc8, 0x9c, 0x77, + 0x4a, 0x08, 0xdc, 0x04, 0xb3, 0xdd, 0x20, 0x19, + 0x32, 0xbc, 0x8a, 0x5e, 0xa5, 0xf8, 0xb8, 0x9b, + 0xbb, 0x2a, 0x7e, 0x66, 0x7a, 0xff, 0x81, 0xcd, + }, + }, +}; + +TEST(P224, ExternalToInternalAndBack) { + Point point; + + EXPECT_TRUE(point.SetFromString( + std::string(reinterpret_cast<const char*>(kBasePointExternal), + sizeof(kBasePointExternal)))); + + const std::string external = point.ToString(); + + ASSERT_EQ(external.size(), 56u); + EXPECT_EQ(0, memcmp(external.data(), kBasePointExternal, + sizeof(kBasePointExternal))); +} + +TEST(P224, ScalarBaseMult) { + Point point; + + for (size_t i = 0; i < arraysize(kNISTTestVectors); i++) { + p224::ScalarBaseMult(kNISTTestVectors[i].scalar, &point); + const std::string external = point.ToString(); + ASSERT_EQ(external.size(), 56u); + EXPECT_EQ(0, memcmp(external.data(), kNISTTestVectors[i].affine, + external.size())); + } +} + +TEST(P224, Addition) { + Point a, b, minus_b, sum, a_again; + + ASSERT_TRUE(a.SetFromString(std::string( + reinterpret_cast<const char*>(kNISTTestVectors[10].affine), 56))); + ASSERT_TRUE(b.SetFromString(std::string( + reinterpret_cast<const char*>(kNISTTestVectors[11].affine), 56))); + + p224::Negate(b, &minus_b); + p224::Add(a, b, &sum); + EXPECT_NE(0, memcmp(&sum, &a, sizeof(sum))); + p224::Add(minus_b, sum, &a_again); + EXPECT_TRUE(a_again.ToString() == a.ToString()); +} + +TEST(P224, Infinity) { + char zeros[56]; + memset(zeros, 0, sizeof(zeros)); + + // Test that x^0 = ∞. + Point a; + p224::ScalarBaseMult(reinterpret_cast<const uint8*>(zeros), &a); + EXPECT_EQ(0, memcmp(zeros, a.ToString().data(), sizeof(zeros))); + + // We shouldn't allow ∞ to be imported. + EXPECT_FALSE(a.SetFromString(std::string(zeros, sizeof(zeros)))); +} + +} // namespace crypto diff --git a/third_party/chromium/crypto/sha2.cc b/third_party/chromium/crypto/sha2.cc new file mode 100644 index 0000000..7dcef0b --- /dev/null +++ b/third_party/chromium/crypto/sha2.cc @@ -0,0 +1,30 @@ +// Copyright 2012 The Chromium OS 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 "third_party/chromium/crypto/sha2.h" + +#include <algorithm> +#include <openssl/sha.h> + +#include <base/memory/scoped_ptr.h> + +namespace crypto { + +void SHA256HashString(const std::string& str, uint8_t* output, size_t len) { + std::string hash = SHA256HashString(str); + len = std::min(hash.size(), len); + std::copy(hash.begin(), hash.begin() + len, output); +} + +std::string SHA256HashString(const std::string& str) { + SHA256_CTX sha_context; + SHA256_Init(&sha_context); + SHA256_Update(&sha_context, str.data(), str.size()); + + std::string hash(kSHA256Length, 0); + SHA256_Final(reinterpret_cast<uint8_t*>(&hash[0]), &sha_context); + return hash; +} + +} // namespace crypto diff --git a/third_party/chromium/crypto/sha2.h b/third_party/chromium/crypto/sha2.h new file mode 100644 index 0000000..8e05388 --- /dev/null +++ b/third_party/chromium/crypto/sha2.h @@ -0,0 +1,29 @@ +// Copyright 2012 The Chromium OS 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 LIBWEAVE_THIRD_PARTY_CHROMIUM_SHA2_H_ +#define LIBWEAVE_THIRD_PARTY_CHROMIUM_SHA2_H_ + +#include <string> + +namespace crypto { + +// These functions perform SHA-256 operations. +// +// Functions for SHA-384 and SHA-512 can be added when the need arises. + +static const size_t kSHA256Length = 32; // Length in bytes of a SHA-256 hash. + +// Computes the SHA-256 hash of the input string 'str' and stores the first +// 'len' bytes of the hash in the output buffer 'output'. If 'len' > 32, +// only 32 bytes (the full hash) are stored in the 'output' buffer. +void SHA256HashString(const std::string& str, uint8_t* output, size_t len); + +// Convenience version of the above that returns the result in a 32-byte +// string. +std::string SHA256HashString(const std::string& str); + +} // namespace crypto + +#endif // LIBWEAVE_THIRD_PARTY_CHROMIUM_SHA2_H_ diff --git a/third_party/chromium/crypto/sha2_unittest.cc b/third_party/chromium/crypto/sha2_unittest.cc new file mode 100644 index 0000000..0c30f45 --- /dev/null +++ b/third_party/chromium/crypto/sha2_unittest.cc @@ -0,0 +1,104 @@ +// Copyright 2011 The Chromium OS 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 "third_party/chromium/crypto/sha2.h" + +#include <base/basictypes.h> +#include <gtest/gtest.h> + +namespace weave { + +TEST(Sha256Test, Test1) { + // Example B.1 from FIPS 180-2: one-block message. + std::string input1 = "abc"; + int expected1[] = { 0xba, 0x78, 0x16, 0xbf, + 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, + 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, + 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, + 0xf2, 0x00, 0x15, 0xad }; + + uint8 output1[crypto::kSHA256Length]; + crypto::SHA256HashString(input1, output1, sizeof(output1)); + for (size_t i = 0; i < crypto::kSHA256Length; i++) + EXPECT_EQ(expected1[i], static_cast<int>(output1[i])); + + uint8 output_truncated1[4]; // 4 bytes == 32 bits + crypto::SHA256HashString(input1, + output_truncated1, sizeof(output_truncated1)); + for (size_t i = 0; i < sizeof(output_truncated1); i++) + EXPECT_EQ(expected1[i], static_cast<int>(output_truncated1[i])); +} + +TEST(Sha256Test, Test1_String) { + // Same as the above, but using the wrapper that returns a std::string. + // Example B.1 from FIPS 180-2: one-block message. + std::string input1 = "abc"; + int expected1[] = { 0xba, 0x78, 0x16, 0xbf, + 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, + 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, + 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, + 0xf2, 0x00, 0x15, 0xad }; + + std::string output1 = crypto::SHA256HashString(input1); + ASSERT_EQ(crypto::kSHA256Length, output1.size()); + for (size_t i = 0; i < crypto::kSHA256Length; i++) + EXPECT_EQ(expected1[i], static_cast<uint8>(output1[i])); +} + +TEST(Sha256Test, Test2) { + // Example B.2 from FIPS 180-2: multi-block message. + std::string input2 = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + int expected2[] = { 0x24, 0x8d, 0x6a, 0x61, + 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, + 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, + 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, + 0x19, 0xdb, 0x06, 0xc1 }; + + uint8 output2[crypto::kSHA256Length]; + crypto::SHA256HashString(input2, output2, sizeof(output2)); + for (size_t i = 0; i < crypto::kSHA256Length; i++) + EXPECT_EQ(expected2[i], static_cast<int>(output2[i])); + + uint8 output_truncated2[6]; + crypto::SHA256HashString(input2, + output_truncated2, sizeof(output_truncated2)); + for (size_t i = 0; i < sizeof(output_truncated2); i++) + EXPECT_EQ(expected2[i], static_cast<int>(output_truncated2[i])); +} + +TEST(Sha256Test, Test3) { + // Example B.3 from FIPS 180-2: long message. + std::string input3(1000000, 'a'); // 'a' repeated a million times + int expected3[] = { 0xcd, 0xc7, 0x6e, 0x5c, + 0x99, 0x14, 0xfb, 0x92, + 0x81, 0xa1, 0xc7, 0xe2, + 0x84, 0xd7, 0x3e, 0x67, + 0xf1, 0x80, 0x9a, 0x48, + 0xa4, 0x97, 0x20, 0x0e, + 0x04, 0x6d, 0x39, 0xcc, + 0xc7, 0x11, 0x2c, 0xd0 }; + + uint8 output3[crypto::kSHA256Length]; + crypto::SHA256HashString(input3, output3, sizeof(output3)); + for (size_t i = 0; i < crypto::kSHA256Length; i++) + EXPECT_EQ(expected3[i], static_cast<int>(output3[i])); + + uint8 output_truncated3[12]; + crypto::SHA256HashString(input3, + output_truncated3, sizeof(output_truncated3)); + for (size_t i = 0; i < sizeof(output_truncated3); i++) + EXPECT_EQ(expected3[i], static_cast<int>(output_truncated3[i])); +} + +} // namespace weave diff --git a/third_party/modp_b64/LICENSE b/third_party/modp_b64/LICENSE new file mode 100644 index 0000000..55af76f --- /dev/null +++ b/third_party/modp_b64/LICENSE @@ -0,0 +1,33 @@ + * MODP_B64 - High performance base64 encoder/decoder + * Version 1.3 -- 17-Mar-2006 + * http://modp.com/release/base64 + * + * Copyright (c) 2005, 2006 Nick Galbreath -- nickg [at] modp [dot] com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the modp.com nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/modp_b64/MODULE_LICENSE_BSD b/third_party/modp_b64/MODULE_LICENSE_BSD new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/third_party/modp_b64/MODULE_LICENSE_BSD diff --git a/third_party/modp_b64/NOTICE b/third_party/modp_b64/NOTICE new file mode 120000 index 0000000..7a694c9 --- /dev/null +++ b/third_party/modp_b64/NOTICE @@ -0,0 +1 @@ +LICENSE
\ No newline at end of file diff --git a/third_party/modp_b64/README.chromium b/third_party/modp_b64/README.chromium new file mode 100644 index 0000000..40b93d2 --- /dev/null +++ b/third_party/modp_b64/README.chromium @@ -0,0 +1,17 @@ +Name: modp base64 decoder +Short Name: stringencoders +URL: http://code.google.com/p/stringencoders/ +Version: unknown +License: BSD +Security Critical: yes + +Description: +The modp_b64.c file was modified to remove the inclusion of modp's config.h +and to fix compilation errors that occur under VC8. The file was renamed +modp_b64.cc to force it to be compiled as C++ so that the inclusion of +basictypes.h could be possible. + +The modp_b64.cc and modp_b64.h files were modified to make them safe on +64-bit systems. +The modp_b64.cc was modified to avoid misaligned read/write on +little-endian hardware. diff --git a/third_party/modp_b64/modp_b64.cc b/third_party/modp_b64/modp_b64.cc new file mode 100644 index 0000000..fdb8a40 --- /dev/null +++ b/third_party/modp_b64/modp_b64.cc @@ -0,0 +1,253 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4: */ +/** + * \file + * <PRE> + * MODP_B64 - High performance base64 encoder/decoder + * Version 1.3 -- 17-Mar-2006 + * http://modp.com/release/base64 + * + * Copyright © 2005, 2006 Nick Galbreath -- nickg [at] modp [dot] com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the modp.com nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This is the standard "new" BSD license: + * http://www.opensource.org/licenses/bsd-license.php + * </PRE> + */ + +/* public header */ +#include "modp_b64.h" + +/* + * If you are ripping this out of the library, comment out the next + * line and uncomment the next lines as approrpiate + */ +//#include "config.h" + +/* if on motoral, sun, ibm; uncomment this */ +/* #define WORDS_BIGENDIAN 1 */ +/* else for Intel, Amd; uncomment this */ +/* #undef WORDS_BIGENDIAN */ + +#include "modp_b64_data.h" + +#define BADCHAR 0x01FFFFFF + +/** + * you can control if we use padding by commenting out this + * next line. However, I highly recommend you use padding and not + * using it should only be for compatability with a 3rd party. + * Also, 'no padding' is not tested! + */ +#define DOPAD 1 + +/* + * if we aren't doing padding + * set the pad character to NULL + */ +#ifndef DOPAD +#undef CHARPAD +#define CHARPAD '\0' +#endif + +size_t modp_b64_encode(char* dest, const char* str, size_t len) +{ + size_t i = 0; + uint8_t* p = (uint8_t*) dest; + + /* unsigned here is important! */ + uint8_t t1, t2, t3; + + if (len > 2) { + for (; i < len - 2; i += 3) { + t1 = str[i]; t2 = str[i+1]; t3 = str[i+2]; + *p++ = e0[t1]; + *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *p++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + *p++ = e2[t3]; + } + } + + switch (len - i) { + case 0: + break; + case 1: + t1 = str[i]; + *p++ = e0[t1]; + *p++ = e1[(t1 & 0x03) << 4]; + *p++ = CHARPAD; + *p++ = CHARPAD; + break; + default: /* case 2 */ + t1 = str[i]; t2 = str[i+1]; + *p++ = e0[t1]; + *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + *p++ = e2[(t2 & 0x0F) << 2]; + *p++ = CHARPAD; + } + + *p = '\0'; + return p - (uint8_t*)dest; +} + +#ifdef WORDS_BIGENDIAN /* BIG ENDIAN -- SUN / IBM / MOTOROLA */ +int modp_b64_decode(char* dest, const char* src, int len) +{ + if (len == 0) return 0; + +#ifdef DOPAD + /* if padding is used, then the message must be at least + 4 chars and be a multiple of 4. + there can be at most 2 pad chars at the end */ + if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR; + if (src[len-1] == CHARPAD) { + len--; + if (src[len -1] == CHARPAD) { + len--; + } + } +#endif /* DOPAD */ + + size_t i; + int leftover = len % 4; + size_t chunks = (leftover == 0) ? len / 4 - 1 : len /4; + + uint8_t* p = (uint8_t*) dest; + uint32_t x = 0; + uint32_t* destInt = (uint32_t*) p; + uint32_t* srcInt = (uint32_t*) src; + uint32_t y = *srcInt++; + for (i = 0; i < chunks; ++i) { + x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] | + d2[y >> 8 & 0xff] | d3[y & 0xff]; + + if (x >= BADCHAR) return MODP_B64_ERROR; + *destInt = x << 8; + p += 3; + destInt = (uint32_t*)p; + y = *srcInt++; + } + + switch (leftover) { + case 0: + x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] | + d2[y >> 8 & 0xff] | d3[y & 0xff]; + if (x >= BADCHAR) return MODP_B64_ERROR; + *p++ = ((uint8_t*)&x)[1]; + *p++ = ((uint8_t*)&x)[2]; + *p = ((uint8_t*)&x)[3]; + return (chunks+1)*3; + case 1: + x = d3[y >> 24]; + *p = (uint8_t)x; + break; + case 2: + x = d3[y >> 24] *64 + d3[(y >> 16) & 0xff]; + *p = (uint8_t)(x >> 4); + break; + default: /* case 3 */ + x = (d3[y >> 24] *64 + d3[(y >> 16) & 0xff])*64 + + d3[(y >> 8) & 0xff]; + *p++ = (uint8_t) (x >> 10); + *p = (uint8_t) (x >> 2); + break; + } + + if (x >= BADCHAR) return MODP_B64_ERROR; + return 3*chunks + (6*leftover)/8; +} + +#else /* LITTLE ENDIAN -- INTEL AND FRIENDS */ + +size_t modp_b64_decode(char* dest, const char* src, size_t len) +{ + if (len == 0) return 0; + +#ifdef DOPAD + /* + * if padding is used, then the message must be at least + * 4 chars and be a multiple of 4 + */ + if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR; /* error */ + /* there can be at most 2 pad chars at the end */ + if (src[len-1] == CHARPAD) { + len--; + if (src[len -1] == CHARPAD) { + len--; + } + } +#endif + + size_t i; + int leftover = len % 4; + size_t chunks = (leftover == 0) ? len / 4 - 1 : len /4; + + uint8_t* p = (uint8_t*)dest; + uint32_t x = 0; + const uint8_t* y = (uint8_t*)src; + for (i = 0; i < chunks; ++i, y += 4) { + x = d0[y[0]] | d1[y[1]] | d2[y[2]] | d3[y[3]]; + if (x >= BADCHAR) return MODP_B64_ERROR; + *p++ = ((uint8_t*)(&x))[0]; + *p++ = ((uint8_t*)(&x))[1]; + *p++ = ((uint8_t*)(&x))[2]; + } + + switch (leftover) { + case 0: + x = d0[y[0]] | d1[y[1]] | d2[y[2]] | d3[y[3]]; + + if (x >= BADCHAR) return MODP_B64_ERROR; + *p++ = ((uint8_t*)(&x))[0]; + *p++ = ((uint8_t*)(&x))[1]; + *p = ((uint8_t*)(&x))[2]; + return (chunks+1)*3; + break; + case 1: /* with padding this is an impossible case */ + x = d0[y[0]]; + *p = *((uint8_t*)(&x)); // i.e. first char/byte in int + break; + case 2: // * case 2, 1 output byte */ + x = d0[y[0]] | d1[y[1]]; + *p = *((uint8_t*)(&x)); // i.e. first char + break; + default: /* case 3, 2 output bytes */ + x = d0[y[0]] | d1[y[1]] | d2[y[2]]; /* 0x3c */ + *p++ = ((uint8_t*)(&x))[0]; + *p = ((uint8_t*)(&x))[1]; + break; + } + + if (x >= BADCHAR) return MODP_B64_ERROR; + + return 3*chunks + (6*leftover)/8; +} + +#endif /* if bigendian / else / endif */ diff --git a/third_party/modp_b64/modp_b64/modp_b64.h b/third_party/modp_b64/modp_b64/modp_b64.h new file mode 100644 index 0000000..3270e5f --- /dev/null +++ b/third_party/modp_b64/modp_b64/modp_b64.h @@ -0,0 +1,171 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4: */ + +/** + * \file + * <PRE> + * High performance base64 encoder / decoder + * Version 1.3 -- 17-Mar-2006 + * + * Copyright © 2005, 2006, Nick Galbreath -- nickg [at] modp [dot] com + * All rights reserved. + * + * http://modp.com/release/base64 + * + * Released under bsd license. See modp_b64.c for details. + * </pre> + * + * The default implementation is the standard b64 encoding with padding. + * It's easy to change this to use "URL safe" characters and to remove + * padding. See the modp_b64.c source code for details. + * + */ + +#ifndef MODP_B64 +#define MODP_B64 + +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Encode a raw binary string into base 64. + * src contains the bytes + * len contains the number of bytes in the src + * dest should be allocated by the caller to contain + * at least modp_b64_encode_len(len) bytes (see below) + * This will contain the null-terminated b64 encoded result + * returns length of the destination string plus the ending null byte + * i.e. the result will be equal to strlen(dest) + 1 + * + * Example + * + * \code + * char* src = ...; + * int srclen = ...; //the length of number of bytes in src + * char* dest = (char*) malloc(modp_b64_encode_len); + * int len = modp_b64_encode(dest, src, sourcelen); + * if (len == -1) { + * printf("Error\n"); + * } else { + * printf("b64 = %s\n", dest); + * } + * \endcode + * + */ +size_t modp_b64_encode(char* dest, const char* str, size_t len); + +/** + * Decode a base64 encoded string + * + * src should contain exactly len bytes of b64 characters. + * if src contains -any- non-base characters (such as white + * space, -1 is returned. + * + * dest should be allocated by the caller to contain at least + * len * 3 / 4 bytes. + * + * Returns the length (strlen) of the output, or -1 if unable to + * decode + * + * \code + * char* src = ...; + * int srclen = ...; // or if you don't know use strlen(src) + * char* dest = (char*) malloc(modp_b64_decode_len(srclen)); + * int len = modp_b64_decode(dest, src, sourcelen); + * if (len == -1) { error } + * \endcode + */ +size_t modp_b64_decode(char* dest, const char* src, size_t len); + +/** + * Given a source string of length len, this returns the amount of + * memory the destination string should have. + * + * remember, this is integer math + * 3 bytes turn into 4 chars + * ceiling[len / 3] * 4 + 1 + * + * +1 is for any extra null. + */ +#define modp_b64_encode_len(A) ((A+2)/3 * 4 + 1) + +/** + * Given a base64 string of length len, + * this returns the amount of memory required for output string + * It maybe be more than the actual number of bytes written. + * NOTE: remember this is integer math + * this allocates a bit more memory than traditional versions of b64 + * decode 4 chars turn into 3 bytes + * floor[len * 3/4] + 2 + */ +#define modp_b64_decode_len(A) (A / 4 * 3 + 2) + +/** + * Will return the strlen of the output from encoding. + * This may be less than the required number of bytes allocated. + * + * This allows you to 'deserialized' a struct + * \code + * char* b64encoded = "..."; + * int len = strlen(b64encoded); + * + * struct datastuff foo; + * if (modp_b64_encode_strlen(sizeof(struct datastuff)) != len) { + * // wrong size + * return false; + * } else { + * // safe to do; + * if (modp_b64_decode((char*) &foo, b64encoded, len) == -1) { + * // bad characters + * return false; + * } + * } + * // foo is filled out now + * \endcode + */ +#define modp_b64_encode_strlen(A) ((A + 2)/ 3 * 4) + +#define MODP_B64_ERROR ((size_t)-1) + +#ifdef __cplusplus +} + +#include <string> + +inline std::string& modp_b64_encode(std::string& s) +{ + std::string x(modp_b64_encode_len(s.size()), '\0'); + size_t d = modp_b64_encode(const_cast<char*>(x.data()), s.data(), (int)s.size()); + x.erase(d, std::string::npos); + s.swap(x); + return s; +} + +/** + * base 64 decode a string (self-modifing) + * On failure, the string is empty. + * + * This function is for C++ only (duh) + * + * \param[in,out] s the string to be decoded + * \return a reference to the input string + */ +inline std::string& modp_b64_decode(std::string& s) +{ + std::string x(modp_b64_decode_len(s.size()), '\0'); + size_t d = modp_b64_decode(const_cast<char*>(x.data()), s.data(), (int)s.size()); + if (d == MODP_B64_ERROR) { + x.clear(); + } else { + x.erase(d, std::string::npos); + } + s.swap(x); + return s; +} + +#endif /* __cplusplus */ + +#endif /* MODP_B64 */ diff --git a/third_party/modp_b64/modp_b64_data.h b/third_party/modp_b64/modp_b64_data.h new file mode 100644 index 0000000..2ecf597 --- /dev/null +++ b/third_party/modp_b64/modp_b64_data.h @@ -0,0 +1,481 @@ +#include <stdint.h> + +#define CHAR62 '+' +#define CHAR63 '/' +#define CHARPAD '=' +static const char e0[256] = { + 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', + 'C', 'C', 'D', 'D', 'D', 'D', 'E', 'E', 'E', 'E', + 'F', 'F', 'F', 'F', 'G', 'G', 'G', 'G', 'H', 'H', + 'H', 'H', 'I', 'I', 'I', 'I', 'J', 'J', 'J', 'J', + 'K', 'K', 'K', 'K', 'L', 'L', 'L', 'L', 'M', 'M', + 'M', 'M', 'N', 'N', 'N', 'N', 'O', 'O', 'O', 'O', + 'P', 'P', 'P', 'P', 'Q', 'Q', 'Q', 'Q', 'R', 'R', + 'R', 'R', 'S', 'S', 'S', 'S', 'T', 'T', 'T', 'T', + 'U', 'U', 'U', 'U', 'V', 'V', 'V', 'V', 'W', 'W', + 'W', 'W', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y', 'Y', + 'Z', 'Z', 'Z', 'Z', 'a', 'a', 'a', 'a', 'b', 'b', + 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'd', + 'e', 'e', 'e', 'e', 'f', 'f', 'f', 'f', 'g', 'g', + 'g', 'g', 'h', 'h', 'h', 'h', 'i', 'i', 'i', 'i', + 'j', 'j', 'j', 'j', 'k', 'k', 'k', 'k', 'l', 'l', + 'l', 'l', 'm', 'm', 'm', 'm', 'n', 'n', 'n', 'n', + 'o', 'o', 'o', 'o', 'p', 'p', 'p', 'p', 'q', 'q', + 'q', 'q', 'r', 'r', 'r', 'r', 's', 's', 's', 's', + 't', 't', 't', 't', 'u', 'u', 'u', 'u', 'v', 'v', + 'v', 'v', 'w', 'w', 'w', 'w', 'x', 'x', 'x', 'x', + 'y', 'y', 'y', 'y', 'z', 'z', 'z', 'z', '0', '0', + '0', '0', '1', '1', '1', '1', '2', '2', '2', '2', + '3', '3', '3', '3', '4', '4', '4', '4', '5', '5', + '5', '5', '6', '6', '6', '6', '7', '7', '7', '7', + '8', '8', '8', '8', '9', '9', '9', '9', '+', '+', + '+', '+', '/', '/', '/', '/' +}; + +static const char e1[256] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', '+', '/' +}; + +static const char e2[256] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', '+', '/' +}; + + + +#ifdef WORDS_BIGENDIAN + + +/* SPECIAL DECODE TABLES FOR BIG ENDIAN (IBM/MOTOROLA/SUN) CPUS */ + +static const uint32_t d0[256] = { +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x00f80000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00fc0000, +0x00d00000, 0x00d40000, 0x00d80000, 0x00dc0000, 0x00e00000, 0x00e40000, +0x00e80000, 0x00ec0000, 0x00f00000, 0x00f40000, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, +0x00040000, 0x00080000, 0x000c0000, 0x00100000, 0x00140000, 0x00180000, +0x001c0000, 0x00200000, 0x00240000, 0x00280000, 0x002c0000, 0x00300000, +0x00340000, 0x00380000, 0x003c0000, 0x00400000, 0x00440000, 0x00480000, +0x004c0000, 0x00500000, 0x00540000, 0x00580000, 0x005c0000, 0x00600000, +0x00640000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x00680000, 0x006c0000, 0x00700000, 0x00740000, 0x00780000, +0x007c0000, 0x00800000, 0x00840000, 0x00880000, 0x008c0000, 0x00900000, +0x00940000, 0x00980000, 0x009c0000, 0x00a00000, 0x00a40000, 0x00a80000, +0x00ac0000, 0x00b00000, 0x00b40000, 0x00b80000, 0x00bc0000, 0x00c00000, +0x00c40000, 0x00c80000, 0x00cc0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff +}; + + +static const uint32_t d1[256] = { +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x0003e000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0003f000, +0x00034000, 0x00035000, 0x00036000, 0x00037000, 0x00038000, 0x00039000, +0x0003a000, 0x0003b000, 0x0003c000, 0x0003d000, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, +0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, +0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, +0x0000d000, 0x0000e000, 0x0000f000, 0x00010000, 0x00011000, 0x00012000, +0x00013000, 0x00014000, 0x00015000, 0x00016000, 0x00017000, 0x00018000, +0x00019000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x0001a000, 0x0001b000, 0x0001c000, 0x0001d000, 0x0001e000, +0x0001f000, 0x00020000, 0x00021000, 0x00022000, 0x00023000, 0x00024000, +0x00025000, 0x00026000, 0x00027000, 0x00028000, 0x00029000, 0x0002a000, +0x0002b000, 0x0002c000, 0x0002d000, 0x0002e000, 0x0002f000, 0x00030000, +0x00031000, 0x00032000, 0x00033000, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff +}; + + +static const uint32_t d2[256] = { +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x00000f80, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000fc0, +0x00000d00, 0x00000d40, 0x00000d80, 0x00000dc0, 0x00000e00, 0x00000e40, +0x00000e80, 0x00000ec0, 0x00000f00, 0x00000f40, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, +0x00000040, 0x00000080, 0x000000c0, 0x00000100, 0x00000140, 0x00000180, +0x000001c0, 0x00000200, 0x00000240, 0x00000280, 0x000002c0, 0x00000300, +0x00000340, 0x00000380, 0x000003c0, 0x00000400, 0x00000440, 0x00000480, +0x000004c0, 0x00000500, 0x00000540, 0x00000580, 0x000005c0, 0x00000600, +0x00000640, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x00000680, 0x000006c0, 0x00000700, 0x00000740, 0x00000780, +0x000007c0, 0x00000800, 0x00000840, 0x00000880, 0x000008c0, 0x00000900, +0x00000940, 0x00000980, 0x000009c0, 0x00000a00, 0x00000a40, 0x00000a80, +0x00000ac0, 0x00000b00, 0x00000b40, 0x00000b80, 0x00000bc0, 0x00000c00, +0x00000c40, 0x00000c80, 0x00000cc0, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff +}; + + +static const uint32_t d3[256] = { +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x0000003e, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000003f, +0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, +0x0000003a, 0x0000003b, 0x0000003c, 0x0000003d, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, +0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, +0x00000007, 0x00000008, 0x00000009, 0x0000000a, 0x0000000b, 0x0000000c, +0x0000000d, 0x0000000e, 0x0000000f, 0x00000010, 0x00000011, 0x00000012, +0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 0x00000018, +0x00000019, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x0000001a, 0x0000001b, 0x0000001c, 0x0000001d, 0x0000001e, +0x0000001f, 0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, +0x00000025, 0x00000026, 0x00000027, 0x00000028, 0x00000029, 0x0000002a, +0x0000002b, 0x0000002c, 0x0000002d, 0x0000002e, 0x0000002f, 0x00000030, +0x00000031, 0x00000032, 0x00000033, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff +}; + + +#else + + +/* SPECIAL DECODE TABLES FOR LITTLE ENDIAN (INTEL) CPUS */ + +static const uint32_t d0[256] = { +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, +0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, +0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, +0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, +0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, +0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, +0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, +0x00000064, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, +0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, +0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, +0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, +0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff +}; + + +static const uint32_t d1[256] = { +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, +0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, +0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, +0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, +0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, +0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, +0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, +0x00009001, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, +0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, +0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, +0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, +0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff +}; + + +static const uint32_t d2[256] = { +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, +0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, +0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, +0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, +0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, +0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, +0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, +0x00400600, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, +0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, +0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, +0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, +0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff +}; + + +static const uint32_t d3[256] = { +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, +0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, +0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, +0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, +0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, +0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, +0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, +0x00190000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, +0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, +0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, +0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, +0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, +0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff +}; + + +#endif |