diff --git a/.gitignore b/.gitignore index cd582983501..e7581f4ff6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .qmake.cache .qmake.stash +src/3rdparty/chromium src/3rdparty_upstream/patches src/3rdparty_upstream/gn src/3rdparty_upstream/ninja diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index be62b2203e7..00000000000 --- a/.gitmodules +++ /dev/null @@ -1,5 +0,0 @@ -[submodule "src/3rdparty"] - path = src/3rdparty - url = ../qtwebengine-chromium.git - ignore = dirty - initrepo = true diff --git a/coin/product_dependencies.yaml b/coin/product_dependencies.yaml new file mode 100644 index 00000000000..3b8e9011c0a --- /dev/null +++ b/coin/product_dependencies.yaml @@ -0,0 +1,3 @@ +dependencies: + ../tqtc-qt5.git: + ref: "tqtc/lts-5.15" diff --git a/configure.pri b/configure.pri index d3ba9b14714..519b1aa657b 100644 --- a/configure.pri +++ b/configure.pri @@ -201,6 +201,19 @@ defineTest(qtConfTest_detectNodeJS) { return(false) } } + nodejs = $$system_quote($$system_path($$nodejs)) + !qtRunLoggedCommand("$$nodejs --version", version) { + qtLog("'$$nodejs' didn't run.") + return(false) + } + # at least version 10 + version10 = false + contains(version, "v([1-9][0-9])\..*"): version10 = true + + $${1}.version10 = $$version10 + export($${1}.version10) + $${1}.cache += version10 + export($${1}.cache) return(true) } @@ -461,10 +474,17 @@ defineTest(qtwebengine_isMacOsPlatformSupported) { defineTest(qtwebengine_isGCCVersionSupported) { # Keep in sync with src/webengine/doc/src/qtwebengine-platform-notes.qdoc - greaterThan(QMAKE_GCC_MAJOR_VERSION, 4):return(true) + lessThan(QMAKE_GCC_MAJOR_VERSION, 5) { + qtwebengine_platformError("requires at least gcc version 5, but using gcc version $${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.") + return(false) + } - qtwebengine_platformError("requires at least gcc version 5, but using gcc version $${QMAKE_GCC_MAJOR_VERSION}.$${QMAKE_GCC_MINOR_VERSION}.") - return(false) + equals(QMAKE_GCC_MAJOR_VERSION, 5): equals(QMAKE_GCC_MINOR_VERSION, 4): equals(QMAKE_GCC_PATCH_VERSION, 0) { + qtwebengine_platformError("gcc version 5.4.0 is blacklisted due to internal compiler errors.") + return(false) + } + + return(true) } defineTest(qtwebengine_isBuildingOnWin32) { diff --git a/src/3rdparty b/src/3rdparty deleted file mode 160000 index fb6ab5e4838..00000000000 --- a/src/3rdparty +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fb6ab5e483876298235be1c6a6013b426c82b759 diff --git a/src/3rdparty/.gclient b/src/3rdparty/.gclient new file mode 100644 index 00000000000..6b12b7021d8 --- /dev/null +++ b/src/3rdparty/.gclient @@ -0,0 +1,11 @@ +solutions = [ + { "name" : 'chromium', + "url" : 'https://github.com/chromium/chromium.git', + "deps_file" : 'DEPS', + "managed" : False, + "custom_deps" : { + }, + "custom_vars": {'checkout_nacl': False}, + }, +] +target_os = ["linux", "mac", "win"] diff --git a/src/3rdparty/gn/.clang-format b/src/3rdparty/gn/.clang-format new file mode 100644 index 00000000000..b17a52a80ac --- /dev/null +++ b/src/3rdparty/gn/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: Chromium +Standard: Cpp11 diff --git a/src/3rdparty/gn/.editorconfig b/src/3rdparty/gn/.editorconfig new file mode 100644 index 00000000000..2491fdfae55 --- /dev/null +++ b/src/3rdparty/gn/.editorconfig @@ -0,0 +1,3 @@ +[*.py] +indent_style = space +indent_size = 2 diff --git a/src/3rdparty/gn/.style.yapf b/src/3rdparty/gn/.style.yapf new file mode 100644 index 00000000000..de0c6a70f38 --- /dev/null +++ b/src/3rdparty/gn/.style.yapf @@ -0,0 +1,2 @@ +[style] +based_on_style = chromium diff --git a/src/3rdparty/gn/AUTHORS b/src/3rdparty/gn/AUTHORS new file mode 100644 index 00000000000..17b4959f9ce --- /dev/null +++ b/src/3rdparty/gn/AUTHORS @@ -0,0 +1,45 @@ +# Names should be added to this file with this pattern: +# +# For individuals: +# Name +# +# For organizations: +# Organization +# +# See python fnmatch module documentation for more information. + +Google Inc. <*@google.com> +IBM Inc. <*@*.ibm.com> +Loongson Technology Corporation Limited. <*@loongson.cn> +MIPS Technologies, Inc. <*@mips.com> +NVIDIA Corporation <*@nvidia.com> +Opera Software ASA <*@opera.com> +The Chromium Authors <*@chromium.org> +Vewd Software AS <*@vewd.com> +Vivaldi Technologies AS <*@vivaldi.com> +Yandex LLC <*@yandex-team.ru> + +Alexis Menard +Alfredo Mazzinghi +Andrew Boyarshin +Anuj Kumar Sharma +DanCraft99 +Gergely Nagy +Ilia K +Ivan Naydonov +Joe Armstrong +Julien Brianceau +Kal Conley +Kamil Rytarowski +Martijn Croonen +Matej Knopp +Michael Gilbert +Milko Leporis +Mohan Reddy +Raphael Kubo da Costa +Riku Voipio +Saikrishna Arcot +Tim Niederhausen +Tomas Popela +Tripta Gupta +Yuriy Taraday diff --git a/src/3rdparty/gn/LICENSE b/src/3rdparty/gn/LICENSE new file mode 100644 index 00000000000..a32e00ce6be --- /dev/null +++ b/src/3rdparty/gn/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/src/3rdparty/gn/OWNERS b/src/3rdparty/gn/OWNERS new file mode 100644 index 00000000000..d78697cf06f --- /dev/null +++ b/src/3rdparty/gn/OWNERS @@ -0,0 +1,3 @@ +brettw@chromium.org +phosek@chromium.org +scottmg@chromium.org diff --git a/src/3rdparty/gn/README.md b/src/3rdparty/gn/README.md new file mode 100644 index 00000000000..a8d9fa3724f --- /dev/null +++ b/src/3rdparty/gn/README.md @@ -0,0 +1,90 @@ +# GN + +GN is a meta-build system that generates build files for +[Ninja](https://ninja-build.org). + +Related resources: + + * Documentation in [docs/](https://gn.googlesource.com/gn/+/master/docs/). + * An introductory [presentation](https://docs.google.com/presentation/d/15Zwb53JcncHfEwHpnG_PoIbbzQ3GQi_cpujYwbpcbZo/edit?usp=sharing). + * The [mailing list](https://groups.google.com/a/chromium.org/forum/#!forum/gn-dev). + +## Getting a binary + +You can download the latest version of GN binary for +[Linux](https://chrome-infra-packages.appspot.com/dl/gn/gn/linux-amd64/+/latest), +[macOS](https://chrome-infra-packages.appspot.com/dl/gn/gn/mac-amd64/+/latest) and +[Windows](https://chrome-infra-packages.appspot.com/dl/gn/gn/windows-amd64/+/latest). + +Alternatively, you can build GN from source: + + git clone https://gn.googlesource.com/gn + cd gn + python build/gen.py + ninja -C out + # To run tests: + out/gn_unittests + +On Windows, it is expected that `cl.exe`, `link.exe`, and `lib.exe` can be found +in `PATH`, so you'll want to run from a Visual Studio command prompt, or +similar. + +On Linux and Mac, the default compiler is `clang++`, a recent version is +expected to be found in `PATH`. This can be overridden by setting `CC`, `CXX`, +and `AR`. + +## Examples + +There is a simple example in [examples/simple_build](examples/simple_build) +directory that is a good place to get started with the minimal configuration. + +For a maximal configuration see the Chromium setup: + * [.gn](https://cs.chromium.org/chromium/src/.gn) + * [BUILDCONFIG.gn](https://cs.chromium.org/chromium/src/build/config/BUILDCONFIG.gn) + * [Toolchain setup](https://cs.chromium.org/chromium/src/build/toolchain/) + * [Compiler setup](https://cs.chromium.org/chromium/src/build/config/compiler/BUILD.gn) + +and the Fuchsia setup: + * [.gn](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/.gn) + * [BUILDCONFIG.gn](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/build/config/BUILDCONFIG.gn) + * [Toolchain setup](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/build/toolchain/) + * [Compiler setup](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/master/build/config/BUILD.gn) + +## Reporting bugs + +If you find a bug, you can see if it is known or report it in the [bug +database](https://bugs.chromium.org/p/gn/issues/list). + +## Sending patches + +GN uses [Gerrit](https://www.gerritcodereview.com/) for code review. The short +version of how to patch is: + + Register at https://gn-review.googlesource.com. + + ... edit code ... + ninja -C out && out/gn_unittests + +Then, to upload a change for review: + + git commit + git cl upload --gerrit + +When revising a change, use: + + git commit --amend + git cl upload --gerrit + +which will add the new changes to the existing code review, rather than creating +a new one. + +We ask that all contributors +[sign Google's Contributor License Agreement](https://cla.developers.google.com/) +(either individual or corporate as appropriate, select 'any other Google +project'). + +## Community + +You may ask questions and follow along with GN's development on Chromium's +[gn-dev@](https://groups.google.com/a/chromium.org/forum/#!forum/gn-dev) +Google Group. diff --git a/src/3rdparty/gn/base/atomic_ref_count.h b/src/3rdparty/gn/base/atomic_ref_count.h new file mode 100644 index 00000000000..3ffa017acd3 --- /dev/null +++ b/src/3rdparty/gn/base/atomic_ref_count.h @@ -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. + +// This is a low level implementation of atomic semantics for reference +// counting. Please use base/memory/ref_counted.h directly instead. + +#ifndef BASE_ATOMIC_REF_COUNT_H_ +#define BASE_ATOMIC_REF_COUNT_H_ + +#include + +namespace base { + +class AtomicRefCount { + public: + constexpr AtomicRefCount() : ref_count_(0) {} + explicit constexpr AtomicRefCount(int initial_value) + : ref_count_(initial_value) {} + + // Increment a reference count. + void Increment() { Increment(1); } + + // Increment a reference count by "increment", which must exceed 0. + void Increment(int increment) { + ref_count_.fetch_add(increment, std::memory_order_relaxed); + } + + // Decrement a reference count, and return whether the result is non-zero. + // Insert barriers to ensure that state written before the reference count + // became zero will be visible to a thread that has just made the count zero. + bool Decrement() { + // TODO(jbroman): Technically this doesn't need to be an acquire operation + // unless the result is 1 (i.e., the ref count did indeed reach zero). + // However, there are toolchain issues that make that not work as well at + // present (notably TSAN doesn't like it). + return ref_count_.fetch_sub(1, std::memory_order_acq_rel) != 1; + } + + // Return whether the reference count is one. If the reference count is used + // in the conventional way, a refrerence count of 1 implies that the current + // thread owns the reference and no other thread shares it. This call + // performs the test for a reference count of one, and performs the memory + // barrier needed for the owning thread to act on the object, knowing that it + // has exclusive access to the object. + bool IsOne() const { return ref_count_.load(std::memory_order_acquire) == 1; } + + // Return whether the reference count is zero. With conventional object + // referencing counting, the object will be destroyed, so the reference count + // should never be zero. Hence this is generally used for a debug check. + bool IsZero() const { + return ref_count_.load(std::memory_order_acquire) == 0; + } + + // Returns the current reference count (with no barriers). This is subtle, and + // should be used only for debugging. + int SubtleRefCountForDebug() const { + return ref_count_.load(std::memory_order_relaxed); + } + + private: + std::atomic_int ref_count_; +}; + +} // namespace base + +#endif // BASE_ATOMIC_REF_COUNT_H_ diff --git a/src/3rdparty/gn/base/bind.h b/src/3rdparty/gn/base/bind.h new file mode 100644 index 00000000000..71df0fe952a --- /dev/null +++ b/src/3rdparty/gn/base/bind.h @@ -0,0 +1,457 @@ +// 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 + +#include "base/bind_internal.h" + +// ----------------------------------------------------------------------------- +// Usage documentation +// ----------------------------------------------------------------------------- +// +// Overview: +// base::BindOnce() and base::BindRepeating() are helpers for creating +// base::OnceCallback and base::RepeatingCallback objects respectively. +// +// For a runnable object of n-arity, the base::Bind*() family allows partial +// application of the first m arguments. The remaining n - m arguments must be +// passed when invoking the callback with Run(). +// +// // The first argument is bound at callback creation; the remaining +// // two must be passed when calling Run() on the callback object. +// base::OnceCallback cb = base::BindOnce( +// [](short x, int y, long z) { return x * y * z; }, 42); +// +// When binding to a method, the receiver object must also be specified at +// callback creation time. When Run() is invoked, the method will be invoked on +// the specified receiver object. +// +// class C : public base::RefCounted { void F(); }; +// auto instance = base::MakeRefCounted(); +// auto cb = base::BindOnce(&C::F, instance); +// cb.Run(); // Identical to instance->F() +// +// base::Bind is currently a type alias for base::BindRepeating(). In the +// future, we expect to flip this to default to base::BindOnce(). +// +// See //docs/callback.md for the full 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. + +namespace base { + +namespace internal { + +// IsOnceCallback is a std::true_type if |T| is a OnceCallback. +template +struct IsOnceCallback : std::false_type {}; + +template +struct IsOnceCallback> : std::true_type {}; + +// Helper to assert that parameter |i| of type |Arg| can be bound, which means: +// - |Arg| can be retained internally as |Storage|. +// - |Arg| can be forwarded as |Unwrapped| to |Param|. +template +struct AssertConstructible { + private: + static constexpr bool param_is_forwardable = + std::is_constructible::value; + // Unlike the check for binding into storage below, the check for + // forwardability drops the const qualifier for repeating callbacks. This is + // to try to catch instances where std::move()--which forwards as a const + // reference with repeating callbacks--is used instead of base::Passed(). + static_assert( + param_is_forwardable || + !std::is_constructible&&>::value, + "Bound argument |i| is move-only but will be forwarded by copy. " + "Ensure |Arg| is bound using base::Passed(), not std::move()."); + static_assert( + param_is_forwardable, + "Bound argument |i| of type |Arg| cannot be forwarded as " + "|Unwrapped| to the bound functor, which declares it as |Param|."); + + static constexpr bool arg_is_storable = + std::is_constructible::value; + static_assert(arg_is_storable || + !std::is_constructible&&>::value, + "Bound argument |i| is move-only but will be bound by copy. " + "Ensure |Arg| is mutable and bound using std::move()."); + static_assert(arg_is_storable, + "Bound argument |i| of type |Arg| cannot be converted and " + "bound as |Storage|."); +}; + +// Takes three same-length TypeLists, and applies AssertConstructible for each +// triples. +template +struct AssertBindArgsValidity; + +template +struct AssertBindArgsValidity, + TypeList, + TypeList, + TypeList> + : AssertConstructible, Unwrapped, Params>... { + static constexpr bool ok = true; +}; + +// The implementation of TransformToUnwrappedType below. +template +struct TransformToUnwrappedTypeImpl; + +template +struct TransformToUnwrappedTypeImpl { + using StoredType = std::decay_t; + using ForwardType = StoredType&&; + using Unwrapped = decltype(Unwrap(std::declval())); +}; + +template +struct TransformToUnwrappedTypeImpl { + using StoredType = std::decay_t; + using ForwardType = const StoredType&; + using Unwrapped = decltype(Unwrap(std::declval())); +}; + +// Transform |T| into `Unwrapped` type, which is passed to the target function. +// Example: +// In is_once == true case, +// `int&&` -> `int&&`, +// `const int&` -> `int&&`, +// `OwnedWrapper&` -> `int*&&`. +// In is_once == false case, +// `int&&` -> `const int&`, +// `const int&` -> `const int&`, +// `OwnedWrapper&` -> `int* const &`. +template +using TransformToUnwrappedType = + typename TransformToUnwrappedTypeImpl::Unwrapped; + +// Transforms |Args| into `Unwrapped` types, and packs them into a TypeList. +// If |is_method| is true, tries to dereference the first argument to support +// smart pointers. +template +struct MakeUnwrappedTypeListImpl { + using Type = TypeList...>; +}; + +// Performs special handling for this pointers. +// Example: +// int* -> int*, +// std::unique_ptr -> int*. +template +struct MakeUnwrappedTypeListImpl { + using UnwrappedReceiver = TransformToUnwrappedType; + using Type = TypeList()), + TransformToUnwrappedType...>; +}; + +template +using MakeUnwrappedTypeList = + typename MakeUnwrappedTypeListImpl::Type; + +} // namespace internal + +// Bind as OnceCallback. +template +inline OnceCallback> BindOnce( + Functor&& functor, + Args&&... args) { + static_assert(!internal::IsOnceCallback>() || + (std::is_rvalue_reference() && + !std::is_const>()), + "BindOnce requires non-const rvalue for OnceCallback binding." + " I.e.: base::BindOnce(std::move(callback))."); + + // This block checks if each |args| matches to the corresponding params of the + // target function. This check does not affect the behavior of Bind, but its + // error message should be more readable. + using Helper = internal::BindTypeHelper; + using FunctorTraits = typename Helper::FunctorTraits; + using BoundArgsList = typename Helper::BoundArgsList; + using UnwrappedArgsList = + internal::MakeUnwrappedTypeList; + using BoundParamsList = typename Helper::BoundParamsList; + static_assert(internal::AssertBindArgsValidity< + std::make_index_sequence, BoundArgsList, + UnwrappedArgsList, BoundParamsList>::ok, + "The bound args need to be convertible to the target params."); + + using BindState = internal::MakeBindStateType; + using UnboundRunType = MakeUnboundRunType; + using Invoker = internal::Invoker; + using CallbackType = OnceCallback; + + // Store the invoke func into PolymorphicInvoke before casting it to + // InvokeFuncStorage, so that we can ensure its type matches to + // PolymorphicInvoke, to which CallbackType will cast back. + using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke; + PolymorphicInvoke invoke_func = &Invoker::RunOnce; + + using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage; + return CallbackType(new BindState( + reinterpret_cast(invoke_func), + std::forward(functor), std::forward(args)...)); +} + +// Bind as RepeatingCallback. +template +inline RepeatingCallback> BindRepeating( + Functor&& functor, + Args&&... args) { + static_assert( + !internal::IsOnceCallback>(), + "BindRepeating cannot bind OnceCallback. Use BindOnce with std::move()."); + + // This block checks if each |args| matches to the corresponding params of the + // target function. This check does not affect the behavior of Bind, but its + // error message should be more readable. + using Helper = internal::BindTypeHelper; + using FunctorTraits = typename Helper::FunctorTraits; + using BoundArgsList = typename Helper::BoundArgsList; + using UnwrappedArgsList = + internal::MakeUnwrappedTypeList; + using BoundParamsList = typename Helper::BoundParamsList; + static_assert(internal::AssertBindArgsValidity< + std::make_index_sequence, BoundArgsList, + UnwrappedArgsList, BoundParamsList>::ok, + "The bound args need to be convertible to the target params."); + + using BindState = internal::MakeBindStateType; + using UnboundRunType = MakeUnboundRunType; + using Invoker = internal::Invoker; + using CallbackType = RepeatingCallback; + + // Store the invoke func into PolymorphicInvoke before casting it to + // InvokeFuncStorage, so that we can ensure its type matches to + // PolymorphicInvoke, to which CallbackType will cast back. + using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke; + PolymorphicInvoke invoke_func = &Invoker::Run; + + using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage; + return CallbackType(new BindState( + reinterpret_cast(invoke_func), + std::forward(functor), std::forward(args)...)); +} + +// Unannotated Bind. +// TODO(tzik): Deprecate this and migrate to OnceCallback and +// RepeatingCallback, once they get ready. +template +inline Callback> Bind(Functor&& functor, + Args&&... args) { + return base::BindRepeating(std::forward(functor), + std::forward(args)...); +} + +// Special cases for binding to a base::Callback without extra bound arguments. +template +OnceCallback BindOnce(OnceCallback closure) { + return closure; +} + +template +RepeatingCallback BindRepeating( + RepeatingCallback closure) { + return closure; +} + +template +Callback Bind(Callback closure) { + return closure; +} + +// Unretained() allows Bind() to bind a non-refcounted class, and to disable +// refcounting on arguments that are refcounted objects. +// +// 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. +template +static inline internal::UnretainedWrapper Unretained(T* o) { + return internal::UnretainedWrapper(o); +} + +// RetainedRef() accepts a ref counted object and retains a reference to it. +// When the callback is called, the object is passed as a raw pointer. +// +// EXAMPLE OF RetainedRef(): +// +// void foo(RefCountedBytes* bytes) {} +// +// scoped_refptr bytes = ...; +// Closure callback = Bind(&foo, base::RetainedRef(bytes)); +// callback.Run(); +// +// Without RetainedRef, the scoped_refptr would try to implicitly convert to +// a raw pointer and fail compilation: +// +// Closure callback = Bind(&foo, bytes); // ERROR! +template +static inline internal::RetainedRefWrapper RetainedRef(T* o) { + return internal::RetainedRefWrapper(o); +} +template +static inline internal::RetainedRefWrapper RetainedRef(scoped_refptr o) { + return internal::RetainedRefWrapper(std::move(o)); +} + +// ConstRef() allows binding a constant reference to an argument rather +// than a copy. +// +// 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. +template +static inline internal::ConstRefWrapper ConstRef(const T& o) { + return internal::ConstRefWrapper(o); +} + +// Owned() transfers ownership of an object to the Callback resulting from +// bind; the object will be deleted when the Callback is deleted. +// +// 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. +template +static inline internal::OwnedWrapper Owned(T* o) { + return internal::OwnedWrapper(o); +} + +// Passed() is for transferring movable-but-not-copyable types (eg. unique_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. +// +// Note that Passed() is not necessary with BindOnce(), as std::move() does the +// same thing. Avoid Passed() in favor of std::move() with BindOnce(). +// +// EXAMPLE OF Passed(): +// +// void TakesOwnership(std::unique_ptr arg) { } +// std::unique_ptr CreateFoo() { return std::make_unique(); +// } +// +// auto f = std::make_unique(); +// +// // |cb| is given ownership of Foo(). |f| is now NULL. +// // You can use std::move(f) in place of &f, but it's more verbose. +// Closure cb = Bind(&TakesOwnership, Passed(&f)); +// +// // Run was never called so |cb| still owns Foo() and deletes +// // it on Reset(). +// cb.Reset(); +// +// // |cb| is given a new Foo created by CreateFoo(). +// cb = Bind(&TakesOwnership, Passed(CreateFoo())); +// +// // |arg| in TakesOwnership() is given ownership of Foo(). |cb| +// // no longer owns Foo() and, if reset, would not delete Foo(). +// cb.Run(); // Foo() is now transferred to |arg| and deleted. +// cb.Run(); // This CHECK()s since Foo() already been used once. +// +// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and +// is best suited for use with the return value of a function or other temporary +// rvalues. The second takes a pointer to the scoper and is just syntactic sugar +// to avoid having to write Passed(std::move(scoper)). +// +// Both versions of Passed() prevent T from being an lvalue reference. The first +// via use of enable_if, and the second takes a T* which will not bind to T&. +template ::value>* = nullptr> +static inline internal::PassedWrapper Passed(T&& scoper) { + return internal::PassedWrapper(std::move(scoper)); +} +template +static inline internal::PassedWrapper Passed(T* scoper) { + return internal::PassedWrapper(std::move(*scoper)); +} + +// 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 IgnoreResult(): +// +// int DoSomething(int arg) { cout << arg << endl; } +// +// // Assign to a Callback with a void return type. +// Callback cb = Bind(IgnoreResult(&DoSomething)); +// cb->Run(1); // Prints "1". +// +// // Prints "1" on |ml|. +// ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1); +template +static inline internal::IgnoreResultHelper IgnoreResult(T data) { + return internal::IgnoreResultHelper(std::move(data)); +} + +} // namespace base + +#endif // BASE_BIND_H_ diff --git a/src/3rdparty/gn/base/bind_internal.h b/src/3rdparty/gn/base/bind_internal.h new file mode 100644 index 00000000000..0dc59e60c9a --- /dev/null +++ b/src/3rdparty/gn/base/bind_internal.h @@ -0,0 +1,912 @@ +// 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 + +#include +#include + +#include "base/callback_internal.h" +#include "base/memory/raw_scoped_refptr_mismatch_checker.h" +#include "base/memory/weak_ptr.h" +#include "base/template_util.h" +#include "util/build_config.h" + +// See base/callback.h for user documentation. +// +// +// CONCEPTS: +// Functor -- A movable type representing something that should be called. +// All function pointers and Callback<> are functors even if the +// invocation syntax differs. +// RunType -- A function type (as opposed to function _pointer_ type) for +// a Callback<>::Run(). Usually just a convenience typedef. +// (Bound)Args -- A set of types that stores the arguments. +// +// Types: +// ForceVoidReturn<> -- Helper class for translating function signatures to +// equivalent forms with a "void" return type. +// FunctorTraits<> -- Type traits used to determine the correct RunType and +// invocation manner for a Functor. This is where function +// signature adapters are applied. +// InvokeHelper<> -- Take a Functor + arguments and actully invokes it. +// Handle the differing syntaxes needed for WeakPtr<> +// support. This is separate from Invoker to avoid creating +// multiple version of Invoker<>. +// Invoker<> -- Unwraps the curried parameters and executes the Functor. +// BindState<> -- Stores the curried parameters, and is the main entry point +// into the Bind() system. + +namespace base { + +template +struct IsWeakReceiver; + +template +struct BindUnwrapTraits; + +template +struct CallbackCancellationTraits; + +namespace internal { + +template +struct FunctorTraits; + +template +class UnretainedWrapper { + public: + explicit UnretainedWrapper(T* o) : ptr_(o) {} + T* get() const { return ptr_; } + + private: + T* ptr_; +}; + +template +class ConstRefWrapper { + public: + explicit ConstRefWrapper(const T& o) : ptr_(&o) {} + const T& get() const { return *ptr_; } + + private: + const T* ptr_; +}; + +template +class RetainedRefWrapper { + public: + explicit RetainedRefWrapper(T* o) : ptr_(o) {} + explicit RetainedRefWrapper(scoped_refptr o) : ptr_(std::move(o)) {} + T* get() const { return ptr_.get(); } + + private: + scoped_refptr ptr_; +}; + +template +struct IgnoreResultHelper { + explicit IgnoreResultHelper(T functor) : functor_(std::move(functor)) {} + explicit operator bool() const { return !!functor_; } + + 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 std::unique_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 +class OwnedWrapper { + public: + explicit OwnedWrapper(T* o) : ptr_(o) {} + ~OwnedWrapper() { delete ptr_; } + T* get() const { return ptr_; } + OwnedWrapper(OwnedWrapper&& other) { + ptr_ = other.ptr_; + other.ptr_ = NULL; + } + + private: + mutable T* ptr_; +}; + +// PassedWrapper is a copyable adapter for a scoper that ignores const. +// +// It is needed to get around the fact that Bind() takes a const reference to +// all its arguments. Because Bind() takes a const reference to avoid +// unnecessary copies, it is incompatible with movable-but-not-copyable +// types; doing a destructive "move" of the type into Bind() would violate +// the const correctness. +// +// This conundrum cannot be solved without either C++11 rvalue references or +// a O(2^n) blowup of Bind() templates to handle each combination of regular +// types and movable-but-not-copyable types. Thus we introduce a wrapper type +// that is copyable to transmit the correct type information down into +// BindState<>. Ignoring const in this type makes sense because it is only +// created when we are explicitly trying to do a destructive move. +// +// Two notes: +// 1) PassedWrapper supports any type that has a move constructor, however +// the type will need to be specifically whitelisted in order for it to be +// bound to a Callback. We guard this explicitly at the call of Passed() +// to make for clear errors. Things not given to Passed() will be forwarded +// and stored by value which will not work for general move-only types. +// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL" +// scoper to a Callback and allow the Callback to execute once. +template +class PassedWrapper { + public: + explicit PassedWrapper(T&& scoper) + : is_valid_(true), scoper_(std::move(scoper)) {} + PassedWrapper(PassedWrapper&& other) + : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {} + T Take() const { + CHECK(is_valid_); + is_valid_ = false; + return std::move(scoper_); + } + + private: + mutable bool is_valid_; + mutable T scoper_; +}; + +template +using Unwrapper = BindUnwrapTraits>; + +template +decltype(auto) Unwrap(T&& o) { + return Unwrapper::Unwrap(std::forward(o)); +} + +// 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 +struct IsWeakMethod : std::false_type {}; + +template +struct IsWeakMethod : IsWeakReceiver {}; + +// Packs a list of types to hold them in a single type. +template +struct TypeList {}; + +// Used for DropTypeListItem implementation. +template +struct DropTypeListItemImpl; + +// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure. +template +struct DropTypeListItemImpl> + : DropTypeListItemImpl> {}; + +template +struct DropTypeListItemImpl<0, TypeList> { + using Type = TypeList; +}; + +template <> +struct DropTypeListItemImpl<0, TypeList<>> { + using Type = TypeList<>; +}; + +// A type-level function that drops |n| list item from given TypeList. +template +using DropTypeListItem = typename DropTypeListItemImpl::Type; + +// Used for TakeTypeListItem implementation. +template +struct TakeTypeListItemImpl; + +// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure. +template +struct TakeTypeListItemImpl, Accum...> + : TakeTypeListItemImpl, Accum..., T> {}; + +template +struct TakeTypeListItemImpl<0, TypeList, Accum...> { + using Type = TypeList; +}; + +template +struct TakeTypeListItemImpl<0, TypeList<>, Accum...> { + using Type = TypeList; +}; + +// A type-level function that takes first |n| list item from given TypeList. +// E.g. TakeTypeListItem<3, TypeList> is evaluated to +// TypeList. +template +using TakeTypeListItem = typename TakeTypeListItemImpl::Type; + +// Used for ConcatTypeLists implementation. +template +struct ConcatTypeListsImpl; + +template +struct ConcatTypeListsImpl, TypeList> { + using Type = TypeList; +}; + +// A type-level function that concats two TypeLists. +template +using ConcatTypeLists = typename ConcatTypeListsImpl::Type; + +// Used for MakeFunctionType implementation. +template +struct MakeFunctionTypeImpl; + +template +struct MakeFunctionTypeImpl> { + // MSVC 2013 doesn't support Type Alias of function types. + // Revisit this after we update it to newer version. + typedef R Type(Args...); +}; + +// A type-level function that constructs a function type that has |R| as its +// return type and has TypeLists items as its arguments. +template +using MakeFunctionType = typename MakeFunctionTypeImpl::Type; + +// Used for ExtractArgs and ExtractReturnType. +template +struct ExtractArgsImpl; + +template +struct ExtractArgsImpl { + using ReturnType = R; + using ArgsList = TypeList; +}; + +// A type-level function that extracts function arguments into a TypeList. +// E.g. ExtractArgs is evaluated to TypeList. +template +using ExtractArgs = typename ExtractArgsImpl::ArgsList; + +// A type-level function that extracts the return type of a function. +// E.g. ExtractReturnType is evaluated to R. +template +using ExtractReturnType = typename ExtractArgsImpl::ReturnType; + +template +struct ExtractCallableRunTypeImpl; + +template +struct ExtractCallableRunTypeImpl { + using Type = R(Args...); +}; + +template +struct ExtractCallableRunTypeImpl { + using Type = R(Args...); +}; + +// Evaluated to RunType of the given callable type. +// Example: +// auto f = [](int, char*) { return 0.1; }; +// ExtractCallableRunType +// is evaluated to +// double(int, char*); +template +using ExtractCallableRunType = + typename ExtractCallableRunTypeImpl::Type; + +// IsCallableObject is std::true_type if |Functor| has operator(). +// Otherwise, it's std::false_type. +// Example: +// IsCallableObject::value is false. +// +// struct Foo {}; +// IsCallableObject::value is false. +// +// int i = 0; +// auto f = [i]() {}; +// IsCallableObject::value is false. +template +struct IsCallableObject : std::false_type {}; + +template +struct IsCallableObject> + : std::true_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 +struct HasRefCountedTypeAsRawPtr : std::false_type {}; + +// Implementation note: Select true_type if the first parameter is a raw pointer +// to a RefCounted type. Otherwise, skip the first parameter and check rest of +// parameters recursively. +template +struct HasRefCountedTypeAsRawPtr + : std::conditional_t::value, + std::true_type, + HasRefCountedTypeAsRawPtr> {}; + +// ForceVoidReturn<> +// +// Set of templates that support forcing the function return type to void. +template +struct ForceVoidReturn; + +template +struct ForceVoidReturn { + using RunType = void(Args...); +}; + +// FunctorTraits<> +// +// See description at top of file. +template +struct FunctorTraits; + +// For empty callable types. +// This specialization is intended to allow binding captureless lambdas by +// base::Bind(), based on the fact that captureless lambdas are empty while +// capturing lambdas are not. This also allows any functors as far as it's an +// empty class. +// Example: +// +// // Captureless lambdas are allowed. +// []() {return 42;}; +// +// // Capturing lambdas are *not* allowed. +// int x; +// [x]() {return x;}; +// +// // Any empty class with operator() is allowed. +// struct Foo { +// void operator()() const {} +// // No non-static member variable and no virtual functions. +// }; +template +struct FunctorTraits::value && + std::is_empty::value>> { + using RunType = ExtractCallableRunType; + static constexpr bool is_method = false; + static constexpr bool is_nullable = false; + + template + static ExtractReturnType Invoke(RunFunctor&& functor, + RunArgs&&... args) { + return std::forward(functor)(std::forward(args)...); + } +}; + +// For functions. +template +struct FunctorTraits { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; + + template + static R Invoke(Function&& function, RunArgs&&... args) { + return std::forward(function)(std::forward(args)...); + } +}; + +#if defined(OS_WIN) && !defined(ARCH_CPU_X86_64) + +// For functions. +template +struct FunctorTraits { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; + + template + static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) { + return function(std::forward(args)...); + } +}; + +// For functions. +template +struct FunctorTraits { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; + + template + static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) { + return function(std::forward(args)...); + } +}; + +#endif // defined(OS_WIN) && !defined(ARCH_CPU_X86_64) + +// For methods. +template +struct FunctorTraits { + using RunType = R(Receiver*, Args...); + static constexpr bool is_method = true; + static constexpr bool is_nullable = true; + + template + static R Invoke(Method method, + ReceiverPtr&& receiver_ptr, + RunArgs&&... args) { + return ((*receiver_ptr).*method)(std::forward(args)...); + } +}; + +// For const methods. +template +struct FunctorTraits { + using RunType = R(const Receiver*, Args...); + static constexpr bool is_method = true; + static constexpr bool is_nullable = true; + + template + static R Invoke(Method method, + ReceiverPtr&& receiver_ptr, + RunArgs&&... args) { + return ((*receiver_ptr).*method)(std::forward(args)...); + } +}; + +#ifdef __cpp_noexcept_function_type +// noexcept makes a distinct function type in C++17. +// I.e. `void(*)()` and `void(*)() noexcept` are same in pre-C++17, and +// different in C++17. +template +struct FunctorTraits : FunctorTraits { +}; + +template +struct FunctorTraits + : FunctorTraits {}; + +template +struct FunctorTraits + : FunctorTraits {}; +#endif + +// For IgnoreResults. +template +struct FunctorTraits> : FunctorTraits { + using RunType = + typename ForceVoidReturn::RunType>::RunType; + + template + static void Invoke(IgnoreResultType&& ignore_result_helper, + RunArgs&&... args) { + FunctorTraits::Invoke( + std::forward(ignore_result_helper).functor_, + std::forward(args)...); + } +}; + +// For OnceCallbacks. +template +struct FunctorTraits> { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; + + template + static R Invoke(CallbackType&& callback, RunArgs&&... args) { + DCHECK(!callback.is_null()); + return std::forward(callback).Run( + std::forward(args)...); + } +}; + +// For RepeatingCallbacks. +template +struct FunctorTraits> { + using RunType = R(Args...); + static constexpr bool is_method = false; + static constexpr bool is_nullable = true; + + template + static R Invoke(CallbackType&& callback, RunArgs&&... args) { + DCHECK(!callback.is_null()); + return std::forward(callback).Run( + std::forward(args)...); + } +}; + +template +using MakeFunctorTraits = FunctorTraits>; + +// InvokeHelper<> +// +// There are 2 logical InvokeHelper<> specializations: normal, WeakCalls. +// +// The normal type just calls the underlying runnable. +// +// WeakCalls need special syntax that is applied to the first argument to check +// if they should no-op themselves. +template +struct InvokeHelper; + +template +struct InvokeHelper { + template + static inline ReturnType MakeItSo(Functor&& functor, RunArgs&&... args) { + using Traits = MakeFunctorTraits; + return Traits::Invoke(std::forward(functor), + std::forward(args)...); + } +}; + +template +struct InvokeHelper { + // WeakCalls are only supported for functions with a void return type. + // Otherwise, the function result would be undefined if the the WeakPtr<> + // is invalidated. + static_assert(std::is_void::value, + "weak_ptrs can only bind to methods without return values"); + + template + static inline void MakeItSo(Functor&& functor, + BoundWeakPtr&& weak_ptr, + RunArgs&&... args) { + if (!weak_ptr) + return; + using Traits = MakeFunctorTraits; + Traits::Invoke(std::forward(functor), + std::forward(weak_ptr), + std::forward(args)...); + } +}; + +// Invoker<> +// +// See description at the top of the file. +template +struct Invoker; + +template +struct Invoker { + static R RunOnce(BindStateBase* base, + PassingTraitsType... unbound_args) { + // 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. + StorageType* storage = static_cast(base); + static constexpr size_t num_bound_args = + std::tuple_sizebound_args_)>::value; + return RunImpl(std::move(storage->functor_), + std::move(storage->bound_args_), + std::make_index_sequence(), + std::forward(unbound_args)...); + } + + static R Run(BindStateBase* base, + PassingTraitsType... unbound_args) { + // 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. + const StorageType* storage = static_cast(base); + static constexpr size_t num_bound_args = + std::tuple_sizebound_args_)>::value; + return RunImpl(storage->functor_, storage->bound_args_, + std::make_index_sequence(), + std::forward(unbound_args)...); + } + + private: + template + static inline R RunImpl(Functor&& functor, + BoundArgsTuple&& bound, + std::index_sequence, + UnboundArgs&&... unbound_args) { + static constexpr bool is_method = MakeFunctorTraits::is_method; + + using DecayedArgsTuple = std::decay_t; + static constexpr bool is_weak_call = + IsWeakMethod...>(); + + return InvokeHelper::MakeItSo( + std::forward(functor), + Unwrap(std::get(std::forward(bound)))..., + std::forward(unbound_args)...); + } +}; + +// Extracts necessary type info from Functor and BoundArgs. +// Used to implement MakeUnboundRunType, BindOnce and BindRepeating. +template +struct BindTypeHelper { + static constexpr size_t num_bounds = sizeof...(BoundArgs); + using FunctorTraits = MakeFunctorTraits; + + // Example: + // When Functor is `double (Foo::*)(int, const std::string&)`, and BoundArgs + // is a template pack of `Foo*` and `int16_t`: + // - RunType is `double(Foo*, int, const std::string&)`, + // - ReturnType is `double`, + // - RunParamsList is `TypeList`, + // - BoundParamsList is `TypeList`, + // - UnboundParamsList is `TypeList`, + // - BoundArgsList is `TypeList`, + // - UnboundRunType is `double(const std::string&)`. + using RunType = typename FunctorTraits::RunType; + using ReturnType = ExtractReturnType; + + using RunParamsList = ExtractArgs; + using BoundParamsList = TakeTypeListItem; + using UnboundParamsList = DropTypeListItem; + + using BoundArgsList = TypeList; + + using UnboundRunType = MakeFunctionType; +}; + +template +std::enable_if_t::is_nullable, bool> IsNull( + const Functor& functor) { + return !functor; +} + +template +std::enable_if_t::is_nullable, bool> IsNull( + const Functor&) { + return false; +} + +// Used by ApplyCancellationTraits below. +template +bool ApplyCancellationTraitsImpl(const Functor& functor, + const BoundArgsTuple& bound_args, + std::index_sequence) { + return CallbackCancellationTraits::IsCancelled( + functor, std::get(bound_args)...); +} + +// Relays |base| to corresponding CallbackCancellationTraits<>::Run(). Returns +// true if the callback |base| represents is canceled. +template +bool ApplyCancellationTraits(const BindStateBase* base) { + const BindStateType* storage = static_cast(base); + static constexpr size_t num_bound_args = + std::tuple_sizebound_args_)>::value; + return ApplyCancellationTraitsImpl( + storage->functor_, storage->bound_args_, + std::make_index_sequence()); +}; + +// BindState<> +// +// This stores all the state passed into Bind(). +template +struct BindState final : BindStateBase { + using IsCancellable = std::integral_constant< + bool, + CallbackCancellationTraits>::is_cancellable>; + + template + explicit BindState(BindStateBase::InvokeFuncStorage invoke_func, + ForwardFunctor&& functor, + ForwardBoundArgs&&... bound_args) + // IsCancellable is std::false_type if + // CallbackCancellationTraits<>::IsCancelled returns always false. + // Otherwise, it's std::true_type. + : BindState(IsCancellable{}, + invoke_func, + std::forward(functor), + std::forward(bound_args)...) {} + + Functor functor_; + std::tuple bound_args_; + + private: + template + explicit BindState(std::true_type, + BindStateBase::InvokeFuncStorage invoke_func, + ForwardFunctor&& functor, + ForwardBoundArgs&&... bound_args) + : BindStateBase(invoke_func, + &Destroy, + &ApplyCancellationTraits), + functor_(std::forward(functor)), + bound_args_(std::forward(bound_args)...) { + DCHECK(!IsNull(functor_)); + } + + template + explicit BindState(std::false_type, + BindStateBase::InvokeFuncStorage invoke_func, + ForwardFunctor&& functor, + ForwardBoundArgs&&... bound_args) + : BindStateBase(invoke_func, &Destroy), + functor_(std::forward(functor)), + bound_args_(std::forward(bound_args)...) { + DCHECK(!IsNull(functor_)); + } + + ~BindState() = default; + + static void Destroy(const BindStateBase* self) { + delete static_cast(self); + } +}; + +// Used to implement MakeBindStateType. +template +struct MakeBindStateTypeImpl; + +template +struct MakeBindStateTypeImpl { + static_assert(!HasRefCountedTypeAsRawPtr...>::value, + "A parameter is a refcounted type and needs scoped_refptr."); + using Type = BindState, std::decay_t...>; +}; + +template +struct MakeBindStateTypeImpl { + using Type = BindState>; +}; + +template +struct MakeBindStateTypeImpl { + private: + using DecayedReceiver = std::decay_t; + + static_assert(!std::is_array>::value, + "First bound argument to a method cannot be an array."); + static_assert( + !std::is_pointer::value || + IsRefCountedType>::value, + "Receivers may not be raw pointers. If using a raw pointer here is safe" + " and has no lifetime concerns, use base::Unretained() and document why" + " it's safe."); + static_assert(!HasRefCountedTypeAsRawPtr...>::value, + "A parameter is a refcounted type and needs scoped_refptr."); + + public: + using Type = BindState< + std::decay_t, + std::conditional_t::value, + scoped_refptr>, + DecayedReceiver>, + std::decay_t...>; +}; + +template +using MakeBindStateType = + typename MakeBindStateTypeImpl::is_method, + Functor, + BoundArgs...>::Type; + +} // namespace internal + +// An injection point to control |this| pointer behavior on a method invocation. +// If IsWeakReceiver<> is true_type for |T| and |T| is used for a receiver of a +// method, base::Bind cancels the method invocation if the receiver is tested as +// false. +// E.g. Foo::bar() is not called: +// struct Foo : base::SupportsWeakPtr { +// void bar() {} +// }; +// +// WeakPtr oo = nullptr; +// base::Bind(&Foo::bar, oo).Run(); +template +struct IsWeakReceiver : std::false_type {}; + +template +struct IsWeakReceiver> : IsWeakReceiver {}; + +template +struct IsWeakReceiver> : std::true_type {}; + +// An injection point to control how bound objects passed to the target +// function. BindUnwrapTraits<>::Unwrap() is called for each bound objects right +// before the target function is invoked. +template +struct BindUnwrapTraits { + template + static T&& Unwrap(T&& o) { + return std::forward(o); + } +}; + +template +struct BindUnwrapTraits> { + static T* Unwrap(const internal::UnretainedWrapper& o) { return o.get(); } +}; + +template +struct BindUnwrapTraits> { + static const T& Unwrap(const internal::ConstRefWrapper& o) { + return o.get(); + } +}; + +template +struct BindUnwrapTraits> { + static T* Unwrap(const internal::RetainedRefWrapper& o) { return o.get(); } +}; + +template +struct BindUnwrapTraits> { + static T* Unwrap(const internal::OwnedWrapper& o) { return o.get(); } +}; + +template +struct BindUnwrapTraits> { + static T Unwrap(const internal::PassedWrapper& o) { return o.Take(); } +}; + +// CallbackCancellationTraits allows customization of Callback's cancellation +// semantics. By default, callbacks are not cancellable. A specialization should +// set is_cancellable = true and implement an IsCancelled() that returns if the +// callback should be cancelled. +template +struct CallbackCancellationTraits { + static constexpr bool is_cancellable = false; +}; + +// Specialization for method bound to weak pointer receiver. +template +struct CallbackCancellationTraits< + Functor, + std::tuple, + std::enable_if_t< + internal::IsWeakMethod::is_method, + BoundArgs...>::value>> { + static constexpr bool is_cancellable = true; + + template + static bool IsCancelled(const Functor&, + const Receiver& receiver, + const Args&...) { + return !receiver; + } +}; + +// Specialization for a nested bind. +template +struct CallbackCancellationTraits, + std::tuple> { + static constexpr bool is_cancellable = true; + + template + static bool IsCancelled(const Functor& functor, const BoundArgs&...) { + return functor.IsCancelled(); + } +}; + +template +struct CallbackCancellationTraits, + std::tuple> { + static constexpr bool is_cancellable = true; + + template + static bool IsCancelled(const Functor& functor, const BoundArgs&...) { + return functor.IsCancelled(); + } +}; + +// Returns a RunType of bound functor. +// E.g. MakeUnboundRunType is evaluated to R(C). +template +using MakeUnboundRunType = + typename internal::BindTypeHelper::UnboundRunType; + +} // namespace base + +#endif // BASE_BIND_INTERNAL_H_ diff --git a/src/3rdparty/gn/base/callback.h b/src/3rdparty/gn/base/callback.h new file mode 100644 index 00000000000..1b84f403969 --- /dev/null +++ b/src/3rdparty/gn/base/callback.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. +// +// NOTE: Header files that do not require the full definition of Callback or +// Closure should #include "base/callback_forward.h" instead of this file. + +#ifndef BASE_CALLBACK_H_ +#define BASE_CALLBACK_H_ + +#include "base/callback_forward.h" +#include "base/callback_internal.h" + +// ----------------------------------------------------------------------------- +// Usage documentation +// ----------------------------------------------------------------------------- +// +// Overview: +// A callback is similar in concept to a function pointer: it wraps a runnable +// object such as a function, method, lambda, or even another callback, allowing +// the runnable object to be invoked later via the callback object. +// +// Unlike function pointers, callbacks are created with base::BindOnce() or +// base::BindRepeating() and support partial function application. +// +// A base::OnceCallback may be Run() at most once; a base::RepeatingCallback may +// be Run() any number of times. |is_null()| is guaranteed to return true for a +// moved-from callback. +// +// // The lambda takes two arguments, but the first argument |x| is bound at +// // callback creation. +// base::OnceCallback cb = base::BindOnce([] (int x, int y) { +// return x + y; +// }, 1); +// // Run() only needs the remaining unbound argument |y|. +// printf("1 + 2 = %d\n", std::move(cb).Run(2)); // Prints 3 +// printf("cb is null? %s\n", +// cb.is_null() ? "true" : "false"); // Prints true +// std::move(cb).Run(2); // Crashes since |cb| has already run. +// +// Callbacks also support cancellation. A common use is binding the receiver +// object as a WeakPtr. If that weak pointer is invalidated, calling Run() +// will be a no-op. Note that |is_cancelled()| and |is_null()| are distinct: +// simply cancelling a callback will not also make it null. +// +// base::Callback is currently a type alias for base::RepeatingCallback. In the +// future, we expect to flip this to default to base::OnceCallback. +// +// See //docs/callback.md for the full documentation. + +namespace base { + +template +class OnceCallback : public internal::CallbackBase { + public: + using RunType = R(Args...); + using PolymorphicInvoke = R (*)(internal::BindStateBase*, + internal::PassingTraitsType...); + + constexpr OnceCallback() = default; + + explicit OnceCallback(internal::BindStateBase* bind_state) + : internal::CallbackBase(bind_state) {} + + OnceCallback(const OnceCallback&) = delete; + OnceCallback& operator=(const OnceCallback&) = delete; + + OnceCallback(OnceCallback&&) noexcept = default; + OnceCallback& operator=(OnceCallback&&) noexcept = default; + + OnceCallback(RepeatingCallback other) + : internal::CallbackBase(std::move(other)) {} + + OnceCallback& operator=(RepeatingCallback other) { + static_cast(*this) = std::move(other); + return *this; + } + + bool Equals(const OnceCallback& other) const { return EqualsInternal(other); } + + R Run(Args... args) const& { + static_assert(!sizeof(*this), + "OnceCallback::Run() may only be invoked on a non-const " + "rvalue, i.e. std::move(callback).Run()."); + NOTREACHED(); + } + + R Run(Args... args) && { + // Move the callback instance into a local variable before the invocation, + // that ensures the internal state is cleared after the invocation. + // It's not safe to touch |this| after the invocation, since running the + // bound function may destroy |this|. + OnceCallback cb = std::move(*this); + PolymorphicInvoke f = + reinterpret_cast(cb.polymorphic_invoke()); + return f(cb.bind_state_.get(), std::forward(args)...); + } +}; + +template +class RepeatingCallback : public internal::CallbackBaseCopyable { + public: + using RunType = R(Args...); + using PolymorphicInvoke = R (*)(internal::BindStateBase*, + internal::PassingTraitsType...); + + constexpr RepeatingCallback() = default; + + explicit RepeatingCallback(internal::BindStateBase* bind_state) + : internal::CallbackBaseCopyable(bind_state) {} + + // Copyable and movable. + RepeatingCallback(const RepeatingCallback&) = default; + RepeatingCallback& operator=(const RepeatingCallback&) = default; + RepeatingCallback(RepeatingCallback&&) noexcept = default; + RepeatingCallback& operator=(RepeatingCallback&&) noexcept = default; + + bool Equals(const RepeatingCallback& other) const { + return EqualsInternal(other); + } + + R Run(Args... args) const& { + PolymorphicInvoke f = + reinterpret_cast(this->polymorphic_invoke()); + return f(this->bind_state_.get(), std::forward(args)...); + } + + R Run(Args... args) && { + // Move the callback instance into a local variable before the invocation, + // that ensures the internal state is cleared after the invocation. + // It's not safe to touch |this| after the invocation, since running the + // bound function may destroy |this|. + RepeatingCallback cb = std::move(*this); + PolymorphicInvoke f = + reinterpret_cast(cb.polymorphic_invoke()); + return f(cb.bind_state_.get(), std::forward(args)...); + } +}; + +} // namespace base + +#endif // BASE_CALLBACK_H_ diff --git a/src/3rdparty/gn/base/callback_forward.h b/src/3rdparty/gn/base/callback_forward.h new file mode 100644 index 00000000000..f1851c4fbbf --- /dev/null +++ b/src/3rdparty/gn/base/callback_forward.h @@ -0,0 +1,27 @@ +// 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 +class OnceCallback; + +template +class RepeatingCallback; + +template +using Callback = RepeatingCallback; + +// Syntactic sugar to make Callback easier to declare since it +// will be used in a lot of APIs with delayed execution. +using OnceClosure = OnceCallback; +using RepeatingClosure = RepeatingCallback; +using Closure = Callback; + +} // namespace base + +#endif // BASE_CALLBACK_FORWARD_H_ diff --git a/src/3rdparty/gn/base/callback_internal.cc b/src/3rdparty/gn/base/callback_internal.cc new file mode 100644 index 00000000000..c52d8afaba2 --- /dev/null +++ b/src/3rdparty/gn/base/callback_internal.cc @@ -0,0 +1,93 @@ +// 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 { + +namespace { + +bool ReturnFalse(const BindStateBase*) { + return false; +} + +} // namespace + +void BindStateBaseRefCountTraits::Destruct(const BindStateBase* bind_state) { + bind_state->destructor_(bind_state); +} + +BindStateBase::BindStateBase(InvokeFuncStorage polymorphic_invoke, + void (*destructor)(const BindStateBase*)) + : BindStateBase(polymorphic_invoke, destructor, &ReturnFalse) {} + +BindStateBase::BindStateBase(InvokeFuncStorage polymorphic_invoke, + void (*destructor)(const BindStateBase*), + bool (*is_cancelled)(const BindStateBase*)) + : polymorphic_invoke_(polymorphic_invoke), + destructor_(destructor), + is_cancelled_(is_cancelled) {} + +CallbackBase::CallbackBase(CallbackBase&& c) noexcept = default; +CallbackBase& CallbackBase::operator=(CallbackBase&& c) noexcept = default; +CallbackBase::CallbackBase(const CallbackBaseCopyable& c) + : bind_state_(c.bind_state_) {} + +CallbackBase& CallbackBase::operator=(const CallbackBaseCopyable& c) { + bind_state_ = c.bind_state_; + return *this; +} + +CallbackBase::CallbackBase(CallbackBaseCopyable&& c) noexcept + : bind_state_(std::move(c.bind_state_)) {} + +CallbackBase& CallbackBase::operator=(CallbackBaseCopyable&& c) noexcept { + bind_state_ = std::move(c.bind_state_); + return *this; +} + +void CallbackBase::Reset() { + // 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_ = nullptr; +} + +bool CallbackBase::IsCancelled() const { + DCHECK(bind_state_); + return bind_state_->IsCancelled(); +} + +bool CallbackBase::EqualsInternal(const CallbackBase& other) const { + return bind_state_ == other.bind_state_; +} + +CallbackBase::CallbackBase(BindStateBase* bind_state) + : bind_state_(bind_state ? AdoptRef(bind_state) : nullptr) { + DCHECK(!bind_state_.get() || bind_state_->HasOneRef()); +} + +CallbackBase::~CallbackBase() = default; + +CallbackBaseCopyable::CallbackBaseCopyable(const CallbackBaseCopyable& c) + : CallbackBase(nullptr) { + bind_state_ = c.bind_state_; +} + +CallbackBaseCopyable::CallbackBaseCopyable(CallbackBaseCopyable&& c) noexcept = + default; + +CallbackBaseCopyable& CallbackBaseCopyable::operator=( + const CallbackBaseCopyable& c) { + bind_state_ = c.bind_state_; + return *this; +} + +CallbackBaseCopyable& CallbackBaseCopyable::operator=( + CallbackBaseCopyable&& c) noexcept = default; + +} // namespace internal +} // namespace base diff --git a/src/3rdparty/gn/base/callback_internal.h b/src/3rdparty/gn/base/callback_internal.h new file mode 100644 index 00000000000..7e5180f317a --- /dev/null +++ b/src/3rdparty/gn/base/callback_internal.h @@ -0,0 +1,172 @@ +// 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 "base/callback_forward.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" + +namespace base { + +struct FakeBindState; + +namespace internal { + +class CallbackBase; +class CallbackBaseCopyable; + +class BindStateBase; + +template +struct BindState; + +struct BindStateBaseRefCountTraits { + static void Destruct(const BindStateBase*); +}; + +template ::value> +struct PassingTraits; + +template +struct PassingTraits { + using Type = T&&; +}; + +template +struct PassingTraits { + using Type = T; +}; + +template +using PassingTraitsType = typename PassingTraits::Type; + +// 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 + : public RefCountedThreadSafe { + public: + REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); + + using InvokeFuncStorage = void (*)(); + + private: + BindStateBase(InvokeFuncStorage polymorphic_invoke, + void (*destructor)(const BindStateBase*)); + BindStateBase(InvokeFuncStorage polymorphic_invoke, + void (*destructor)(const BindStateBase*), + bool (*is_cancelled)(const BindStateBase*)); + + ~BindStateBase() = default; + + friend struct BindStateBaseRefCountTraits; + friend class RefCountedThreadSafe; + + friend class CallbackBase; + friend class CallbackBaseCopyable; + + // Whitelist subclasses that access the destructor of BindStateBase. + template + friend struct BindState; + friend struct ::base::FakeBindState; + + bool IsCancelled() const { return is_cancelled_(this); } + + // 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. + InvokeFuncStorage polymorphic_invoke_; + + // Pointer to a function that will properly destroy |this|. + void (*destructor_)(const BindStateBase*); + bool (*is_cancelled_)(const BindStateBase*); + + DISALLOW_COPY_AND_ASSIGN(BindStateBase); +}; + +// Holds the Callback methods that don't require specialization to reduce +// template bloat. +// CallbackBase is a direct base class of MoveOnly callbacks, and +// CallbackBase uses CallbackBase for its implementation. +class CallbackBase { + public: + CallbackBase(CallbackBase&& c) noexcept; + CallbackBase& operator=(CallbackBase&& c) noexcept; + + explicit CallbackBase(const CallbackBaseCopyable& c); + CallbackBase& operator=(const CallbackBaseCopyable& c); + + explicit CallbackBase(CallbackBaseCopyable&& c) noexcept; + CallbackBase& operator=(CallbackBaseCopyable&& c) noexcept; + + // Returns true if Callback is null (doesn't refer to anything). + bool is_null() const { return !bind_state_; } + explicit operator bool() const { return !is_null(); } + + // Returns true if the callback invocation will be nop due to an cancellation. + // It's invalid to call this on uninitialized callback. + bool IsCancelled() const; + + // Returns the Callback into an uninitialized state. + void Reset(); + + protected: + using InvokeFuncStorage = BindStateBase::InvokeFuncStorage; + + // Returns true if this callback equals |other|. |other| may be null. + bool EqualsInternal(const CallbackBase& other) const; + + constexpr inline CallbackBase(); + + // Allow initializing of |bind_state_| via the constructor to avoid default + // initialization of the scoped_refptr. + explicit CallbackBase(BindStateBase* bind_state); + + InvokeFuncStorage polymorphic_invoke() const { + return bind_state_->polymorphic_invoke_; + } + + // 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 bind_state_; +}; + +constexpr CallbackBase::CallbackBase() = default; + +// CallbackBase is a direct base class of Copyable Callbacks. +class CallbackBaseCopyable : public CallbackBase { + public: + CallbackBaseCopyable(const CallbackBaseCopyable& c); + CallbackBaseCopyable(CallbackBaseCopyable&& c) noexcept; + CallbackBaseCopyable& operator=(const CallbackBaseCopyable& c); + CallbackBaseCopyable& operator=(CallbackBaseCopyable&& c) noexcept; + + protected: + constexpr CallbackBaseCopyable() = default; + explicit CallbackBaseCopyable(BindStateBase* bind_state) + : CallbackBase(bind_state) {} + ~CallbackBaseCopyable() = default; +}; + +} // namespace internal +} // namespace base + +#endif // BASE_CALLBACK_INTERNAL_H_ diff --git a/src/3rdparty/gn/base/command_line.cc b/src/3rdparty/gn/base/command_line.cc new file mode 100644 index 00000000000..792d322fe1e --- /dev/null +++ b/src/3rdparty/gn/base/command_line.cc @@ -0,0 +1,486 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" + +#include +#include + +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/stl_util.h" +#include "base/strings/string_split.h" +#include "base/strings/string_tokenizer.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "util/build_config.h" + +#if defined(OS_WIN) +#include + +#include +#endif + +namespace base { + +CommandLine* CommandLine::current_process_commandline_ = nullptr; + +namespace { + +const CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--"); +const CommandLine::CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("="); + +// Since we use a lazy match, make sure that longer versions (like "--") are +// listed before shorter versions (like "-") of similar prefixes. +#if defined(OS_WIN) +// By putting slash last, we can control whether it is treaded as a switch +// value by changing the value of switch_prefix_count to be one less than +// the array size. +const CommandLine::CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"}; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +// Unixes don't use slash as a switch. +const CommandLine::CharType* const kSwitchPrefixes[] = {"--", "-"}; +#endif +size_t switch_prefix_count = arraysize(kSwitchPrefixes); + +size_t GetSwitchPrefixLength(const CommandLine::StringType& string) { + for (size_t i = 0; i < switch_prefix_count; ++i) { + CommandLine::StringType prefix(kSwitchPrefixes[i]); + if (string.compare(0, prefix.length(), prefix) == 0) + return prefix.length(); + } + return 0; +} + +// Fills in |switch_string| and |switch_value| if |string| is a switch. +// This will preserve the input switch prefix in the output |switch_string|. +bool IsSwitch(const CommandLine::StringType& string, + CommandLine::StringType* switch_string, + CommandLine::StringType* switch_value) { + switch_string->clear(); + switch_value->clear(); + size_t prefix_length = GetSwitchPrefixLength(string); + if (prefix_length == 0 || prefix_length == string.length()) + return false; + + const size_t equals_position = string.find(kSwitchValueSeparator); + *switch_string = string.substr(0, equals_position); + if (equals_position != CommandLine::StringType::npos) + *switch_value = string.substr(equals_position + 1); + return true; +} + +// Append switches and arguments, keeping switches before arguments +// if handle_switches is true. +void AppendSwitchesAndArguments(CommandLine* command_line, + const CommandLine::StringVector& argv, + bool handle_switches) { + bool parse_switches = handle_switches; + for (size_t i = 1; i < argv.size(); ++i) { + CommandLine::StringType arg = argv[i]; +#if defined(OS_WIN) + TrimWhitespace(arg, TRIM_ALL, &arg); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + TrimWhitespaceASCII(arg, TRIM_ALL, &arg); +#endif + + CommandLine::StringType switch_string; + CommandLine::StringType switch_value; + parse_switches &= (arg != kSwitchTerminator); + if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) { +#if defined(OS_WIN) + command_line->AppendSwitchNative(UTF16ToASCII(switch_string), + switch_value); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + command_line->AppendSwitchNative(switch_string, switch_value); +#else +#error Unsupported platform +#endif + } else { + command_line->AppendArgNative(arg); + } + } +} + +#if defined(OS_WIN) +// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*. +string16 QuoteForCommandLineToArgvW(const string16& arg, + bool quote_placeholders) { + // We follow the quoting rules of CommandLineToArgvW. + // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx + string16 quotable_chars(L" \\\""); + // We may also be required to quote '%', which is commonly used in a command + // line as a placeholder. (It may be substituted for a string with spaces.) + if (quote_placeholders) + quotable_chars.push_back(L'%'); + if (arg.find_first_of(quotable_chars) == string16::npos) { + // No quoting necessary. + return arg; + } + + string16 out; + out.push_back(L'"'); + for (size_t i = 0; i < arg.size(); ++i) { + if (arg[i] == '\\') { + // Find the extent of this run of backslashes. + size_t start = i, end = start + 1; + for (; end < arg.size() && arg[end] == '\\'; ++end) { + } + size_t backslash_count = end - start; + + // Backslashes are escapes only if the run is followed by a double quote. + // Since we also will end the string with a double quote, we escape for + // either a double quote or the end of the string. + if (end == arg.size() || arg[end] == '"') { + // To quote, we need to output 2x as many backslashes. + backslash_count *= 2; + } + for (size_t j = 0; j < backslash_count; ++j) + out.push_back('\\'); + + // Advance i to one before the end to balance i++ in loop. + i = end - 1; + } else if (arg[i] == '"') { + out.push_back('\\'); + out.push_back('"'); + } else { + out.push_back(arg[i]); + } + } + out.push_back('"'); + + return out; +} +#endif + +} // namespace + +CommandLine::CommandLine(NoProgram no_program) + : argv_(1), begin_args_(1), parse_switches_(true) {} + +CommandLine::CommandLine(const FilePath& program) + : argv_(1), begin_args_(1), parse_switches_(true) { + SetProgram(program); +} + +CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv) + : argv_(1), begin_args_(1), parse_switches_(true) { + InitFromArgv(argc, argv); +} + +CommandLine::CommandLine(const StringVector& argv) + : argv_(1), begin_args_(1), parse_switches_(true) { + InitFromArgv(argv); +} + +CommandLine::CommandLine(const CommandLine& other) = default; + +CommandLine& CommandLine::operator=(const CommandLine& other) = default; + +CommandLine::~CommandLine() = default; + +#if defined(OS_WIN) +// static +void CommandLine::set_slash_is_not_a_switch() { + // The last switch prefix should be slash, so adjust the size to skip it. + DCHECK_EQ(wcscmp(kSwitchPrefixes[arraysize(kSwitchPrefixes) - 1], L"/"), 0); + switch_prefix_count = arraysize(kSwitchPrefixes) - 1; +} + +// static +void CommandLine::InitUsingArgvForTesting(int argc, const char* const* argv) { + DCHECK(!current_process_commandline_); + current_process_commandline_ = new CommandLine(NO_PROGRAM); + // On Windows we need to convert the command line arguments to string16. + base::CommandLine::StringVector argv_vector; + for (int i = 0; i < argc; ++i) + argv_vector.push_back(UTF8ToUTF16(argv[i])); + current_process_commandline_->InitFromArgv(argv_vector); +} +#endif + +// static +bool CommandLine::Init(int argc, const char* const* argv) { + if (current_process_commandline_) { + // If this is intentional, Reset() must be called first. If we are using + // the shared build mode, we have to share a single object across multiple + // shared libraries. + return false; + } + + current_process_commandline_ = new CommandLine(NO_PROGRAM); +#if defined(OS_WIN) + current_process_commandline_->ParseFromString(::GetCommandLineW()); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + current_process_commandline_->InitFromArgv(argc, argv); +#else +#error Unsupported platform +#endif + + return true; +} + +// static +void CommandLine::Reset() { + DCHECK(current_process_commandline_); + delete current_process_commandline_; + current_process_commandline_ = nullptr; +} + +// static +CommandLine* CommandLine::ForCurrentProcess() { + DCHECK(current_process_commandline_); + return current_process_commandline_; +} + +// static +bool CommandLine::InitializedForCurrentProcess() { + return !!current_process_commandline_; +} + +#if defined(OS_WIN) +// static +CommandLine CommandLine::FromString(const string16& command_line) { + CommandLine cmd(NO_PROGRAM); + cmd.ParseFromString(command_line); + return cmd; +} +#endif + +void CommandLine::InitFromArgv(int argc, + const CommandLine::CharType* const* argv) { + StringVector new_argv; + for (int i = 0; i < argc; ++i) + new_argv.push_back(argv[i]); + InitFromArgv(new_argv); +} + +void CommandLine::InitFromArgv(const StringVector& argv) { + argv_ = StringVector(1); + switches_.clear(); + begin_args_ = 1; + SetProgram(argv.empty() ? FilePath() : FilePath(argv[0])); + AppendSwitchesAndArguments(this, argv, parse_switches_); +} + +FilePath CommandLine::GetProgram() const { + return FilePath(argv_[0]); +} + +void CommandLine::SetProgram(const FilePath& program) { +#if defined(OS_WIN) + TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + TrimWhitespaceASCII(program.value(), TRIM_ALL, &argv_[0]); +#else +#error Unsupported platform +#endif +} + +bool CommandLine::HasSwitch(const base::StringPiece& switch_string) const { + DCHECK_EQ(ToLowerASCII(switch_string), switch_string); + return ContainsKey(switches_, switch_string); +} + +bool CommandLine::HasSwitch(const char switch_constant[]) const { + return HasSwitch(base::StringPiece(switch_constant)); +} + +std::string CommandLine::GetSwitchValueASCII( + const base::StringPiece& switch_string) const { + StringType value = GetSwitchValueNative(switch_string); + if (!IsStringASCII(value)) { + DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII."; + return std::string(); + } +#if defined(OS_WIN) + return UTF16ToASCII(value); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + return value; +#endif +} + +FilePath CommandLine::GetSwitchValuePath( + const base::StringPiece& switch_string) const { + return FilePath(GetSwitchValueNative(switch_string)); +} + +CommandLine::StringType CommandLine::GetSwitchValueNative( + const base::StringPiece& switch_string) const { + DCHECK_EQ(ToLowerASCII(switch_string), switch_string); + auto result = switches_.find(switch_string); + return result == switches_.end() ? StringType() : result->second; +} + +void CommandLine::AppendSwitch(const std::string& switch_string) { + AppendSwitchNative(switch_string, StringType()); +} + +void CommandLine::AppendSwitchPath(const std::string& switch_string, + const FilePath& path) { + AppendSwitchNative(switch_string, path.value()); +} + +void CommandLine::AppendSwitchNative(const std::string& switch_string, + const CommandLine::StringType& value) { +#if defined(OS_WIN) + const std::string switch_key = ToLowerASCII(switch_string); + StringType combined_switch_string(ASCIIToUTF16(switch_key)); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + const std::string& switch_key = switch_string; + StringType combined_switch_string(switch_key); +#endif + size_t prefix_length = GetSwitchPrefixLength(combined_switch_string); + auto insertion = + switches_.insert(make_pair(switch_key.substr(prefix_length), value)); + if (!insertion.second) + insertion.first->second = value; + // Preserve existing switch prefixes in |argv_|; only append one if necessary. + if (prefix_length == 0) + combined_switch_string = kSwitchPrefixes[0] + combined_switch_string; + if (!value.empty()) + combined_switch_string += kSwitchValueSeparator + value; + // Append the switch and update the switches/arguments divider |begin_args_|. + argv_.insert(argv_.begin() + begin_args_++, combined_switch_string); +} + +void CommandLine::AppendSwitchASCII(const std::string& switch_string, + const std::string& value_string) { +#if defined(OS_WIN) + AppendSwitchNative(switch_string, ASCIIToUTF16(value_string)); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + AppendSwitchNative(switch_string, value_string); +#else +#error Unsupported platform +#endif +} + +void CommandLine::CopySwitchesFrom(const CommandLine& source, + const char* const switches[], + size_t count) { + for (size_t i = 0; i < count; ++i) { + if (source.HasSwitch(switches[i])) + AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i])); + } +} + +CommandLine::StringVector CommandLine::GetArgs() const { + // Gather all arguments after the last switch (may include kSwitchTerminator). + StringVector args(argv_.begin() + begin_args_, argv_.end()); + // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?) + StringVector::iterator switch_terminator = + std::find(args.begin(), args.end(), kSwitchTerminator); + if (switch_terminator != args.end()) + args.erase(switch_terminator); + return args; +} + +void CommandLine::AppendArg(const std::string& value) { +#if defined(OS_WIN) + DCHECK(IsStringUTF8(value)); + AppendArgNative(UTF8ToWide(value)); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + AppendArgNative(value); +#else +#error Unsupported platform +#endif +} + +void CommandLine::AppendArgPath(const FilePath& path) { + AppendArgNative(path.value()); +} + +void CommandLine::AppendArgNative(const CommandLine::StringType& value) { + argv_.push_back(value); +} + +void CommandLine::AppendArguments(const CommandLine& other, + bool include_program) { + if (include_program) + SetProgram(other.GetProgram()); + AppendSwitchesAndArguments(this, other.argv(), parse_switches_); +} + +void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) { + if (wrapper.empty()) + return; + // Split the wrapper command based on whitespace (with quoting). + using CommandLineTokenizer = + StringTokenizerT; + CommandLineTokenizer tokenizer(wrapper, FILE_PATH_LITERAL(" ")); + tokenizer.set_quote_chars(FILE_PATH_LITERAL("'\"")); + std::vector wrapper_argv; + while (tokenizer.GetNext()) + wrapper_argv.emplace_back(tokenizer.token()); + + // Prepend the wrapper and update the switches/arguments |begin_args_|. + argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end()); + begin_args_ += wrapper_argv.size(); +} + +#if defined(OS_WIN) +void CommandLine::ParseFromString(const string16& command_line) { + string16 command_line_string; + TrimWhitespace(command_line, TRIM_ALL, &command_line_string); + if (command_line_string.empty()) + return; + + int num_args = 0; + wchar_t** args = NULL; + args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args); + + DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: " + << UTF16ToUTF8(command_line); + InitFromArgv(num_args, args); + LocalFree(args); +} +#endif + +CommandLine::StringType CommandLine::GetCommandLineStringInternal( + bool quote_placeholders) const { + StringType string(argv_[0]); +#if defined(OS_WIN) + string = QuoteForCommandLineToArgvW(string, quote_placeholders); +#endif + StringType params(GetArgumentsStringInternal(quote_placeholders)); + if (!params.empty()) { + string.append(StringType(FILE_PATH_LITERAL(" "))); + string.append(params); + } + return string; +} + +CommandLine::StringType CommandLine::GetArgumentsStringInternal( + bool quote_placeholders) const { + StringType params; + // Append switches and arguments. + bool parse_switches = parse_switches_; + for (size_t i = 1; i < argv_.size(); ++i) { + StringType arg = argv_[i]; + StringType switch_string; + StringType switch_value; + parse_switches &= arg != kSwitchTerminator; + if (i > 1) + params.append(StringType(FILE_PATH_LITERAL(" "))); + if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) { + params.append(switch_string); + if (!switch_value.empty()) { +#if defined(OS_WIN) + switch_value = + QuoteForCommandLineToArgvW(switch_value, quote_placeholders); +#endif + params.append(kSwitchValueSeparator + switch_value); + } + } else { +#if defined(OS_WIN) + arg = QuoteForCommandLineToArgvW(arg, quote_placeholders); +#endif + params.append(arg); + } + } + return params; +} + +} // namespace base diff --git a/src/3rdparty/gn/base/command_line.h b/src/3rdparty/gn/base/command_line.h new file mode 100644 index 00000000000..01614576832 --- /dev/null +++ b/src/3rdparty/gn/base/command_line.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. + +// 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 +#include +#include +#include + +#include "base/strings/string16.h" +#include "base/strings/string_piece.h" +#include "util/build_config.h" + +namespace base { + +class FilePath; + +class CommandLine { + public: +#if defined(OS_WIN) + // The native command line string type. + using StringType = string16; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + using StringType = std::string; +#endif + + using CharType = StringType::value_type; + using StringVector = std::vector; + using SwitchMap = std::map>; + + // A constructor for CommandLines that only carry switches and arguments. + enum NoProgram { NO_PROGRAM }; + explicit CommandLine(NoProgram no_program); + + // Construct a new command line with |program| as argv[0]. + explicit CommandLine(const FilePath& program); + + // Construct a new command line from an argument list. + CommandLine(int argc, const CharType* const* argv); + explicit CommandLine(const StringVector& argv); + + // Override copy and assign to ensure |switches_by_stringpiece_| is valid. + CommandLine(const CommandLine& other); + CommandLine& operator=(const CommandLine& other); + + ~CommandLine(); + +#if defined(OS_WIN) + // By default this class will treat command-line arguments beginning with + // slashes as switches on Windows, but not other platforms. + // + // If this behavior is inappropriate for your application, you can call this + // function BEFORE initializing the current process' global command line + // object and the behavior will be the same as Posix systems (only hyphens + // begin switches, everything else will be an arg). + static void set_slash_is_not_a_switch(); + + // Normally when the CommandLine singleton is initialized it gets the command + // line via the GetCommandLineW API and then uses the shell32 API + // CommandLineToArgvW to parse the command line and convert it back to + // argc and argv. Tests who don't want this dependency on shell32 and need + // to honor the arguments passed in should use this function. + static void InitUsingArgvForTesting(int argc, const char* const* argv); +#endif + + // Initialize the current process CommandLine singleton. On Windows, ignores + // its arguments (we instead parse GetCommandLineW() directly) because we + // don't trust the CRT's parsing of the command line, but it still must be + // called to set up the command line. Returns false if initialization has + // already occurred, and true otherwise. Only the caller receiving a 'true' + // return value should take responsibility for calling Reset. + static bool Init(int argc, const char* const* argv); + + // Destroys the current process CommandLine singleton. This is necessary if + // you want to reset the base library to its initial state (for example, in an + // outer library that needs to be able to terminate, and be re-initialized). + // If Init is called only once, as in main(), Reset() is not necessary. + // Do not call this in tests. Use base::test::ScopedCommandLine instead. + static void Reset(); + + // Get the singleton CommandLine representing the current process's + // command line. Note: returned value is mutable, but not thread safe; + // only mutate if you know what you're doing! + static CommandLine* ForCurrentProcess(); + + // Returns true if the CommandLine has been initialized for the given process. + static bool InitializedForCurrentProcess(); + +#if defined(OS_WIN) + static CommandLine FromString(const string16& command_line); +#endif + + // Initialize from an argv vector. + void InitFromArgv(int argc, const CharType* const* argv); + void InitFromArgv(const StringVector& argv); + + // Constructs and returns the represented command line string. + // CAUTION! This should be avoided on POSIX because quoting behavior is + // unclear. + StringType GetCommandLineString() const { + return GetCommandLineStringInternal(false); + } + +#if defined(OS_WIN) + // Constructs and returns the represented command line string. Assumes the + // command line contains placeholders (eg, %1) and quotes any program or + // argument with a '%' in it. This should be avoided unless the placeholder is + // required by an external interface (eg, the Windows registry), because it is + // not generally safe to replace it with an arbitrary string. If possible, + // placeholders should be replaced *before* converting the command line to a + // string. + StringType GetCommandLineStringWithPlaceholders() const { + return GetCommandLineStringInternal(true); + } +#endif + + // Constructs and returns the represented arguments string. + // CAUTION! This should be avoided on POSIX because quoting behavior is + // unclear. + StringType GetArgumentsString() const { + return GetArgumentsStringInternal(false); + } + +#if defined(OS_WIN) + // Constructs and returns the represented arguments string. Assumes the + // command line contains placeholders (eg, %1) and quotes any argument with a + // '%' in it. This should be avoided unless the placeholder is required by an + // external interface (eg, the Windows registry), because it is not generally + // safe to replace it with an arbitrary string. If possible, placeholders + // should be replaced *before* converting the arguments to a string. + StringType GetArgumentsStringWithPlaceholders() const { + return GetArgumentsStringInternal(true); + } +#endif + + // Returns the original command line string as a vector of strings. + const StringVector& argv() const { return argv_; } + + // Get and Set the program part of the command line string (the first item). + FilePath GetProgram() const; + void SetProgram(const FilePath& program); + + // Enables/disables the parsing of switches for future argument appending. + // True by default, but can be set to false to ensure that no re-ordering + // is done. + void SetParseSwitches(bool parse_switches) { + parse_switches_ = parse_switches; + } + + // Returns true if this command line contains the given switch. + // Switch names must be lowercase. + // The second override provides an optimized version to avoid inlining codegen + // at every callsite to find the length of the constant and construct a + // StringPiece. + bool HasSwitch(const StringPiece& switch_string) const; + bool HasSwitch(const char switch_constant[]) const; + + // Returns the value associated with the given switch. If the switch has no + // value or isn't present, this method returns the empty string. + // Switch names must be lowercase. + std::string GetSwitchValueASCII(const StringPiece& switch_string) const; + FilePath GetSwitchValuePath(const StringPiece& switch_string) const; + StringType GetSwitchValueNative(const StringPiece& switch_string) const; + + // Get a copy of all switches, along with their values. + const SwitchMap& GetSwitches() const { return switches_; } + + // Append a switch [with optional value] to the command line. + // Note: Switches will precede arguments regardless of appending order. + void AppendSwitch(const std::string& switch_string); + void AppendSwitchPath(const std::string& switch_string, const FilePath& path); + void AppendSwitchNative(const std::string& switch_string, + const StringType& value); + void AppendSwitchASCII(const std::string& switch_string, + const std::string& value); + + // Copy a set of switches (and any values) from another command line. + // Commonly used when launching a subprocess. + void CopySwitchesFrom(const CommandLine& source, + const char* const switches[], + size_t count); + + // Get the remaining arguments to the command. + StringVector GetArgs() const; + + // Append an argument to the command line. Note that the argument is quoted + // properly such that it is interpreted as one argument to the target command. + // AppendArg is primarily for ASCII; non-ASCII input is interpreted as UTF-8. + // Note: Switches will precede arguments regardless of appending order. + void AppendArg(const std::string& value); + void AppendArgPath(const FilePath& value); + void AppendArgNative(const StringType& value); + + // Append the switches and arguments from another command line to this one. + // If |include_program| is true, include |other|'s program as well. + void AppendArguments(const CommandLine& other, bool include_program); + + // Insert a command before the current command. + // Common for debuggers, like "gdb --args". + void PrependWrapper(const StringType& wrapper); + +#if defined(OS_WIN) + // Initialize by parsing the given command line string. + // The program name is assumed to be the first item in the string. + void ParseFromString(const string16& command_line); +#endif + + private: + // Disallow default constructor; a program name must be explicitly specified. + CommandLine() = delete; + // Allow the copy constructor. A common pattern is to copy of the current + // process's command line and then add some flags to it. For example: + // CommandLine cl(*CommandLine::ForCurrentProcess()); + // cl.AppendSwitch(...); + + // Internal version of GetCommandLineString. If |quote_placeholders| is true, + // also quotes parts with '%' in them. + StringType GetCommandLineStringInternal(bool quote_placeholders) const; + + // Internal version of GetArgumentsString. If |quote_placeholders| is true, + // also quotes parts with '%' in them. + StringType GetArgumentsStringInternal(bool quote_placeholders) const; + + // The singleton CommandLine representing the current process's command line. + static CommandLine* current_process_commandline_; + + // The argv array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* } + StringVector argv_; + + // Parsed-out switch keys and values. + SwitchMap switches_; + + // The index after the program and switches, any arguments start here. + size_t begin_args_; + + // Whether or not to parse arguments that look like switches as switches. + bool parse_switches_; +}; + +} // namespace base + +#endif // BASE_COMMAND_LINE_H_ diff --git a/src/3rdparty/gn/base/compiler_specific.h b/src/3rdparty/gn/base/compiler_specific.h new file mode 100644 index 00000000000..42241976483 --- /dev/null +++ b/src/3rdparty/gn/base/compiler_specific.h @@ -0,0 +1,231 @@ +// 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 "util/build_config.h" + +#if defined(COMPILER_MSVC) + +// For _Printf_format_string_. +#include + +// 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)) + +#else // Not MSVC + +#define _Printf_format_string_ +#define MSVC_SUPPRESS_WARNING(n) +#define MSVC_PUSH_DISABLE_WARNING(n) +#define MSVC_PUSH_WARNING_LEVEL(n) +#define MSVC_POP_WARNING() +#define MSVC_DISABLE_OPTIMIZE() +#define MSVC_ENABLE_OPTIMIZE() + +#endif // COMPILER_MSVC + +// Annotate a variable indicating it's ok if the variable is not used. +// (Typically used to silence a compiler warning when the assignment +// is important for some other reason.) +// Use like: +// int x = ...; +// ALLOW_UNUSED_LOCAL(x); +#define ALLOW_UNUSED_LOCAL(x) (void)x + +// Annotate a typedef or function indicating it's ok if it's not used. +// Use like: +// typedef Foo Bar ALLOW_UNUSED_TYPE; +#if defined(COMPILER_GCC) || defined(__clang__) +#define ALLOW_UNUSED_TYPE __attribute__((unused)) +#else +#define ALLOW_UNUSED_TYPE +#endif + +// Annotate a function indicating it should not be inlined. +// Use like: +// NOINLINE void DoStuff() { ... } +#if defined(COMPILER_GCC) +#define NOINLINE __attribute__((noinline)) +#elif defined(COMPILER_MSVC) +#define NOINLINE __declspec(noinline) +#else +#define NOINLINE +#endif + +#if COMPILER_GCC && defined(NDEBUG) +#define ALWAYS_INLINE inline __attribute__((__always_inline__)) +#elif COMPILER_MSVC && defined(NDEBUG) +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE inline +#endif + +// Specify memory alignment for structs, classes, etc. +// Use like: +// class ALIGNAS(16) MyClass { ... } +// ALIGNAS(16) int array[4]; +// +// In most places you can use the C++11 keyword "alignas", which is preferred. +// +// But compilers have trouble mixing __attribute__((...)) syntax with +// alignas(...) syntax. +// +// Doesn't work in clang or gcc: +// struct alignas(16) __attribute__((packed)) S { char c; }; +// Works in clang but not gcc: +// struct __attribute__((packed)) alignas(16) S2 { char c; }; +// Works in clang and gcc: +// struct alignas(16) S3 { char c; } __attribute__((packed)); +// +// There are also some attributes that must be specified *before* a class +// definition: visibility (used for exporting functions/classes) is one of +// these attributes. This means that it is not possible to use alignas() with a +// class that is marked as exported. +#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 + +// Annotate a function indicating the caller must examine the return value. +// Use like: +// int foo() WARN_UNUSED_RESULT; +// To explicitly ignore a result, see |ignore_result()| in base/macros.h. +#undef WARN_UNUSED_RESULT +#if defined(COMPILER_GCC) || defined(__clang__) +#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define WARN_UNUSED_RESULT +#endif + +// Tell the compiler a function is using a printf-style format string. +// |format_param| is the one-based index of the format string parameter; +// |dots_param| is the one-based index of the "..." parameter. +// For v*printf functions (which take a va_list), pass 0 for dots_param. +// (This is undocumented but matches what the system C headers do.) +#if defined(COMPILER_GCC) || defined(__clang__) +#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))) + +// Sanitizers annotations. +#if defined(__has_attribute) +#if __has_attribute(no_sanitize) +#define NO_SANITIZE(what) __attribute__((no_sanitize(what))) +#endif +#endif +#if !defined(NO_SANITIZE) +#define NO_SANITIZE(what) +#endif + +// MemorySanitizer annotations. +#if defined(MEMORY_SANITIZER) && !defined(OS_NACL) +#include + +// 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 + +// DISABLE_CFI_PERF -- Disable Control Flow Integrity for perf reasons. +#if !defined(DISABLE_CFI_PERF) +#if defined(__clang__) && defined(OFFICIAL_BUILD) +#define DISABLE_CFI_PERF __attribute__((no_sanitize("cfi"))) +#else +#define DISABLE_CFI_PERF +#endif +#endif + +// 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) || defined(__clang__) +#define UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define UNLIKELY(x) (x) +#endif // defined(COMPILER_GCC) +#endif // !defined(UNLIKELY) + +#if !defined(LIKELY) +#if defined(COMPILER_GCC) || defined(__clang__) +#define LIKELY(x) __builtin_expect(!!(x), 1) +#else +#define LIKELY(x) (x) +#endif // defined(COMPILER_GCC) +#endif // !defined(LIKELY) + +// Compiler feature-detection. +// clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension +#if defined(__has_feature) +#define HAS_FEATURE(FEATURE) __has_feature(FEATURE) +#else +#define HAS_FEATURE(FEATURE) 0 +#endif + +// Macro for telling -Wimplicit-fallthrough that a fallthrough is intentional. +#if defined(__clang__) +#define FALLTHROUGH [[clang::fallthrough]] +#else +#define FALLTHROUGH +#endif + +#endif // BASE_COMPILER_SPECIFIC_H_ diff --git a/src/3rdparty/gn/base/containers/circular_deque.h b/src/3rdparty/gn/base/containers/circular_deque.h new file mode 100644 index 00000000000..bf42a958448 --- /dev/null +++ b/src/3rdparty/gn/base/containers/circular_deque.h @@ -0,0 +1,1111 @@ +// Copyright 2017 The Chromium 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_CONTAINERS_CIRCULAR_DEQUE_H_ +#define BASE_CONTAINERS_CIRCULAR_DEQUE_H_ + +#include +#include +#include +#include +#include + +#include "base/containers/vector_buffer.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/template_util.h" + +// base::circular_deque is similar to std::deque. Unlike std::deque, the +// storage is provided in a flat circular buffer conceptually similar to a +// vector. The beginning and end will wrap around as necessary so that +// pushes and pops will be constant time as long as a capacity expansion is +// not required. +// +// The API should be identical to std::deque with the following differences: +// +// - ITERATORS ARE NOT STABLE. Mutating the container will invalidate all +// iterators. +// +// - Insertions may resize the vector and so are not constant time (std::deque +// guarantees constant time for insertions at the ends). +// +// - Container-wide comparisons are not implemented. If you want to compare +// two containers, use an algorithm so the expensive iteration is explicit. +// +// If you want a similar container with only a queue API, use base::queue in +// base/containers/queue.h. +// +// Constructors: +// circular_deque(); +// circular_deque(size_t count); +// circular_deque(size_t count, const T& value); +// circular_deque(InputIterator first, InputIterator last); +// circular_deque(const circular_deque&); +// circular_deque(circular_deque&&); +// circular_deque(std::initializer_list); +// +// Assignment functions: +// circular_deque& operator=(const circular_deque&); +// circular_deque& operator=(circular_deque&&); +// circular_deque& operator=(std::initializer_list); +// void assign(size_t count, const T& value); +// void assign(InputIterator first, InputIterator last); +// void assign(std::initializer_list value); +// +// Random accessors: +// T& at(size_t); +// const T& at(size_t) const; +// T& operator[](size_t); +// const T& operator[](size_t) const; +// +// End accessors: +// T& front(); +// const T& front() const; +// T& back(); +// const T& back() const; +// +// Iterator functions: +// iterator begin(); +// const_iterator begin() const; +// const_iterator cbegin() const; +// iterator end(); +// const_iterator end() const; +// const_iterator cend() const; +// reverse_iterator rbegin(); +// const_reverse_iterator rbegin() const; +// const_reverse_iterator crbegin() const; +// reverse_iterator rend(); +// const_reverse_iterator rend() const; +// const_reverse_iterator crend() const; +// +// Memory management: +// void reserve(size_t); // SEE IMPLEMENTATION FOR SOME GOTCHAS. +// size_t capacity() const; +// void shrink_to_fit(); +// +// Size management: +// void clear(); +// bool empty() const; +// size_t size() const; +// void resize(size_t); +// void resize(size_t count, const T& value); +// +// Positional insert and erase: +// void insert(const_iterator pos, size_type count, const T& value); +// void insert(const_iterator pos, +// InputIterator first, InputIterator last); +// iterator insert(const_iterator pos, const T& value); +// iterator insert(const_iterator pos, T&& value); +// iterator emplace(const_iterator pos, Args&&... args); +// iterator erase(const_iterator pos); +// iterator erase(const_iterator first, const_iterator last); +// +// End insert and erase: +// void push_front(const T&); +// void push_front(T&&); +// void push_back(const T&); +// void push_back(T&&); +// T& emplace_front(Args&&...); +// T& emplace_back(Args&&...); +// void pop_front(); +// void pop_back(); +// +// General: +// void swap(circular_deque&); + +namespace base { + +template +class circular_deque; + +namespace internal { + +// Start allocating nonempty buffers with this many entries. This is the +// external capacity so the internal buffer will be one larger (= 4) which is +// more even for the allocator. See the descriptions of internal vs. external +// capacity on the comment above the buffer_ variable below. +constexpr size_t kCircularBufferInitialCapacity = 3; + +template +class circular_deque_const_iterator { + public: + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; + using iterator_category = std::random_access_iterator_tag; + + circular_deque_const_iterator() : parent_deque_(nullptr), index_(0) { +#if DCHECK_IS_ON() + created_generation_ = 0; +#endif // DCHECK_IS_ON() + } + + // Dereferencing. + const T& operator*() const { + CheckUnstableUsage(); + parent_deque_->CheckValidIndex(index_); + return parent_deque_->buffer_[index_]; + } + const T* operator->() const { + CheckUnstableUsage(); + parent_deque_->CheckValidIndex(index_); + return &parent_deque_->buffer_[index_]; + } + const value_type& operator[](difference_type i) const { return *(*this + i); } + + // Increment and decrement. + circular_deque_const_iterator& operator++() { + Increment(); + return *this; + } + circular_deque_const_iterator operator++(int) { + circular_deque_const_iterator ret = *this; + Increment(); + return ret; + } + circular_deque_const_iterator& operator--() { + Decrement(); + return *this; + } + circular_deque_const_iterator operator--(int) { + circular_deque_const_iterator ret = *this; + Decrement(); + return ret; + } + + // Random access mutation. + friend circular_deque_const_iterator operator+( + const circular_deque_const_iterator& iter, + difference_type offset) { + circular_deque_const_iterator ret = iter; + ret.Add(offset); + return ret; + } + circular_deque_const_iterator& operator+=(difference_type offset) { + Add(offset); + return *this; + } + friend circular_deque_const_iterator operator-( + const circular_deque_const_iterator& iter, + difference_type offset) { + circular_deque_const_iterator ret = iter; + ret.Add(-offset); + return ret; + } + circular_deque_const_iterator& operator-=(difference_type offset) { + Add(-offset); + return *this; + } + + friend std::ptrdiff_t operator-(const circular_deque_const_iterator& lhs, + const circular_deque_const_iterator& rhs) { + lhs.CheckComparable(rhs); + return lhs.OffsetFromBegin() - rhs.OffsetFromBegin(); + } + + // Comparisons. + friend bool operator==(const circular_deque_const_iterator& lhs, + const circular_deque_const_iterator& rhs) { + lhs.CheckComparable(rhs); + return lhs.index_ == rhs.index_; + } + friend bool operator!=(const circular_deque_const_iterator& lhs, + const circular_deque_const_iterator& rhs) { + return !(lhs == rhs); + } + friend bool operator<(const circular_deque_const_iterator& lhs, + const circular_deque_const_iterator& rhs) { + lhs.CheckComparable(rhs); + return lhs.OffsetFromBegin() < rhs.OffsetFromBegin(); + } + friend bool operator<=(const circular_deque_const_iterator& lhs, + const circular_deque_const_iterator& rhs) { + return !(lhs > rhs); + } + friend bool operator>(const circular_deque_const_iterator& lhs, + const circular_deque_const_iterator& rhs) { + lhs.CheckComparable(rhs); + return lhs.OffsetFromBegin() > rhs.OffsetFromBegin(); + } + friend bool operator>=(const circular_deque_const_iterator& lhs, + const circular_deque_const_iterator& rhs) { + return !(lhs < rhs); + } + + protected: + friend class circular_deque; + + circular_deque_const_iterator(const circular_deque* parent, size_t index) + : parent_deque_(parent), index_(index) { +#if DCHECK_IS_ON() + created_generation_ = parent->generation_; +#endif // DCHECK_IS_ON() + } + + // Returns the offset from the beginning index of the buffer to the current + // item. + size_t OffsetFromBegin() const { + if (index_ >= parent_deque_->begin_) + return index_ - parent_deque_->begin_; // On the same side as begin. + return parent_deque_->buffer_.capacity() - parent_deque_->begin_ + index_; + } + + // Most uses will be ++ and -- so use a simplified implementation. + void Increment() { + CheckUnstableUsage(); + parent_deque_->CheckValidIndex(index_); + index_++; + if (index_ == parent_deque_->buffer_.capacity()) + index_ = 0; + } + void Decrement() { + CheckUnstableUsage(); + parent_deque_->CheckValidIndexOrEnd(index_); + if (index_ == 0) + index_ = parent_deque_->buffer_.capacity() - 1; + else + index_--; + } + void Add(difference_type delta) { + CheckUnstableUsage(); +#if DCHECK_IS_ON() + if (delta <= 0) + parent_deque_->CheckValidIndexOrEnd(index_); + else + parent_deque_->CheckValidIndex(index_); +#endif + // It should be valid to add 0 to any iterator, even if the container is + // empty and the iterator points to end(). The modulo below will divide + // by 0 if the buffer capacity is empty, so it's important to check for + // this case explicitly. + if (delta == 0) + return; + + difference_type new_offset = OffsetFromBegin() + delta; + DCHECK(new_offset >= 0 && + new_offset <= static_cast(parent_deque_->size())); + index_ = (new_offset + parent_deque_->begin_) % + parent_deque_->buffer_.capacity(); + } + +#if DCHECK_IS_ON() + void CheckUnstableUsage() const { + DCHECK(parent_deque_); + // Since circular_deque doesn't guarantee stability, any attempt to + // dereference this iterator after a mutation (i.e. the generation doesn't + // match the original) in the container is illegal. + DCHECK_EQ(created_generation_, parent_deque_->generation_) + << "circular_deque iterator dereferenced after mutation."; + } + void CheckComparable(const circular_deque_const_iterator& other) const { + DCHECK_EQ(parent_deque_, other.parent_deque_); + // Since circular_deque doesn't guarantee stability, two iterators that + // are compared must have been generated without mutating the container. + // If this fires, the container was mutated between generating the two + // iterators being compared. + DCHECK_EQ(created_generation_, other.created_generation_); + } +#else + inline void CheckUnstableUsage() const {} + inline void CheckComparable(const circular_deque_const_iterator&) const {} +#endif // DCHECK_IS_ON() + + const circular_deque* parent_deque_; + size_t index_; + +#if DCHECK_IS_ON() + // The generation of the parent deque when this iterator was created. The + // container will update the generation for every modification so we can + // test if the container was modified by comparing them. + uint64_t created_generation_; +#endif // DCHECK_IS_ON() +}; + +template +class circular_deque_iterator : public circular_deque_const_iterator { + using base = circular_deque_const_iterator; + + public: + friend class circular_deque; + + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = T*; + using reference = T&; + using iterator_category = std::random_access_iterator_tag; + + // Expose the base class' constructor. + circular_deque_iterator() : circular_deque_const_iterator() {} + + // Dereferencing. + T& operator*() const { return const_cast(base::operator*()); } + T* operator->() const { return const_cast(base::operator->()); } + T& operator[](difference_type i) { + return const_cast(base::operator[](i)); + } + + // Random access mutation. + friend circular_deque_iterator operator+(const circular_deque_iterator& iter, + difference_type offset) { + circular_deque_iterator ret = iter; + ret.Add(offset); + return ret; + } + circular_deque_iterator& operator+=(difference_type offset) { + base::Add(offset); + return *this; + } + friend circular_deque_iterator operator-(const circular_deque_iterator& iter, + difference_type offset) { + circular_deque_iterator ret = iter; + ret.Add(-offset); + return ret; + } + circular_deque_iterator& operator-=(difference_type offset) { + base::Add(-offset); + return *this; + } + + // Increment and decrement. + circular_deque_iterator& operator++() { + base::Increment(); + return *this; + } + circular_deque_iterator operator++(int) { + circular_deque_iterator ret = *this; + base::Increment(); + return ret; + } + circular_deque_iterator& operator--() { + base::Decrement(); + return *this; + } + circular_deque_iterator operator--(int) { + circular_deque_iterator ret = *this; + base::Decrement(); + return ret; + } + + private: + circular_deque_iterator(const circular_deque* parent, size_t index) + : circular_deque_const_iterator(parent, index) {} +}; + +} // namespace internal + +template +class circular_deque { + private: + using VectorBuffer = internal::VectorBuffer; + + public: + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; + + using iterator = internal::circular_deque_iterator; + using const_iterator = internal::circular_deque_const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + // --------------------------------------------------------------------------- + // Constructor + + constexpr circular_deque() = default; + + // Constructs with |count| copies of |value| or default constructed version. + circular_deque(size_type count) { resize(count); } + circular_deque(size_type count, const T& value) { resize(count, value); } + + // Range constructor. + template + circular_deque(InputIterator first, InputIterator last) { + assign(first, last); + } + + // Copy/move. + circular_deque(const circular_deque& other) : buffer_(other.size() + 1) { + assign(other.begin(), other.end()); + } + circular_deque(circular_deque&& other) noexcept + : buffer_(std::move(other.buffer_)), + begin_(other.begin_), + end_(other.end_) { + other.begin_ = 0; + other.end_ = 0; + } + + circular_deque(std::initializer_list init) { assign(init); } + + ~circular_deque() { DestructRange(begin_, end_); } + + // --------------------------------------------------------------------------- + // Assignments. + // + // All of these may invalidate iterators and references. + + circular_deque& operator=(const circular_deque& other) { + if (&other == this) + return *this; + + reserve(other.size()); + assign(other.begin(), other.end()); + return *this; + } + circular_deque& operator=(circular_deque&& other) noexcept { + if (&other == this) + return *this; + + // We're about to overwrite the buffer, so don't free it in clear to + // avoid doing it twice. + ClearRetainCapacity(); + buffer_ = std::move(other.buffer_); + begin_ = other.begin_; + end_ = other.end_; + + other.begin_ = 0; + other.end_ = 0; + + IncrementGeneration(); + return *this; + } + circular_deque& operator=(std::initializer_list ilist) { + reserve(ilist.size()); + assign(std::begin(ilist), std::end(ilist)); + return *this; + } + + void assign(size_type count, const value_type& value) { + ClearRetainCapacity(); + reserve(count); + for (size_t i = 0; i < count; i++) + emplace_back(value); + IncrementGeneration(); + } + + // This variant should be enabled only when InputIterator is an iterator. + template + typename std::enable_if<::base::internal::is_iterator::value, + void>::type + assign(InputIterator first, InputIterator last) { + // Possible future enhancement, dispatch on iterator tag type. For forward + // iterators we can use std::difference to preallocate the space required + // and only do one copy. + ClearRetainCapacity(); + for (; first != last; ++first) + emplace_back(*first); + IncrementGeneration(); + } + + void assign(std::initializer_list value) { + reserve(std::distance(value.begin(), value.end())); + assign(value.begin(), value.end()); + } + + // --------------------------------------------------------------------------- + // Accessors. + // + // Since this class assumes no exceptions, at() and operator[] are equivalent. + + const value_type& at(size_type i) const { + DCHECK(i < size()); + size_t right_size = buffer_.capacity() - begin_; + if (begin_ <= end_ || i < right_size) + return buffer_[begin_ + i]; + return buffer_[i - right_size]; + } + value_type& at(size_type i) { + return const_cast( + const_cast(this)->at(i)); + } + + value_type& operator[](size_type i) { return at(i); } + const value_type& operator[](size_type i) const { + return const_cast(this)->at(i); + } + + value_type& front() { + DCHECK(!empty()); + return buffer_[begin_]; + } + const value_type& front() const { + DCHECK(!empty()); + return buffer_[begin_]; + } + + value_type& back() { + DCHECK(!empty()); + return *(--end()); + } + const value_type& back() const { + DCHECK(!empty()); + return *(--end()); + } + + // --------------------------------------------------------------------------- + // Iterators. + + iterator begin() { return iterator(this, begin_); } + const_iterator begin() const { return const_iterator(this, begin_); } + const_iterator cbegin() const { return const_iterator(this, begin_); } + + iterator end() { return iterator(this, end_); } + const_iterator end() const { return const_iterator(this, end_); } + const_iterator cend() const { return const_iterator(this, end_); } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const { return rbegin(); } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const { return rend(); } + + // --------------------------------------------------------------------------- + // Memory management. + + // IMPORTANT NOTE ON reserve(...): This class implements auto-shrinking of + // the buffer when elements are deleted and there is "too much" wasted space. + // So if you call reserve() with a large size in anticipation of pushing many + // elements, but pop an element before the queue is full, the capacity you + // reserved may be lost. + // + // As a result, it's only worthwhile to call reserve() when you're adding + // many things at once with no intermediate operations. + void reserve(size_type new_capacity) { + if (new_capacity > capacity()) + SetCapacityTo(new_capacity); + } + + size_type capacity() const { + // One item is wasted to indicate end(). + return buffer_.capacity() == 0 ? 0 : buffer_.capacity() - 1; + } + + void shrink_to_fit() { + if (empty()) { + // Optimize empty case to really delete everything if there was + // something. + if (buffer_.capacity()) + buffer_ = VectorBuffer(); + } else { + SetCapacityTo(size()); + } + } + + // --------------------------------------------------------------------------- + // Size management. + + // This will additionally reset the capacity() to 0. + void clear() { + // This can't resize(0) because that requires a default constructor to + // compile, which not all contained classes may implement. + ClearRetainCapacity(); + buffer_ = VectorBuffer(); + } + + bool empty() const { return begin_ == end_; } + + size_type size() const { + if (begin_ <= end_) + return end_ - begin_; + return buffer_.capacity() - begin_ + end_; + } + + // When reducing size, the elements are deleted from the end. When expanding + // size, elements are added to the end with |value| or the default + // constructed version. Even when using resize(count) to shrink, a default + // constructor is required for the code to compile, even though it will not + // be called. + // + // There are two versions rather than using a default value to avoid + // creating a temporary when shrinking (when it's not needed). Plus if + // the default constructor is desired when expanding usually just calling it + // for each element is faster than making a default-constructed temporary and + // copying it. + void resize(size_type count) { + // SEE BELOW VERSION if you change this. The code is mostly the same. + if (count > size()) { + // This could be slighly more efficient but expanding a queue with + // identical elements is unusual and the extra computations of emplacing + // one-by-one will typically be small relative to calling the constructor + // for every item. + ExpandCapacityIfNecessary(count - size()); + while (size() < count) + emplace_back(); + } else if (count < size()) { + size_t new_end = (begin_ + count) % buffer_.capacity(); + DestructRange(new_end, end_); + end_ = new_end; + + ShrinkCapacityIfNecessary(); + } + IncrementGeneration(); + } + void resize(size_type count, const value_type& value) { + // SEE ABOVE VERSION if you change this. The code is mostly the same. + if (count > size()) { + ExpandCapacityIfNecessary(count - size()); + while (size() < count) + emplace_back(value); + } else if (count < size()) { + size_t new_end = (begin_ + count) % buffer_.capacity(); + DestructRange(new_end, end_); + end_ = new_end; + + ShrinkCapacityIfNecessary(); + } + IncrementGeneration(); + } + + // --------------------------------------------------------------------------- + // Insert and erase. + // + // Insertion and deletion in the middle is O(n) and invalidates all existing + // iterators. + // + // The implementation of insert isn't optimized as much as it could be. If + // the insertion requires that the buffer be grown, it will first be grown + // and everything moved, and then the items will be inserted, potentially + // moving some items twice. This simplifies the implemntation substantially + // and means less generated templatized code. Since this is an uncommon + // operation for deques, and already relatively slow, it doesn't seem worth + // the benefit to optimize this. + + void insert(const_iterator pos, size_type count, const T& value) { + ValidateIterator(pos); + + // Optimize insert at the beginning. + if (pos == begin()) { + ExpandCapacityIfNecessary(count); + for (size_t i = 0; i < count; i++) + push_front(value); + return; + } + + iterator insert_cur(this, pos.index_); + iterator insert_end; + MakeRoomFor(count, &insert_cur, &insert_end); + while (insert_cur < insert_end) { + new (&buffer_[insert_cur.index_]) T(value); + ++insert_cur; + } + + IncrementGeneration(); + } + + // This enable_if keeps this call from getting confused with the (pos, count, + // value) version when value is an integer. + template + typename std::enable_if<::base::internal::is_iterator::value, + void>::type + insert(const_iterator pos, InputIterator first, InputIterator last) { + ValidateIterator(pos); + + size_t inserted_items = std::distance(first, last); + if (inserted_items == 0) + return; // Can divide by 0 when doing modulo below, so return early. + + // Make a hole to copy the items into. + iterator insert_cur; + iterator insert_end; + if (pos == begin()) { + // Optimize insert at the beginning, nothing needs to be shifted and the + // hole is the |inserted_items| block immediately before |begin_|. + ExpandCapacityIfNecessary(inserted_items); + insert_end = begin(); + begin_ = + (begin_ + buffer_.capacity() - inserted_items) % buffer_.capacity(); + insert_cur = begin(); + } else { + insert_cur = iterator(this, pos.index_); + MakeRoomFor(inserted_items, &insert_cur, &insert_end); + } + + // Copy the items. + while (insert_cur < insert_end) { + new (&buffer_[insert_cur.index_]) T(*first); + ++insert_cur; + ++first; + } + + IncrementGeneration(); + } + + // These all return an iterator to the inserted item. Existing iterators will + // be invalidated. + iterator insert(const_iterator pos, const T& value) { + return emplace(pos, value); + } + iterator insert(const_iterator pos, T&& value) { + return emplace(pos, std::move(value)); + } + template + iterator emplace(const_iterator pos, Args&&... args) { + ValidateIterator(pos); + + // Optimize insert at beginning which doesn't require shifting. + if (pos == cbegin()) { + emplace_front(std::forward(args)...); + return begin(); + } + + // Do this before we make the new iterators we return. + IncrementGeneration(); + + iterator insert_begin(this, pos.index_); + iterator insert_end; + MakeRoomFor(1, &insert_begin, &insert_end); + new (&buffer_[insert_begin.index_]) T(std::forward(args)...); + + return insert_begin; + } + + // Calling erase() won't automatically resize the buffer smaller like resize + // or the pop functions. Erase is slow and relatively uncommon, and for + // normal deque usage a pop will normally be done on a regular basis that + // will prevent excessive buffer usage over long periods of time. It's not + // worth having the extra code for every template instantiation of erase() + // to resize capacity downward to a new buffer. + iterator erase(const_iterator pos) { return erase(pos, pos + 1); } + iterator erase(const_iterator first, const_iterator last) { + ValidateIterator(first); + ValidateIterator(last); + + IncrementGeneration(); + + // First, call the destructor on the deleted items. + if (first.index_ == last.index_) { + // Nothing deleted. Need to return early to avoid falling through to + // moving items on top of themselves. + return iterator(this, first.index_); + } else if (first.index_ < last.index_) { + // Contiguous range. + buffer_.DestructRange(&buffer_[first.index_], &buffer_[last.index_]); + } else { + // Deleted range wraps around. + buffer_.DestructRange(&buffer_[first.index_], + &buffer_[buffer_.capacity()]); + buffer_.DestructRange(&buffer_[0], &buffer_[last.index_]); + } + + if (first.index_ == begin_) { + // This deletion is from the beginning. Nothing needs to be copied, only + // begin_ needs to be updated. + begin_ = last.index_; + return iterator(this, last.index_); + } + + // In an erase operation, the shifted items all move logically to the left, + // so move them from left-to-right. + iterator move_src(this, last.index_); + iterator move_src_end = end(); + iterator move_dest(this, first.index_); + for (; move_src < move_src_end; move_src++, move_dest++) { + buffer_.MoveRange(&buffer_[move_src.index_], + &buffer_[move_src.index_ + 1], + &buffer_[move_dest.index_]); + } + + end_ = move_dest.index_; + + // Since we did not reallocate and only changed things after the erase + // element(s), the input iterator's index points to the thing following the + // deletion. + return iterator(this, first.index_); + } + + // --------------------------------------------------------------------------- + // Begin/end operations. + + void push_front(const T& value) { emplace_front(value); } + void push_front(T&& value) { emplace_front(std::move(value)); } + + void push_back(const T& value) { emplace_back(value); } + void push_back(T&& value) { emplace_back(std::move(value)); } + + template + reference emplace_front(Args&&... args) { + ExpandCapacityIfNecessary(1); + if (begin_ == 0) + begin_ = buffer_.capacity() - 1; + else + begin_--; + IncrementGeneration(); + new (&buffer_[begin_]) T(std::forward(args)...); + return front(); + } + + template + reference emplace_back(Args&&... args) { + ExpandCapacityIfNecessary(1); + new (&buffer_[end_]) T(std::forward(args)...); + if (end_ == buffer_.capacity() - 1) + end_ = 0; + else + end_++; + IncrementGeneration(); + return back(); + } + + void pop_front() { + DCHECK(size()); + buffer_.DestructRange(&buffer_[begin_], &buffer_[begin_ + 1]); + begin_++; + if (begin_ == buffer_.capacity()) + begin_ = 0; + + ShrinkCapacityIfNecessary(); + + // Technically popping will not invalidate any iterators since the + // underlying buffer will be stable. But in the future we may want to add a + // feature that resizes the buffer smaller if there is too much wasted + // space. This ensures we can make such a change safely. + IncrementGeneration(); + } + void pop_back() { + DCHECK(size()); + if (end_ == 0) + end_ = buffer_.capacity() - 1; + else + end_--; + buffer_.DestructRange(&buffer_[end_], &buffer_[end_ + 1]); + + ShrinkCapacityIfNecessary(); + + // See pop_front comment about why this is here. + IncrementGeneration(); + } + + // --------------------------------------------------------------------------- + // General operations. + + void swap(circular_deque& other) { + std::swap(buffer_, other.buffer_); + std::swap(begin_, other.begin_); + std::swap(end_, other.end_); + IncrementGeneration(); + } + + friend void swap(circular_deque& lhs, circular_deque& rhs) { lhs.swap(rhs); } + + private: + friend internal::circular_deque_iterator; + friend internal::circular_deque_const_iterator; + + // Moves the items in the given circular buffer to the current one. The + // source is moved from so will become invalid. The destination buffer must + // have already been allocated with enough size. + static void MoveBuffer(VectorBuffer& from_buf, + size_t from_begin, + size_t from_end, + VectorBuffer* to_buf, + size_t* to_begin, + size_t* to_end) { + size_t from_capacity = from_buf.capacity(); + + *to_begin = 0; + if (from_begin < from_end) { + // Contiguous. + from_buf.MoveRange(&from_buf[from_begin], &from_buf[from_end], + to_buf->begin()); + *to_end = from_end - from_begin; + } else if (from_begin > from_end) { + // Discontiguous, copy the right side to the beginning of the new buffer. + from_buf.MoveRange(&from_buf[from_begin], &from_buf[from_capacity], + to_buf->begin()); + size_t right_size = from_capacity - from_begin; + // Append the left side. + from_buf.MoveRange(&from_buf[0], &from_buf[from_end], + &(*to_buf)[right_size]); + *to_end = right_size + from_end; + } else { + // No items. + *to_end = 0; + } + } + + // Expands the buffer size. This assumes the size is larger than the + // number of elements in the vector (it won't call delete on anything). + void SetCapacityTo(size_t new_capacity) { + // Use the capacity + 1 as the internal buffer size to differentiate + // empty and full (see definition of buffer_ below). + VectorBuffer new_buffer(new_capacity + 1); + MoveBuffer(buffer_, begin_, end_, &new_buffer, &begin_, &end_); + buffer_ = std::move(new_buffer); + } + void ExpandCapacityIfNecessary(size_t additional_elts) { + size_t min_new_capacity = size() + additional_elts; + if (capacity() >= min_new_capacity) + return; // Already enough room. + + min_new_capacity = + std::max(min_new_capacity, internal::kCircularBufferInitialCapacity); + + // std::vector always grows by at least 50%. WTF::Deque grows by at least + // 25%. We expect queue workloads to generally stay at a similar size and + // grow less than a vector might, so use 25%. + size_t new_capacity = + std::max(min_new_capacity, capacity() + capacity() / 4); + SetCapacityTo(new_capacity); + } + + void ShrinkCapacityIfNecessary() { + // Don't auto-shrink below this size. + if (capacity() <= internal::kCircularBufferInitialCapacity) + return; + + // Shrink when 100% of the size() is wasted. + size_t sz = size(); + size_t empty_spaces = capacity() - sz; + if (empty_spaces < sz) + return; + + // Leave 1/4 the size as free capacity, not going below the initial + // capacity. + size_t new_capacity = + std::max(internal::kCircularBufferInitialCapacity, sz + sz / 4); + if (new_capacity < capacity()) { + // Count extra item to convert to internal capacity. + SetCapacityTo(new_capacity); + } + } + + // Backend for clear() but does not resize the internal buffer. + void ClearRetainCapacity() { + // This can't resize(0) because that requires a default constructor to + // compile, which not all contained classes may implement. + DestructRange(begin_, end_); + begin_ = 0; + end_ = 0; + IncrementGeneration(); + } + + // Calls destructors for the given begin->end indices. The indices may wrap + // around. The buffer is not resized, and the begin_ and end_ members are + // not changed. + void DestructRange(size_t begin, size_t end) { + if (end == begin) { + return; + } else if (end > begin) { + buffer_.DestructRange(&buffer_[begin], &buffer_[end]); + } else { + buffer_.DestructRange(&buffer_[begin], &buffer_[buffer_.capacity()]); + buffer_.DestructRange(&buffer_[0], &buffer_[end]); + } + } + + // Makes room for |count| items starting at |*insert_begin|. Since iterators + // are not stable across buffer resizes, |*insert_begin| will be updated to + // point to the beginning of the newly opened position in the new array (it's + // in/out), and the end of the newly opened position (it's out-only). + void MakeRoomFor(size_t count, iterator* insert_begin, iterator* insert_end) { + if (count == 0) { + *insert_end = *insert_begin; + return; + } + + // The offset from the beginning will be stable across reallocations. + size_t begin_offset = insert_begin->OffsetFromBegin(); + ExpandCapacityIfNecessary(count); + + insert_begin->index_ = (begin_ + begin_offset) % buffer_.capacity(); + *insert_end = + iterator(this, (insert_begin->index_ + count) % buffer_.capacity()); + + // Update the new end and prepare the iterators for copying. + iterator src = end(); + end_ = (end_ + count) % buffer_.capacity(); + iterator dest = end(); + + // Move the elements. This will always involve shifting logically to the + // right, so move in a right-to-left order. + while (true) { + if (src == *insert_begin) + break; + --src; + --dest; + buffer_.MoveRange(&buffer_[src.index_], &buffer_[src.index_ + 1], + &buffer_[dest.index_]); + } + } + +#if DCHECK_IS_ON() + // Asserts the given index is dereferencable. The index is an index into the + // buffer, not an index used by operator[] or at() which will be offsets from + // begin. + void CheckValidIndex(size_t i) const { + if (begin_ <= end_) + DCHECK(i >= begin_ && i < end_); + else + DCHECK((i >= begin_ && i < buffer_.capacity()) || i < end_); + } + + // Asserts the given index is either dereferencable or points to end(). + void CheckValidIndexOrEnd(size_t i) const { + if (i != end_) + CheckValidIndex(i); + } + + void ValidateIterator(const const_iterator& i) const { + DCHECK(i.parent_deque_ == this); + i.CheckUnstableUsage(); + } + + // See generation_ below. + void IncrementGeneration() { generation_++; } +#else + // No-op versions of these functions for release builds. + void CheckValidIndex(size_t) const {} + void CheckValidIndexOrEnd(size_t) const {} + void ValidateIterator(const const_iterator& i) const {} + void IncrementGeneration() {} +#endif + + // Danger, the buffer_.capacity() is the "internal capacity" which is + // capacity() + 1 since there is an extra item to indicate the end. Otherwise + // being completely empty and completely full are indistinguishable (begin == + // end). We could add a separate flag to avoid it, but that adds significant + // extra complexity since every computation will have to check for it. Always + // keeping one extra unused element in the buffer makes iterator computations + // much simpler. + // + // Container internal code will want to use buffer_.capacity() for offset + // computations rather than capacity(). + VectorBuffer buffer_; + size_type begin_ = 0; + size_type end_ = 0; + +#if DCHECK_IS_ON() + // Incremented every time a modification is made that could affect iterator + // invalidations. + uint64_t generation_ = 0; +#endif +}; + +// Implementations of base::Erase[If] (see base/stl_util.h). +template +void Erase(circular_deque& container, const Value& value) { + container.erase(std::remove(container.begin(), container.end(), value), + container.end()); +} + +template +void EraseIf(circular_deque& container, Predicate pred) { + container.erase(std::remove_if(container.begin(), container.end(), pred), + container.end()); +} + +} // namespace base + +#endif // BASE_CONTAINERS_CIRCULAR_DEQUE_H_ diff --git a/src/3rdparty/gn/base/containers/flat_map.h b/src/3rdparty/gn/base/containers/flat_map.h new file mode 100644 index 00000000000..b4fe5196ec8 --- /dev/null +++ b/src/3rdparty/gn/base/containers/flat_map.h @@ -0,0 +1,362 @@ +// Copyright 2017 The Chromium 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_CONTAINERS_FLAT_MAP_H_ +#define BASE_CONTAINERS_FLAT_MAP_H_ + +#include +#include +#include + +#include "base/containers/flat_tree.h" +#include "base/logging.h" +#include "base/template_util.h" + +namespace base { + +namespace internal { + +// An implementation of the flat_tree GetKeyFromValue template parameter that +// extracts the key as the first element of a pair. +template +struct GetKeyFromValuePairFirst { + const Key& operator()(const std::pair& p) const { + return p.first; + } +}; + +} // namespace internal + +// flat_map is a container with a std::map-like interface that stores its +// contents in a sorted vector. +// +// Please see //base/containers/README.md for an overview of which container +// to select. +// +// PROS +// +// - Good memory locality. +// - Low overhead, especially for smaller maps. +// - Performance is good for more workloads than you might expect (see +// overview link above). +// - Supports C++14 map interface. +// +// CONS +// +// - Inserts and removals are O(n). +// +// IMPORTANT NOTES +// +// - Iterators are invalidated across mutations. +// - If possible, construct a flat_map in one operation by inserting into +// a std::vector and moving that vector into the flat_map constructor. +// +// QUICK REFERENCE +// +// Most of the core functionality is inherited from flat_tree. Please see +// flat_tree.h for more details for most of these functions. As a quick +// reference, the functions available are: +// +// Constructors (inputs need not be sorted): +// flat_map(InputIterator first, InputIterator last, +// FlatContainerDupes = KEEP_FIRST_OF_DUPES, +// const Compare& compare = Compare()); +// flat_map(const flat_map&); +// flat_map(flat_map&&); +// flat_map(std::vector, +// FlatContainerDupes = KEEP_FIRST_OF_DUPES, +// const Compare& compare = Compare()); // Re-use storage. +// flat_map(std::initializer_list ilist, +// FlatContainerDupes = KEEP_FIRST_OF_DUPES, +// const Compare& comp = Compare()); +// +// Assignment functions: +// flat_map& operator=(const flat_map&); +// flat_map& operator=(flat_map&&); +// flat_map& operator=(initializer_list); +// +// Memory management functions: +// void reserve(size_t); +// size_t capacity() const; +// void shrink_to_fit(); +// +// Size management functions: +// void clear(); +// size_t size() const; +// size_t max_size() const; +// bool empty() const; +// +// Iterator functions: +// iterator begin(); +// const_iterator begin() const; +// const_iterator cbegin() const; +// iterator end(); +// const_iterator end() const; +// const_iterator cend() const; +// reverse_iterator rbegin(); +// const reverse_iterator rbegin() const; +// const_reverse_iterator crbegin() const; +// reverse_iterator rend(); +// const_reverse_iterator rend() const; +// const_reverse_iterator crend() const; +// +// Insert and accessor functions: +// mapped_type& operator[](const key_type&); +// mapped_type& operator[](key_type&&); +// pair insert(const value_type&); +// pair insert(value_type&&); +// iterator insert(const_iterator hint, const value_type&); +// iterator insert(const_iterator hint, value_type&&); +// void insert(InputIterator first, InputIterator last, +// FlatContainerDupes = KEEP_FIRST_OF_DUPES); +// pair insert_or_assign(K&&, M&&); +// iterator insert_or_assign(const_iterator hint, K&&, M&&); +// pair emplace(Args&&...); +// iterator emplace_hint(const_iterator, Args&&...); +// pair try_emplace(K&&, Args&&...); +// iterator try_emplace(const_iterator hint, K&&, Args&&...); +// +// Erase functions: +// iterator erase(iterator); +// iterator erase(const_iterator); +// iterator erase(const_iterator first, const_iterator& last); +// template size_t erase(const K& key); +// +// Comparators (see std::map documentation). +// key_compare key_comp() const; +// value_compare value_comp() const; +// +// Search functions: +// template size_t count(const K&) const; +// template iterator find(const K&); +// template const_iterator find(const K&) const; +// template pair equal_range(const K&); +// template iterator lower_bound(const K&); +// template const_iterator lower_bound(const K&) const; +// template iterator upper_bound(const K&); +// template const_iterator upper_bound(const K&) const; +// +// General functions: +// void swap(flat_map&&); +// +// Non-member operators: +// bool operator==(const flat_map&, const flat_map); +// bool operator!=(const flat_map&, const flat_map); +// bool operator<(const flat_map&, const flat_map); +// bool operator>(const flat_map&, const flat_map); +// bool operator>=(const flat_map&, const flat_map); +// bool operator<=(const flat_map&, const flat_map); +// +template > +class flat_map : public ::base::internal::flat_tree< + Key, + std::pair, + ::base::internal::GetKeyFromValuePairFirst, + Compare> { + private: + using tree = typename ::base::internal::flat_tree< + Key, + std::pair, + ::base::internal::GetKeyFromValuePairFirst, + Compare>; + + public: + using key_type = typename tree::key_type; + using mapped_type = Mapped; + using value_type = typename tree::value_type; + using iterator = typename tree::iterator; + using const_iterator = typename tree::const_iterator; + + // -------------------------------------------------------------------------- + // Lifetime and assignments. + // + // Note: we could do away with these constructors, destructor and assignment + // operator overloads by inheriting |tree|'s, but this breaks the GCC build + // due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84782 (see + // https://crbug.com/837221). + + flat_map() = default; + explicit flat_map(const Compare& comp); + + template + flat_map(InputIterator first, + InputIterator last, + FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES, + const Compare& comp = Compare()); + + flat_map(const flat_map&) = default; + flat_map(flat_map&&) noexcept = default; + + flat_map(std::vector items, + FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES, + const Compare& comp = Compare()); + + flat_map(std::initializer_list ilist, + FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES, + const Compare& comp = Compare()); + + ~flat_map() = default; + + flat_map& operator=(const flat_map&) = default; + flat_map& operator=(flat_map&&) = default; + // Takes the first if there are duplicates in the initializer list. + flat_map& operator=(std::initializer_list ilist); + + // -------------------------------------------------------------------------- + // Map-specific insert operations. + // + // Normal insert() functions are inherited from flat_tree. + // + // Assume that every operation invalidates iterators and references. + // Insertion of one element can take O(size). + + mapped_type& operator[](const key_type& key); + mapped_type& operator[](key_type&& key); + + template + std::pair insert_or_assign(K&& key, M&& obj); + template + iterator insert_or_assign(const_iterator hint, K&& key, M&& obj); + + template + std::enable_if_t::value, + std::pair> + try_emplace(K&& key, Args&&... args); + + template + std::enable_if_t::value, iterator> + try_emplace(const_iterator hint, K&& key, Args&&... args); + + // -------------------------------------------------------------------------- + // General operations. + // + // Assume that swap invalidates iterators and references. + + void swap(flat_map& other) noexcept; + + friend void swap(flat_map& lhs, flat_map& rhs) noexcept { lhs.swap(rhs); } +}; + +// ---------------------------------------------------------------------------- +// Lifetime. + +template +flat_map::flat_map(const Compare& comp) : tree(comp) {} + +template +template +flat_map::flat_map(InputIterator first, + InputIterator last, + FlatContainerDupes dupe_handling, + const Compare& comp) + : tree(first, last, dupe_handling, comp) {} + +template +flat_map::flat_map(std::vector items, + FlatContainerDupes dupe_handling, + const Compare& comp) + : tree(std::move(items), dupe_handling, comp) {} + +template +flat_map::flat_map( + std::initializer_list ilist, + FlatContainerDupes dupe_handling, + const Compare& comp) + : flat_map(std::begin(ilist), std::end(ilist), dupe_handling, comp) {} + +// ---------------------------------------------------------------------------- +// Assignments. + +template +auto flat_map::operator=( + std::initializer_list ilist) -> flat_map& { + // When https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84782 gets fixed, we + // need to remember to inherit tree::operator= to prevent + // flat_map<...> x; + // x = {...}; + // from first creating a flat_map and then move assigning it. This most + // likely would be optimized away but still affects our debug builds. + tree::operator=(ilist); + return *this; +} + +// ---------------------------------------------------------------------------- +// Insert operations. + +template +auto flat_map::operator[](const key_type& key) + -> mapped_type& { + iterator found = tree::lower_bound(key); + if (found == tree::end() || tree::key_comp()(key, found->first)) + found = tree::unsafe_emplace(found, key, mapped_type()); + return found->second; +} + +template +auto flat_map::operator[](key_type&& key) + -> mapped_type& { + iterator found = tree::lower_bound(key); + if (found == tree::end() || tree::key_comp()(key, found->first)) + found = tree::unsafe_emplace(found, std::move(key), mapped_type()); + return found->second; +} + +template +template +auto flat_map::insert_or_assign(K&& key, M&& obj) + -> std::pair { + auto result = + tree::emplace_key_args(key, std::forward(key), std::forward(obj)); + if (!result.second) + result.first->second = std::forward(obj); + return result; +} + +template +template +auto flat_map::insert_or_assign(const_iterator hint, + K&& key, + M&& obj) -> iterator { + auto result = tree::emplace_hint_key_args(hint, key, std::forward(key), + std::forward(obj)); + if (!result.second) + result.first->second = std::forward(obj); + return result.first; +} + +template +template +auto flat_map::try_emplace(K&& key, Args&&... args) + -> std::enable_if_t::value, + std::pair> { + return tree::emplace_key_args( + key, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(args)...)); +} + +template +template +auto flat_map::try_emplace(const_iterator hint, + K&& key, + Args&&... args) + -> std::enable_if_t::value, iterator> { + return tree::emplace_hint_key_args( + hint, key, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), + std::forward_as_tuple(std::forward(args)...)) + .first; +} + +// ---------------------------------------------------------------------------- +// General operations. + +template +void flat_map::swap(flat_map& other) noexcept { + tree::swap(other); +} + +} // namespace base + +#endif // BASE_CONTAINERS_FLAT_MAP_H_ diff --git a/src/3rdparty/gn/base/containers/flat_set.h b/src/3rdparty/gn/base/containers/flat_set.h new file mode 100644 index 00000000000..700617f2825 --- /dev/null +++ b/src/3rdparty/gn/base/containers/flat_set.h @@ -0,0 +1,141 @@ +// Copyright 2017 The Chromium 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_CONTAINERS_FLAT_SET_H_ +#define BASE_CONTAINERS_FLAT_SET_H_ + +#include + +#include "base/containers/flat_tree.h" +#include "base/template_util.h" + +namespace base { + +// flat_set is a container with a std::set-like interface that stores its +// contents in a sorted vector. +// +// Please see //base/containers/README.md for an overview of which container +// to select. +// +// PROS +// +// - Good memory locality. +// - Low overhead, especially for smaller sets. +// - Performance is good for more workloads than you might expect (see +// overview link above). +// - Supports C++14 set interface. +// +// CONS +// +// - Inserts and removals are O(n). +// +// IMPORTANT NOTES +// +// - Iterators are invalidated across mutations. +// - If possible, construct a flat_set in one operation by inserting into +// a std::vector and moving that vector into the flat_set constructor. +// - For multiple removals use base::EraseIf() which is O(n) rather than +// O(n * removed_items). +// +// QUICK REFERENCE +// +// Most of the core functionality is inherited from flat_tree. Please see +// flat_tree.h for more details for most of these functions. As a quick +// reference, the functions available are: +// +// Constructors (inputs need not be sorted): +// flat_set(InputIterator first, InputIterator last, +// FlatContainerDupes = KEEP_FIRST_OF_DUPES, +// const Compare& compare = Compare()); +// flat_set(const flat_set&); +// flat_set(flat_set&&); +// flat_set(std::vector, +// FlatContainerDupes = KEEP_FIRST_OF_DUPES, +// const Compare& compare = Compare()); // Re-use storage. +// flat_set(std::initializer_list ilist, +// FlatContainerDupes = KEEP_FIRST_OF_DUPES, +// const Compare& comp = Compare()); +// +// Assignment functions: +// flat_set& operator=(const flat_set&); +// flat_set& operator=(flat_set&&); +// flat_set& operator=(initializer_list); +// +// Memory management functions: +// void reserve(size_t); +// size_t capacity() const; +// void shrink_to_fit(); +// +// Size management functions: +// void clear(); +// size_t size() const; +// size_t max_size() const; +// bool empty() const; +// +// Iterator functions: +// iterator begin(); +// const_iterator begin() const; +// const_iterator cbegin() const; +// iterator end(); +// const_iterator end() const; +// const_iterator cend() const; +// reverse_iterator rbegin(); +// const reverse_iterator rbegin() const; +// const_reverse_iterator crbegin() const; +// reverse_iterator rend(); +// const_reverse_iterator rend() const; +// const_reverse_iterator crend() const; +// +// Insert and accessor functions: +// pair insert(const key_type&); +// pair insert(key_type&&); +// void insert(InputIterator first, InputIterator last, +// FlatContainerDupes = KEEP_FIRST_OF_DUPES); +// iterator insert(const_iterator hint, const key_type&); +// iterator insert(const_iterator hint, key_type&&); +// pair emplace(Args&&...); +// iterator emplace_hint(const_iterator, Args&&...); +// +// Erase functions: +// iterator erase(iterator); +// iterator erase(const_iterator); +// iterator erase(const_iterator first, const_iterator& last); +// template size_t erase(const K& key); +// +// Comparators (see std::set documentation). +// key_compare key_comp() const; +// value_compare value_comp() const; +// +// Search functions: +// template size_t count(const K&) const; +// template iterator find(const K&); +// template const_iterator find(const K&) const; +// template bool contains(const K&) const; +// template pair equal_range(K&); +// template iterator lower_bound(const K&); +// template const_iterator lower_bound(const K&) const; +// template iterator upper_bound(const K&); +// template const_iterator upper_bound(const K&) const; +// +// General functions: +// void swap(flat_set&&); +// +// Non-member operators: +// bool operator==(const flat_set&, const flat_set); +// bool operator!=(const flat_set&, const flat_set); +// bool operator<(const flat_set&, const flat_set); +// bool operator>(const flat_set&, const flat_set); +// bool operator>=(const flat_set&, const flat_set); +// bool operator<=(const flat_set&, const flat_set); +// +template > +using flat_set = typename ::base::internal::flat_tree< + Key, + Key, + ::base::internal::GetKeyFromValueIdentity, + Compare>; + +} // namespace base + +#endif // BASE_CONTAINERS_FLAT_SET_H_ \ No newline at end of file diff --git a/src/3rdparty/gn/base/containers/flat_tree.h b/src/3rdparty/gn/base/containers/flat_tree.h new file mode 100644 index 00000000000..7856e242336 --- /dev/null +++ b/src/3rdparty/gn/base/containers/flat_tree.h @@ -0,0 +1,1004 @@ +// Copyright 2017 The Chromium 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_CONTAINERS_FLAT_TREE_H_ +#define BASE_CONTAINERS_FLAT_TREE_H_ + +#include +#include +#include +#include + +#include "base/template_util.h" + +namespace base { + +enum FlatContainerDupes { + KEEP_FIRST_OF_DUPES, + KEEP_LAST_OF_DUPES, +}; + +namespace internal { + +// This is a convenience method returning true if Iterator is at least a +// ForwardIterator and thus supports multiple passes over a range. +template +constexpr bool is_multipass() { + return std::is_base_of< + std::forward_iterator_tag, + typename std::iterator_traits::iterator_category>::value; +} + +// This algorithm is like unique() from the standard library except it +// selects only the last of consecutive values instead of the first. +template +Iterator LastUnique(Iterator first, Iterator last, BinaryPredicate compare) { + Iterator replacable = std::adjacent_find(first, last, compare); + + // No duplicate elements found. + if (replacable == last) + return last; + + first = std::next(replacable); + + // Last element is a duplicate but all others are unique. + if (first == last) + return replacable; + + // This loop is based on std::adjacent_find but std::adjacent_find doesn't + // quite cut it. + for (Iterator next = std::next(first); next != last; ++next, ++first) { + if (!compare(*first, *next)) + *replacable++ = std::move(*first); + } + + // Last element should be copied unconditionally. + *replacable++ = std::move(*first); + return replacable; +} + +// Uses SFINAE to detect whether type has is_transparent member. +template +struct IsTransparentCompare : std::false_type {}; +template +struct IsTransparentCompare> + : std::true_type {}; + +// Implementation ------------------------------------------------------------- + +// Implementation of a sorted vector for backing flat_set and flat_map. Do not +// use directly. +// +// The use of "value" in this is like std::map uses, meaning it's the thing +// contained (in the case of map it's a pair). The Key is how +// things are looked up. In the case of a set, Key == Value. In the case of +// a map, the Key is a component of a Value. +// +// The helper class GetKeyFromValue provides the means to extract a key from a +// value for comparison purposes. It should implement: +// const Key& operator()(const Value&). +template +class flat_tree { + private: + using underlying_type = std::vector; + + public: + // -------------------------------------------------------------------------- + // Types. + // + using key_type = Key; + using key_compare = KeyCompare; + using value_type = Value; + + // Wraps the templated key comparison to compare values. + class value_compare : public key_compare { + public: + value_compare() = default; + + template + explicit value_compare(Cmp&& compare_arg) + : KeyCompare(std::forward(compare_arg)) {} + + bool operator()(const value_type& left, const value_type& right) const { + GetKeyFromValue extractor; + return key_compare::operator()(extractor(left), extractor(right)); + } + }; + + using pointer = typename underlying_type::pointer; + using const_pointer = typename underlying_type::const_pointer; + using reference = typename underlying_type::reference; + using const_reference = typename underlying_type::const_reference; + using size_type = typename underlying_type::size_type; + using difference_type = typename underlying_type::difference_type; + using iterator = typename underlying_type::iterator; + using const_iterator = typename underlying_type::const_iterator; + using reverse_iterator = typename underlying_type::reverse_iterator; + using const_reverse_iterator = + typename underlying_type::const_reverse_iterator; + + // -------------------------------------------------------------------------- + // Lifetime. + // + // Constructors that take range guarantee O(N * log^2(N)) + O(N) complexity + // and take O(N * log(N)) + O(N) if extra memory is available (N is a range + // length). + // + // Assume that move constructors invalidate iterators and references. + // + // The constructors that take ranges, lists, and vectors do not require that + // the input be sorted. + + flat_tree(); + explicit flat_tree(const key_compare& comp); + + template + flat_tree(InputIterator first, + InputIterator last, + FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES, + const key_compare& comp = key_compare()); + + flat_tree(const flat_tree&); + flat_tree(flat_tree&&) noexcept = default; + + flat_tree(std::vector items, + FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES, + const key_compare& comp = key_compare()); + + flat_tree(std::initializer_list ilist, + FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES, + const key_compare& comp = key_compare()); + + ~flat_tree(); + + // -------------------------------------------------------------------------- + // Assignments. + // + // Assume that move assignment invalidates iterators and references. + + flat_tree& operator=(const flat_tree&); + flat_tree& operator=(flat_tree&&); + // Takes the first if there are duplicates in the initializer list. + flat_tree& operator=(std::initializer_list ilist); + + // -------------------------------------------------------------------------- + // Memory management. + // + // Beware that shrink_to_fit() simply forwards the request to the + // underlying_type and its implementation is free to optimize otherwise and + // leave capacity() to be greater that its size. + // + // reserve() and shrink_to_fit() invalidate iterators and references. + + void reserve(size_type new_capacity); + size_type capacity() const; + void shrink_to_fit(); + + // -------------------------------------------------------------------------- + // Size management. + // + // clear() leaves the capacity() of the flat_tree unchanged. + + void clear(); + + size_type size() const; + size_type max_size() const; + bool empty() const; + + // -------------------------------------------------------------------------- + // Iterators. + + iterator begin(); + const_iterator begin() const; + const_iterator cbegin() const; + + iterator end(); + const_iterator end() const; + const_iterator cend() const; + + reverse_iterator rbegin(); + const_reverse_iterator rbegin() const; + const_reverse_iterator crbegin() const; + + reverse_iterator rend(); + const_reverse_iterator rend() const; + const_reverse_iterator crend() const; + + // -------------------------------------------------------------------------- + // Insert operations. + // + // Assume that every operation invalidates iterators and references. + // Insertion of one element can take O(size). Capacity of flat_tree grows in + // an implementation-defined manner. + // + // NOTE: Prefer to build a new flat_tree from a std::vector (or similar) + // instead of calling insert() repeatedly. + + std::pair insert(const value_type& val); + std::pair insert(value_type&& val); + + iterator insert(const_iterator position_hint, const value_type& x); + iterator insert(const_iterator position_hint, value_type&& x); + + // This method inserts the values from the range [first, last) into the + // current tree. In case of KEEP_LAST_OF_DUPES newly added elements can + // overwrite existing values. + template + void insert(InputIterator first, + InputIterator last, + FlatContainerDupes dupes = KEEP_FIRST_OF_DUPES); + + template + std::pair emplace(Args&&... args); + + template + iterator emplace_hint(const_iterator position_hint, Args&&... args); + + // -------------------------------------------------------------------------- + // Erase operations. + // + // Assume that every operation invalidates iterators and references. + // + // erase(position), erase(first, last) can take O(size). + // erase(key) may take O(size) + O(log(size)). + // + // Prefer base::EraseIf() or some other variation on erase(remove(), end()) + // idiom when deleting multiple non-consecutive elements. + + iterator erase(iterator position); + iterator erase(const_iterator position); + iterator erase(const_iterator first, const_iterator last); + template + size_type erase(const K& key); + + // -------------------------------------------------------------------------- + // Comparators. + + key_compare key_comp() const; + value_compare value_comp() const; + + // -------------------------------------------------------------------------- + // Search operations. + // + // Search operations have O(log(size)) complexity. + + template + size_type count(const K& key) const; + + template + iterator find(const K& key); + + template + const_iterator find(const K& key) const; + + template + std::pair equal_range(const K& key); + + template + std::pair equal_range(const K& key) const; + + template + iterator lower_bound(const K& key); + + template + const_iterator lower_bound(const K& key) const; + + template + iterator upper_bound(const K& key); + + template + const_iterator upper_bound(const K& key) const; + + // -------------------------------------------------------------------------- + // General operations. + // + // Assume that swap invalidates iterators and references. + // + // Implementation note: currently we use operator==() and operator<() on + // std::vector, because they have the same contract we need, so we use them + // directly for brevity and in case it is more optimal than calling equal() + // and lexicograhpical_compare(). If the underlying container type is changed, + // this code may need to be modified. + + void swap(flat_tree& other) noexcept; + + friend bool operator==(const flat_tree& lhs, const flat_tree& rhs) { + return lhs.impl_.body_ == rhs.impl_.body_; + } + + friend bool operator!=(const flat_tree& lhs, const flat_tree& rhs) { + return !(lhs == rhs); + } + + friend bool operator<(const flat_tree& lhs, const flat_tree& rhs) { + return lhs.impl_.body_ < rhs.impl_.body_; + } + + friend bool operator>(const flat_tree& lhs, const flat_tree& rhs) { + return rhs < lhs; + } + + friend bool operator>=(const flat_tree& lhs, const flat_tree& rhs) { + return !(lhs < rhs); + } + + friend bool operator<=(const flat_tree& lhs, const flat_tree& rhs) { + return !(lhs > rhs); + } + + friend void swap(flat_tree& lhs, flat_tree& rhs) noexcept { lhs.swap(rhs); } + + protected: + // Emplaces a new item into the tree that is known not to be in it. This + // is for implementing map operator[]. + template + iterator unsafe_emplace(const_iterator position, Args&&... args); + + // Attempts to emplace a new element with key |key|. Only if |key| is not yet + // present, construct value_type from |args| and insert it. Returns an + // iterator to the element with key |key| and a bool indicating whether an + // insertion happened. + template + std::pair emplace_key_args(const K& key, Args&&... args); + + // Similar to |emplace_key_args|, but checks |hint| first as a possible + // insertion position. + template + std::pair emplace_hint_key_args(const_iterator hint, + const K& key, + Args&&... args); + + private: + // Helper class for e.g. lower_bound that can compare a value on the left + // to a key on the right. + struct KeyValueCompare { + // The key comparison object must outlive this class. + explicit KeyValueCompare(const key_compare& key_comp) + : key_comp_(key_comp) {} + + template + bool operator()(const T& lhs, const U& rhs) const { + return key_comp_(extract_if_value_type(lhs), extract_if_value_type(rhs)); + } + + private: + const key_type& extract_if_value_type(const value_type& v) const { + GetKeyFromValue extractor; + return extractor(v); + } + + template + const K& extract_if_value_type(const K& k) const { + return k; + } + + const key_compare& key_comp_; + }; + + const flat_tree& as_const() { return *this; } + + iterator const_cast_it(const_iterator c_it) { + auto distance = std::distance(cbegin(), c_it); + return std::next(begin(), distance); + } + + // This method is inspired by both std::map::insert(P&&) and + // std::map::insert_or_assign(const K&, V&&). It inserts val if an equivalent + // element is not present yet, otherwise it overwrites. It returns an iterator + // to the modified element and a flag indicating whether insertion or + // assignment happened. + template + std::pair insert_or_assign(V&& val) { + auto position = lower_bound(GetKeyFromValue()(val)); + + if (position == end() || value_comp()(val, *position)) + return {impl_.body_.emplace(position, std::forward(val)), true}; + + *position = std::forward(val); + return {position, false}; + } + + // This method is similar to insert_or_assign, with the following differences: + // - Instead of searching [begin(), end()) it only searches [first, last). + // - In case no equivalent element is found, val is appended to the end of the + // underlying body and an iterator to the next bigger element in [first, + // last) is returned. + template + std::pair append_or_assign(iterator first, + iterator last, + V&& val) { + auto position = std::lower_bound(first, last, val, value_comp()); + + if (position == last || value_comp()(val, *position)) { + // emplace_back might invalidate position, which is why distance needs to + // be cached. + const difference_type distance = std::distance(begin(), position); + impl_.body_.emplace_back(std::forward(val)); + return {std::next(begin(), distance), true}; + } + + *position = std::forward(val); + return {position, false}; + } + + // This method is similar to insert, with the following differences: + // - Instead of searching [begin(), end()) it only searches [first, last). + // - In case no equivalent element is found, val is appended to the end of the + // underlying body and an iterator to the next bigger element in [first, + // last) is returned. + template + std::pair append_unique(iterator first, + iterator last, + V&& val) { + auto position = std::lower_bound(first, last, val, value_comp()); + + if (position == last || value_comp()(val, *position)) { + // emplace_back might invalidate position, which is why distance needs to + // be cached. + const difference_type distance = std::distance(begin(), position); + impl_.body_.emplace_back(std::forward(val)); + return {std::next(begin(), distance), true}; + } + + return {position, false}; + } + + void sort_and_unique(iterator first, + iterator last, + FlatContainerDupes dupes) { + // Preserve stability for the unique code below. + std::stable_sort(first, last, impl_.get_value_comp()); + + auto comparator = [this](const value_type& lhs, const value_type& rhs) { + // lhs is already <= rhs due to sort, therefore + // !(lhs < rhs) <=> lhs == rhs. + return !impl_.get_value_comp()(lhs, rhs); + }; + + iterator erase_after; + switch (dupes) { + case KEEP_FIRST_OF_DUPES: + erase_after = std::unique(first, last, comparator); + break; + case KEEP_LAST_OF_DUPES: + erase_after = LastUnique(first, last, comparator); + break; + } + erase(erase_after, last); + } + + // To support comparators that may not be possible to default-construct, we + // have to store an instance of Compare. Using this to store all internal + // state of flat_tree and using private inheritance to store compare lets us + // take advantage of an empty base class optimization to avoid extra space in + // the common case when Compare has no state. + struct Impl : private value_compare { + Impl() = default; + + template + explicit Impl(Cmp&& compare_arg, Body&&... underlying_type_args) + : value_compare(std::forward(compare_arg)), + body_(std::forward(underlying_type_args)...) {} + + const value_compare& get_value_comp() const { return *this; } + const key_compare& get_key_comp() const { return *this; } + + underlying_type body_; + } impl_; + + // If the compare is not transparent we want to construct key_type once. + template + using KeyTypeOrK = typename std:: + conditional::value, K, key_type>::type; +}; + +// ---------------------------------------------------------------------------- +// Lifetime. + +template +flat_tree::flat_tree() = default; + +template +flat_tree::flat_tree( + const KeyCompare& comp) + : impl_(comp) {} + +template +template +flat_tree::flat_tree( + InputIterator first, + InputIterator last, + FlatContainerDupes dupe_handling, + const KeyCompare& comp) + : impl_(comp, first, last) { + sort_and_unique(begin(), end(), dupe_handling); +} + +template +flat_tree::flat_tree( + const flat_tree&) = default; + +template +flat_tree::flat_tree( + std::vector items, + FlatContainerDupes dupe_handling, + const KeyCompare& comp) + : impl_(comp, std::move(items)) { + sort_and_unique(begin(), end(), dupe_handling); +} + +template +flat_tree::flat_tree( + std::initializer_list ilist, + FlatContainerDupes dupe_handling, + const KeyCompare& comp) + : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {} + +template +flat_tree::~flat_tree() = default; + +// ---------------------------------------------------------------------------- +// Assignments. + +template +auto flat_tree::operator=( + const flat_tree&) -> flat_tree& = default; + +template +auto flat_tree::operator=(flat_tree &&) + -> flat_tree& = default; + +template +auto flat_tree::operator=( + std::initializer_list ilist) -> flat_tree& { + impl_.body_ = ilist; + sort_and_unique(begin(), end(), KEEP_FIRST_OF_DUPES); + return *this; +} + +// ---------------------------------------------------------------------------- +// Memory management. + +template +void flat_tree::reserve( + size_type new_capacity) { + impl_.body_.reserve(new_capacity); +} + +template +auto flat_tree::capacity() const + -> size_type { + return impl_.body_.capacity(); +} + +template +void flat_tree::shrink_to_fit() { + impl_.body_.shrink_to_fit(); +} + +// ---------------------------------------------------------------------------- +// Size management. + +template +void flat_tree::clear() { + impl_.body_.clear(); +} + +template +auto flat_tree::size() const + -> size_type { + return impl_.body_.size(); +} + +template +auto flat_tree::max_size() const + -> size_type { + return impl_.body_.max_size(); +} + +template +bool flat_tree::empty() const { + return impl_.body_.empty(); +} + +// ---------------------------------------------------------------------------- +// Iterators. + +template +auto flat_tree::begin() -> iterator { + return impl_.body_.begin(); +} + +template +auto flat_tree::begin() const + -> const_iterator { + return impl_.body_.begin(); +} + +template +auto flat_tree::cbegin() const + -> const_iterator { + return impl_.body_.cbegin(); +} + +template +auto flat_tree::end() -> iterator { + return impl_.body_.end(); +} + +template +auto flat_tree::end() const + -> const_iterator { + return impl_.body_.end(); +} + +template +auto flat_tree::cend() const + -> const_iterator { + return impl_.body_.cend(); +} + +template +auto flat_tree::rbegin() + -> reverse_iterator { + return impl_.body_.rbegin(); +} + +template +auto flat_tree::rbegin() const + -> const_reverse_iterator { + return impl_.body_.rbegin(); +} + +template +auto flat_tree::crbegin() const + -> const_reverse_iterator { + return impl_.body_.crbegin(); +} + +template +auto flat_tree::rend() + -> reverse_iterator { + return impl_.body_.rend(); +} + +template +auto flat_tree::rend() const + -> const_reverse_iterator { + return impl_.body_.rend(); +} + +template +auto flat_tree::crend() const + -> const_reverse_iterator { + return impl_.body_.crend(); +} + +// ---------------------------------------------------------------------------- +// Insert operations. +// +// Currently we use position_hint the same way as eastl or boost: +// https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set.h#L493 + +template +auto flat_tree::insert( + const value_type& val) -> std::pair { + return emplace_key_args(GetKeyFromValue()(val), val); +} + +template +auto flat_tree::insert( + value_type&& val) -> std::pair { + return emplace_key_args(GetKeyFromValue()(val), std::move(val)); +} + +template +auto flat_tree::insert( + const_iterator position_hint, + const value_type& val) -> iterator { + return emplace_hint_key_args(position_hint, GetKeyFromValue()(val), val) + .first; +} + +template +auto flat_tree::insert( + const_iterator position_hint, + value_type&& val) -> iterator { + return emplace_hint_key_args(position_hint, GetKeyFromValue()(val), + std::move(val)) + .first; +} + +template +template +void flat_tree::insert( + InputIterator first, + InputIterator last, + FlatContainerDupes dupes) { + if (first == last) + return; + + // Cache results whether existing elements should be overwritten and whether + // inserting new elements happens immediately or will be done in a batch. + const bool overwrite_existing = dupes == KEEP_LAST_OF_DUPES; + const bool insert_inplace = + is_multipass() && std::next(first) == last; + + if (insert_inplace) { + if (overwrite_existing) { + for (; first != last; ++first) + insert_or_assign(*first); + } else + std::copy(first, last, std::inserter(*this, end())); + return; + } + + // Provide a convenience lambda to obtain an iterator pointing past the last + // old element. This needs to be dymanic due to possible re-allocations. + const size_type original_size = size(); + auto middle = [this, original_size]() { + return std::next(begin(), original_size); + }; + + // For batch updates initialize the first insertion point. + difference_type pos_first_new = original_size; + + // Loop over the input range while appending new values and overwriting + // existing ones, if applicable. Keep track of the first insertion point. + if (overwrite_existing) { + for (; first != last; ++first) { + std::pair result = + append_or_assign(begin(), middle(), *first); + if (result.second) { + pos_first_new = + std::min(pos_first_new, std::distance(begin(), result.first)); + } + } + } else { + for (; first != last; ++first) { + std::pair result = + append_unique(begin(), middle(), *first); + if (result.second) { + pos_first_new = + std::min(pos_first_new, std::distance(begin(), result.first)); + } + } + } + + // The new elements might be unordered and contain duplicates, so post-process + // the just inserted elements and merge them with the rest, inserting them at + // the previously found spot. + sort_and_unique(middle(), end(), dupes); + std::inplace_merge(std::next(begin(), pos_first_new), middle(), end(), + value_comp()); +} + +template +template +auto flat_tree::emplace(Args&&... args) + -> std::pair { + return insert(value_type(std::forward(args)...)); +} + +template +template +auto flat_tree::emplace_hint( + const_iterator position_hint, + Args&&... args) -> iterator { + return insert(position_hint, value_type(std::forward(args)...)); +} + +// ---------------------------------------------------------------------------- +// Erase operations. + +template +auto flat_tree::erase( + iterator position) -> iterator { + return impl_.body_.erase(position); +} + +template +auto flat_tree::erase( + const_iterator position) -> iterator { + return impl_.body_.erase(position); +} + +template +template +auto flat_tree::erase(const K& val) + -> size_type { + auto eq_range = equal_range(val); + auto res = std::distance(eq_range.first, eq_range.second); + erase(eq_range.first, eq_range.second); + return res; +} + +template +auto flat_tree::erase( + const_iterator first, + const_iterator last) -> iterator { + return impl_.body_.erase(first, last); +} + +// ---------------------------------------------------------------------------- +// Comparators. + +template +auto flat_tree::key_comp() const + -> key_compare { + return impl_.get_key_comp(); +} + +template +auto flat_tree::value_comp() const + -> value_compare { + return impl_.get_value_comp(); +} + +// ---------------------------------------------------------------------------- +// Search operations. + +template +template +auto flat_tree::count( + const K& key) const -> size_type { + auto eq_range = equal_range(key); + return std::distance(eq_range.first, eq_range.second); +} + +template +template +auto flat_tree::find(const K& key) + -> iterator { + return const_cast_it(as_const().find(key)); +} + +template +template +auto flat_tree::find( + const K& key) const -> const_iterator { + auto eq_range = equal_range(key); + return (eq_range.first == eq_range.second) ? end() : eq_range.first; +} + +template +template +auto flat_tree::equal_range( + const K& key) -> std::pair { + auto res = as_const().equal_range(key); + return {const_cast_it(res.first), const_cast_it(res.second)}; +} + +template +template +auto flat_tree::equal_range( + const K& key) const -> std::pair { + auto lower = lower_bound(key); + + GetKeyFromValue extractor; + if (lower == end() || impl_.get_key_comp()(key, extractor(*lower))) + return {lower, lower}; + + return {lower, std::next(lower)}; +} + +template +template +auto flat_tree::lower_bound( + const K& key) -> iterator { + return const_cast_it(as_const().lower_bound(key)); +} + +template +template +auto flat_tree::lower_bound( + const K& key) const -> const_iterator { + static_assert(std::is_convertible&, const K&>::value, + "Requested type cannot be bound to the container's key_type " + "which is required for a non-transparent compare."); + + const KeyTypeOrK& key_ref = key; + + KeyValueCompare key_value(impl_.get_key_comp()); + return std::lower_bound(begin(), end(), key_ref, key_value); +} + +template +template +auto flat_tree::upper_bound( + const K& key) -> iterator { + return const_cast_it(as_const().upper_bound(key)); +} + +template +template +auto flat_tree::upper_bound( + const K& key) const -> const_iterator { + static_assert(std::is_convertible&, const K&>::value, + "Requested type cannot be bound to the container's key_type " + "which is required for a non-transparent compare."); + + const KeyTypeOrK& key_ref = key; + + KeyValueCompare key_value(impl_.get_key_comp()); + return std::upper_bound(begin(), end(), key_ref, key_value); +} + +// ---------------------------------------------------------------------------- +// General operations. + +template +void flat_tree::swap( + flat_tree& other) noexcept { + std::swap(impl_, other.impl_); +} + +template +template +auto flat_tree::unsafe_emplace( + const_iterator position, + Args&&... args) -> iterator { + return impl_.body_.emplace(position, std::forward(args)...); +} + +template +template +auto flat_tree::emplace_key_args( + const K& key, + Args&&... args) -> std::pair { + auto lower = lower_bound(key); + if (lower == end() || key_comp()(key, GetKeyFromValue()(*lower))) + return {unsafe_emplace(lower, std::forward(args)...), true}; + return {lower, false}; +} + +template +template +auto flat_tree::emplace_hint_key_args( + const_iterator hint, + const K& key, + Args&&... args) -> std::pair { + GetKeyFromValue extractor; + if ((hint == begin() || key_comp()(extractor(*std::prev(hint)), key))) { + if (hint == end() || key_comp()(key, extractor(*hint))) { + // *(hint - 1) < key < *hint => key did not exist and hint is correct. + return {unsafe_emplace(hint, std::forward(args)...), true}; + } + if (!key_comp()(extractor(*hint), key)) { + // key == *hint => no-op, return correct hint. + return {const_cast_it(hint), false}; + } + } + // hint was not helpful, dispatch to hintless version. + return emplace_key_args(key, std::forward(args)...); +} + +// For containers like sets, the key is the same as the value. This implements +// the GetKeyFromValue template parameter to flat_tree for this case. +template +struct GetKeyFromValueIdentity { + const Key& operator()(const Key& k) const { return k; } +}; + +} // namespace internal + +// ---------------------------------------------------------------------------- +// Free functions. + +// Erases all elements that match predicate. It has O(size) complexity. +template +void EraseIf(base::internal::flat_tree& + container, + Predicate pred) { + container.erase(std::remove_if(container.begin(), container.end(), pred), + container.end()); +} + +} // namespace base + +#endif // BASE_CONTAINERS_FLAT_TREE_H_ diff --git a/src/3rdparty/gn/base/containers/queue.h b/src/3rdparty/gn/base/containers/queue.h new file mode 100644 index 00000000000..2d3b480089f --- /dev/null +++ b/src/3rdparty/gn/base/containers/queue.h @@ -0,0 +1,23 @@ +// Copyright 2017 The Chromium 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_CONTAINERS_QUEUE_H_ +#define BASE_CONTAINERS_QUEUE_H_ + +#include + +#include "base/containers/circular_deque.h" + +namespace base { + +// Provides a definition of base::queue that's like std::queue but uses a +// base::circular_queue instead of std::deque. Since std::queue is just a +// wrapper for an underlying type, we can just provide a typedef for it that +// defaults to the base circular_deque. +template > +using queue = std::queue; + +} // namespace base + +#endif // BASE_CONTAINERS_QUEUE_H_ diff --git a/src/3rdparty/gn/base/containers/span.h b/src/3rdparty/gn/base/containers/span.h new file mode 100644 index 00000000000..c9718619bcc --- /dev/null +++ b/src/3rdparty/gn/base/containers/span.h @@ -0,0 +1,453 @@ +// Copyright 2017 The Chromium 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_CONTAINERS_SPAN_H_ +#define BASE_CONTAINERS_SPAN_H_ + +#include + +#include +#include +#include +#include +#include + +#include "base/logging.h" +#include "base/stl_util.h" + +namespace base { + +// [views.constants] +constexpr size_t dynamic_extent = static_cast(-1); + +template +class span; + +namespace internal { + +template +struct IsSpanImpl : std::false_type {}; + +template +struct IsSpanImpl> : std::true_type {}; + +template +using IsSpan = IsSpanImpl>; + +template +struct IsStdArrayImpl : std::false_type {}; + +template +struct IsStdArrayImpl> : std::true_type {}; + +template +using IsStdArray = IsStdArrayImpl>; + +template +using IsCArray = std::is_array>; + +template +using IsLegalDataConversion = std::is_convertible; + +template +using ContainerHasConvertibleData = IsLegalDataConversion< + std::remove_pointer_t()))>, + T>; + +template +using ContainerHasIntegralSize = + std::is_integral()))>; + +template +using EnableIfLegalSpanConversion = + std::enable_if_t<(ToExtent == dynamic_extent || ToExtent == FromExtent) && + IsLegalDataConversion::value>; + +// SFINAE check if Array can be converted to a span. +template +using EnableIfSpanCompatibleArray = + std::enable_if_t<(Extent == dynamic_extent || Extent == N) && + ContainerHasConvertibleData::value>; + +// SFINAE check if Container can be converted to a span. +template +using EnableIfSpanCompatibleContainer = + std::enable_if_t::value && + !internal::IsStdArray::value && + !internal::IsCArray::value && + ContainerHasConvertibleData::value && + ContainerHasIntegralSize::value>; + +} // namespace internal + +// A span is a value type that represents an array of elements of type T. Since +// it only consists of a pointer to memory with an associated size, it is very +// light-weight. It is cheap to construct, copy, move and use spans, so that +// users are encouraged to use it as a pass-by-value parameter. A span does not +// own the underlying memory, so care must be taken to ensure that a span does +// not outlive the backing store. +// +// span is somewhat analogous to StringPiece, but with arbitrary element types, +// allowing mutation if T is non-const. +// +// span is implicitly convertible from C++ arrays, as well as most [1] +// container-like types that provide a data() and size() method (such as +// std::vector). A mutable span can also be implicitly converted to an +// immutable span. +// +// Consider using a span for functions that take a data pointer and size +// parameter: it allows the function to still act on an array-like type, while +// allowing the caller code to be a bit more concise. +// +// For read-only data access pass a span: the caller can supply either +// a span or a span, while the callee will have a read-only view. +// For read-write access a mutable span is required. +// +// Without span: +// Read-Only: +// // std::string HexEncode(const uint8_t* data, size_t size); +// std::vector data_buffer = GenerateData(); +// std::string r = HexEncode(data_buffer.data(), data_buffer.size()); +// +// Mutable: +// // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...); +// char str_buffer[100]; +// SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14); +// +// With span: +// Read-Only: +// // std::string HexEncode(base::span data); +// std::vector data_buffer = GenerateData(); +// std::string r = HexEncode(data_buffer); +// +// Mutable: +// // ssize_t SafeSNPrintf(base::span, const char* fmt, Args...); +// char str_buffer[100]; +// SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14); +// +// Spans with "const" and pointers +// ------------------------------- +// +// Const and pointers can get confusing. Here are vectors of pointers and their +// corresponding spans: +// +// const std::vector => base::span +// std::vector => base::span +// const std::vector => base::span +// +// Differences from the working group proposal +// ------------------------------------------- +// +// https://wg21.link/P0122 is the latest working group proposal, Chromium +// currently implements R7. Differences between the proposal and the +// implementation are documented in subsections below. +// +// Differences from [span.objectrep]: +// - as_bytes() and as_writable_bytes() return spans of uint8_t instead of +// std::byte +// +// Differences in constants and types: +// - index_type is aliased to size_t +// +// Differences from [span.sub]: +// - using size_t instead of ptrdiff_t for indexing +// +// Differences from [span.obs]: +// - using size_t instead of ptrdiff_t to represent size() +// +// Differences from [span.elem]: +// - using size_t instead of ptrdiff_t for indexing +// +// Furthermore, all constructors and methods are marked noexcept due to the lack +// of exceptions in Chromium. +// +// Due to the lack of class template argument deduction guides in C++14 +// appropriate make_span() utility functions are provided. + +// [span], class template span +template +class span { + public: + using element_type = T; + using value_type = std::remove_cv_t; + using index_type = size_t; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; + using iterator = T*; + using const_iterator = const T*; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + static constexpr index_type extent = Extent; + + // [span.cons], span constructors, copy, assignment, and destructor + constexpr span() noexcept : data_(nullptr), size_(0) { + static_assert(Extent == dynamic_extent || Extent == 0, "Invalid Extent"); + } + + constexpr span(T* data, size_t size) noexcept : data_(data), size_(size) { + CHECK(Extent == dynamic_extent || Extent == size); + } + + // Artificially templatized to break ambiguity for span(ptr, 0). + template + constexpr span(T* begin, T* end) noexcept : span(begin, end - begin) { + // Note: CHECK_LE is not constexpr, hence regular CHECK must be used. + CHECK(begin <= end); + } + + template < + size_t N, + typename = internal::EnableIfSpanCompatibleArray> + constexpr span(T (&array)[N]) noexcept : span(base::data(array), N) {} + + template < + size_t N, + typename = internal:: + EnableIfSpanCompatibleArray&, N, T, Extent>> + constexpr span(std::array& array) noexcept + : span(base::data(array), N) {} + + template &, + N, + T, + Extent>> + constexpr span(const std::array& array) noexcept + : span(base::data(array), N) {} + + // Conversion from a container that has compatible base::data() and integral + // base::size(). + template > + constexpr span(Container& container) noexcept + : span(base::data(container), base::size(container)) {} + + template < + typename Container, + typename = internal::EnableIfSpanCompatibleContainer> + span(const Container& container) noexcept + : span(base::data(container), base::size(container)) {} + + constexpr span(const span& other) noexcept = default; + + // Conversions from spans of compatible types and extents: this allows a + // span to be seamlessly used as a span, but not the other way + // around. If extent is not dynamic, OtherExtent has to be equal to Extent. + template < + typename U, + size_t OtherExtent, + typename = + internal::EnableIfLegalSpanConversion> + constexpr span(const span& other) + : span(other.data(), other.size()) {} + + constexpr span& operator=(const span& other) noexcept = default; + ~span() noexcept = default; + + // [span.sub], span subviews + template + constexpr span first() const noexcept { + static_assert(Extent == dynamic_extent || Count <= Extent, + "Count must not exceed Extent"); + CHECK(Extent != dynamic_extent || Count <= size()); + return {data(), Count}; + } + + template + constexpr span last() const noexcept { + static_assert(Extent == dynamic_extent || Count <= Extent, + "Count must not exceed Extent"); + CHECK(Extent != dynamic_extent || Count <= size()); + return {data() + (size() - Count), Count}; + } + + template + constexpr span + subspan() const noexcept { + static_assert(Extent == dynamic_extent || Offset <= Extent, + "Offset must not exceed Extent"); + static_assert(Extent == dynamic_extent || Count == dynamic_extent || + Count <= Extent - Offset, + "Count must not exceed Extent - Offset"); + CHECK(Extent != dynamic_extent || Offset <= size()); + CHECK(Extent != dynamic_extent || Count == dynamic_extent || + Count <= size() - Offset); + return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset}; + } + + constexpr span first(size_t count) const noexcept { + // Note: CHECK_LE is not constexpr, hence regular CHECK must be used. + CHECK(count <= size()); + return {data(), count}; + } + + constexpr span last(size_t count) const noexcept { + // Note: CHECK_LE is not constexpr, hence regular CHECK must be used. + CHECK(count <= size()); + return {data() + (size() - count), count}; + } + + constexpr span subspan(size_t offset, + size_t count = dynamic_extent) const + noexcept { + // Note: CHECK_LE is not constexpr, hence regular CHECK must be used. + CHECK(offset <= size()); + CHECK(count == dynamic_extent || count <= size() - offset); + return {data() + offset, count != dynamic_extent ? count : size() - offset}; + } + + // [span.obs], span observers + constexpr size_t size() const noexcept { return size_; } + constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); } + constexpr bool empty() const noexcept { return size() == 0; } + + // [span.elem], span element access + constexpr T& operator[](size_t idx) const noexcept { + // Note: CHECK_LT is not constexpr, hence regular CHECK must be used. + CHECK(idx < size()); + return *(data() + idx); + } + + constexpr T& operator()(size_t idx) const noexcept { + // Note: CHECK_LT is not constexpr, hence regular CHECK must be used. + CHECK(idx < size()); + return *(data() + idx); + } + + constexpr T* data() const noexcept { return data_; } + + // [span.iter], span iterator support + constexpr iterator begin() const noexcept { return data(); } + constexpr iterator end() const noexcept { return data() + size(); } + + constexpr const_iterator cbegin() const noexcept { return begin(); } + constexpr const_iterator cend() const noexcept { return end(); } + + constexpr reverse_iterator rbegin() const noexcept { + return reverse_iterator(end()); + } + constexpr reverse_iterator rend() const noexcept { + return reverse_iterator(begin()); + } + + constexpr const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator(cend()); + } + constexpr const_reverse_iterator crend() const noexcept { + return const_reverse_iterator(cbegin()); + } + + private: + T* data_; + size_t size_; +}; + +// span::extent can not be declared inline prior to C++17, hence this +// definition is required. +template +constexpr size_t span::extent; + +// [span.comparison], span comparison operators +// Relational operators. Equality is a element-wise comparison. +template +constexpr bool operator==(span lhs, span rhs) noexcept { + return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()); +} + +template +constexpr bool operator!=(span lhs, span rhs) noexcept { + return !(lhs == rhs); +} + +template +constexpr bool operator<(span lhs, span rhs) noexcept { + return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), + rhs.cend()); +} + +template +constexpr bool operator<=(span lhs, span rhs) noexcept { + return !(rhs < lhs); +} + +template +constexpr bool operator>(span lhs, span rhs) noexcept { + return rhs < lhs; +} + +template +constexpr bool operator>=(span lhs, span rhs) noexcept { + return !(lhs < rhs); +} + +// [span.objectrep], views of object representation +template +span +as_bytes(span s) noexcept { + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +template ::value>> +span +as_writable_bytes(span s) noexcept { + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +// Type-deducing helpers for constructing a span. +template +constexpr span make_span(T* data, size_t size) noexcept { + return {data, size}; +} + +template +constexpr span make_span(T* begin, T* end) noexcept { + return {begin, end}; +} + +template +constexpr span make_span(T (&array)[N]) noexcept { + return array; +} + +template +constexpr span make_span(std::array& array) noexcept { + return array; +} + +template +constexpr span make_span(const std::array& array) noexcept { + return array; +} + +template > +constexpr span make_span(Container& container) noexcept { + return container; +} + +template < + typename Container, + typename T = const typename Container::value_type, + typename = internal::EnableIfSpanCompatibleContainer> +constexpr span make_span(const Container& container) noexcept { + return container; +} + +template +constexpr span make_span(const span& span) noexcept { + return span; +} + +} // namespace base + +#endif // BASE_CONTAINERS_SPAN_H_ diff --git a/src/3rdparty/gn/base/containers/stack.h b/src/3rdparty/gn/base/containers/stack.h new file mode 100644 index 00000000000..1aaa8793c7c --- /dev/null +++ b/src/3rdparty/gn/base/containers/stack.h @@ -0,0 +1,23 @@ +// Copyright 2017 The Chromium 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_CONTAINERS_STACK_H_ +#define BASE_CONTAINERS_STACK_H_ + +#include + +#include "base/containers/circular_deque.h" + +namespace base { + +// Provides a definition of base::stack that's like std::stack but uses a +// base::circular_queue instead of std::deque. Since std::stack is just a +// wrapper for an underlying type, we can just provide a typedef for it that +// defaults to the base circular_deque. +template > +using stack = std::stack; + +} // namespace base + +#endif // BASE_CONTAINERS_STACK_H_ diff --git a/src/3rdparty/gn/base/containers/vector_buffer.h b/src/3rdparty/gn/base/containers/vector_buffer.h new file mode 100644 index 00000000000..a72c1ed95e8 --- /dev/null +++ b/src/3rdparty/gn/base/containers/vector_buffer.h @@ -0,0 +1,163 @@ +// Copyright 2017 The Chromium 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_CONTAINERS_VECTOR_BUFFERS_H_ +#define BASE_CONTAINERS_VECTOR_BUFFERS_H_ + +#include +#include + +#include +#include + +#include "base/logging.h" +#include "base/macros.h" + +namespace base { +namespace internal { + +// Internal implementation detail of base/containers. +// +// Implements a vector-like buffer that holds a certain capacity of T. Unlike +// std::vector, VectorBuffer never constructs or destructs its arguments, and +// can't change sizes. But it does implement templates to assist in efficient +// moving and destruction of those items manually. +// +// In particular, the destructor function does not iterate over the items if +// there is no destructor. Moves should be implemented as a memcpy/memmove for +// trivially copyable objects (POD) otherwise, it should be a std::move if +// possible, and as a last resort it falls back to a copy. This behavior is +// similar to std::vector. +// +// No special consideration is done for noexcept move constructors since +// we compile without exceptions. +// +// The current API does not support moving overlapping ranges. +template +class VectorBuffer { + public: + constexpr VectorBuffer() = default; + +#if defined(__clang__) && !defined(__native_client__) + // This constructor converts an uninitialized void* to a T* which triggers + // clang Control Flow Integrity. Since this is as-designed, disable. + __attribute__((no_sanitize("cfi-unrelated-cast", "vptr"))) +#endif + VectorBuffer(size_t count) + : buffer_(reinterpret_cast(malloc(sizeof(T) * count))), + capacity_(count) { + } + VectorBuffer(VectorBuffer&& other) noexcept + : buffer_(other.buffer_), capacity_(other.capacity_) { + other.buffer_ = nullptr; + other.capacity_ = 0; + } + + ~VectorBuffer() { free(buffer_); } + + VectorBuffer& operator=(VectorBuffer&& other) { + free(buffer_); + buffer_ = other.buffer_; + capacity_ = other.capacity_; + + other.buffer_ = nullptr; + other.capacity_ = 0; + return *this; + } + + size_t capacity() const { return capacity_; } + + T& operator[](size_t i) { return buffer_[i]; } + const T& operator[](size_t i) const { return buffer_[i]; } + T* begin() { return buffer_; } + T* end() { return &buffer_[capacity_]; } + + // DestructRange ------------------------------------------------------------ + + // Trivially destructible objects need not have their destructors called. + template ::value, + int>::type = 0> + void DestructRange(T* begin, T* end) {} + + // Non-trivially destructible objects must have their destructors called + // individually. + template ::value, + int>::type = 0> + void DestructRange(T* begin, T* end) { + while (begin != end) { + begin->~T(); + begin++; + } + } + + // MoveRange ---------------------------------------------------------------- + // + // The destructor will be called (as necessary) for all moved types. The + // ranges must not overlap. + // + // The parameters and begin and end (one past the last) of the input buffer, + // and the address of the first element to copy to. There must be sufficient + // room in the destination for all items in the range [begin, end). + + // Trivially copyable types can use memcpy. trivially copyable implies + // that there is a trivial destructor as we don't have to call it. + template ::value, + int>::type = 0> + static void MoveRange(T* from_begin, T* from_end, T* to) { + DCHECK(!RangesOverlap(from_begin, from_end, to)); + memcpy(to, from_begin, (from_end - from_begin) * sizeof(T)); + } + + // Not trivially copyable, but movable: call the move constructor and + // destruct the original. + template ::value && + !base::is_trivially_copyable::value, + int>::type = 0> + static void MoveRange(T* from_begin, T* from_end, T* to) { + DCHECK(!RangesOverlap(from_begin, from_end, to)); + while (from_begin != from_end) { + new (to) T(std::move(*from_begin)); + from_begin->~T(); + from_begin++; + to++; + } + } + + // Not movable, not trivially copyable: call the copy constructor and + // destruct the original. + template ::value && + !base::is_trivially_copyable::value, + int>::type = 0> + static void MoveRange(T* from_begin, T* from_end, T* to) { + DCHECK(!RangesOverlap(from_begin, from_end, to)); + while (from_begin != from_end) { + new (to) T(*from_begin); + from_begin->~T(); + from_begin++; + to++; + } + } + + private: + static bool RangesOverlap(const T* from_begin, + const T* from_end, + const T* to) { + return !(to >= from_end || to + (from_end - from_begin) <= from_begin); + } + + T* buffer_ = nullptr; + size_t capacity_ = 0; + + DISALLOW_COPY_AND_ASSIGN(VectorBuffer); +}; + +} // namespace internal +} // namespace base + +#endif // BASE_CONTAINERS_VECTOR_BUFFERS_H_ diff --git a/src/3rdparty/gn/base/environment.cc b/src/3rdparty/gn/base/environment.cc new file mode 100644 index 00000000000..7f0e5d9d5d1 --- /dev/null +++ b/src/3rdparty/gn/base/environment.cc @@ -0,0 +1,237 @@ +// 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/environment.h" + +#include + +#include + +#include "base/memory/ptr_util.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "util/build_config.h" + +#if defined(OS_WIN) +#include +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +#include +#endif + +namespace base { + +namespace { + +class EnvironmentImpl : public Environment { + public: + bool GetVar(StringPiece variable_name, std::string* result) override { + if (GetVarImpl(variable_name, result)) + return true; + + // Some commonly used variable names are uppercase while others + // are lowercase, which is inconsistent. Let's try to be helpful + // and look for a variable name with the reverse case. + // I.e. HTTP_PROXY may be http_proxy for some users/systems. + char first_char = variable_name[0]; + std::string alternate_case_var; + if (IsAsciiLower(first_char)) + alternate_case_var = ToUpperASCII(variable_name); + else if (IsAsciiUpper(first_char)) + alternate_case_var = ToLowerASCII(variable_name); + else + return false; + return GetVarImpl(alternate_case_var, result); + } + + bool SetVar(StringPiece variable_name, + const std::string& new_value) override { + return SetVarImpl(variable_name, new_value); + } + + bool UnSetVar(StringPiece variable_name) override { + return UnSetVarImpl(variable_name); + } + + private: + bool GetVarImpl(StringPiece variable_name, std::string* result) { +#if defined(OS_WIN) + DWORD value_length = + ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), nullptr, 0); + if (value_length == 0) + return false; + if (result) { + std::unique_ptr value(new wchar_t[value_length]); + ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), value.get(), + value_length); + *result = WideToUTF8(value.get()); + } + return true; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + const char* env_value = getenv(variable_name.data()); + if (!env_value) + return false; + // Note that the variable may be defined but empty. + if (result) + *result = env_value; + return true; +#endif + } + + bool SetVarImpl(StringPiece variable_name, const std::string& new_value) { +#if defined(OS_WIN) + // On success, a nonzero value is returned. + return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), + UTF8ToWide(new_value).c_str()); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + // On success, zero is returned. + return !setenv(variable_name.data(), new_value.c_str(), 1); +#endif + } + + bool UnSetVarImpl(StringPiece variable_name) { +#if defined(OS_WIN) + // On success, a nonzero value is returned. + return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), nullptr); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + // On success, zero is returned. + return !unsetenv(variable_name.data()); +#endif + } +}; + +// Parses a null-terminated input string of an environment block. The key is +// placed into the given string, and the total length of the line, including +// the terminating null, is returned. +size_t ParseEnvLine(const NativeEnvironmentString::value_type* input, + NativeEnvironmentString* key) { + // Skip to the equals or end of the string, this is the key. + size_t cur = 0; + while (input[cur] && input[cur] != '=') + cur++; + *key = NativeEnvironmentString(&input[0], cur); + + // Now just skip to the end of the string. + while (input[cur]) + cur++; + return cur + 1; +} + +} // namespace + +namespace env_vars { + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +// On Posix systems, this variable contains the location of the user's home +// directory. (e.g, /home/username/). +const char kHome[] = "HOME"; +#endif + +} // namespace env_vars + +Environment::~Environment() = default; + +// static +std::unique_ptr Environment::Create() { + return std::make_unique(); +} + +bool Environment::HasVar(StringPiece variable_name) { + return GetVar(variable_name, nullptr); +} + +#if defined(OS_WIN) + +string16 AlterEnvironment(const wchar_t* env, const EnvironmentMap& changes) { + string16 result; + + // First copy all unmodified values to the output. + size_t cur_env = 0; + string16 key; + while (env[cur_env]) { + const wchar_t* line = &env[cur_env]; + size_t line_length = ParseEnvLine(line, &key); + + // Keep only values not specified in the change vector. + EnvironmentMap::const_iterator found_change = changes.find(key); + if (found_change == changes.end()) + result.append(line, line_length); + + cur_env += line_length; + } + + // Now append all modified and new values. + for (EnvironmentMap::const_iterator i = changes.begin(); i != changes.end(); + ++i) { + if (!i->second.empty()) { + result.append(i->first); + result.push_back('='); + result.append(i->second); + result.push_back(0); + } + } + + // An additional null marks the end of the list. We always need a double-null + // in case nothing was added above. + if (result.empty()) + result.push_back(0); + result.push_back(0); + return result; +} + +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + +std::unique_ptr AlterEnvironment(const char* const* const env, + const EnvironmentMap& changes) { + std::string value_storage; // Holds concatenated null-terminated strings. + std::vector result_indices; // Line indices into value_storage. + + // First build up all of the unchanged environment strings. These are + // null-terminated of the form "key=value". + std::string key; + for (size_t i = 0; env[i]; i++) { + size_t line_length = ParseEnvLine(env[i], &key); + + // Keep only values not specified in the change vector. + EnvironmentMap::const_iterator found_change = changes.find(key); + if (found_change == changes.end()) { + result_indices.push_back(value_storage.size()); + value_storage.append(env[i], line_length); + } + } + + // Now append all modified and new values. + for (EnvironmentMap::const_iterator i = changes.begin(); i != changes.end(); + ++i) { + if (!i->second.empty()) { + result_indices.push_back(value_storage.size()); + value_storage.append(i->first); + value_storage.push_back('='); + value_storage.append(i->second); + value_storage.push_back(0); + } + } + + size_t pointer_count_required = + result_indices.size() + 1 + // Null-terminated array of pointers. + (value_storage.size() + sizeof(char*) - 1) / sizeof(char*); // Buffer. + std::unique_ptr result(new char*[pointer_count_required]); + + // The string storage goes after the array of pointers. + char* storage_data = + reinterpret_cast(&result.get()[result_indices.size() + 1]); + if (!value_storage.empty()) + memcpy(storage_data, value_storage.data(), value_storage.size()); + + // Fill array of pointers at the beginning of the result. + for (size_t i = 0; i < result_indices.size(); i++) + result[i] = &storage_data[result_indices[i]]; + result[result_indices.size()] = 0; // Null terminator. + + return result; +} + +#endif // OS_WIN + +} // namespace base diff --git a/src/3rdparty/gn/base/environment.h b/src/3rdparty/gn/base/environment.h new file mode 100644 index 00000000000..82af9878dac --- /dev/null +++ b/src/3rdparty/gn/base/environment.h @@ -0,0 +1,86 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ENVIRONMENT_H_ +#define BASE_ENVIRONMENT_H_ + +#include +#include +#include + +#include "base/strings/string16.h" +#include "base/strings/string_piece.h" +#include "util/build_config.h" + +namespace base { + +namespace env_vars { + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +extern const char kHome[]; +#endif + +} // namespace env_vars + +class Environment { + public: + virtual ~Environment(); + + // Returns the appropriate platform-specific instance. + static std::unique_ptr Create(); + + // Gets an environment variable's value and stores it in |result|. + // Returns false if the key is unset. + virtual bool GetVar(StringPiece variable_name, std::string* result) = 0; + + // Syntactic sugar for GetVar(variable_name, nullptr); + virtual bool HasVar(StringPiece variable_name); + + // Returns true on success, otherwise returns false. + virtual bool SetVar(StringPiece variable_name, + const std::string& new_value) = 0; + + // Returns true on success, otherwise returns false. + virtual bool UnSetVar(StringPiece variable_name) = 0; +}; + +#if defined(OS_WIN) + +typedef string16 NativeEnvironmentString; +typedef std::map + EnvironmentMap; + +// Returns a modified environment vector constructed from the given environment +// and the list of changes given in |changes|. Each key in the environment is +// matched against the first element of the pairs. In the event of a match, the +// value is replaced by the second of the pair, unless the second is empty, in +// which case the key-value is removed. +// +// This Windows version takes and returns a Windows-style environment block +// which is a concatenated list of null-terminated 16-bit strings. The end is +// marked by a double-null terminator. The size of the returned string will +// include the terminators. +string16 AlterEnvironment(const wchar_t* env, const EnvironmentMap& changes); + +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + +typedef std::string NativeEnvironmentString; +typedef std::map + EnvironmentMap; + +// See general comments for the Windows version above. +// +// This Posix version takes and returns a Posix-style environment block, which +// is a null-terminated list of pointers to null-terminated strings. The +// returned array will have appended to it the storage for the array itself so +// there is only one pointer to manage, but this means that you can't copy the +// array without keeping the original around. +std::unique_ptr AlterEnvironment(const char* const* env, + const EnvironmentMap& changes); + +#endif + +} // namespace base + +#endif // BASE_ENVIRONMENT_H_ diff --git a/src/3rdparty/gn/base/files/file.cc b/src/3rdparty/gn/base/files/file.cc new file mode 100644 index 00000000000..98fa3a6597c --- /dev/null +++ b/src/3rdparty/gn/base/files/file.cc @@ -0,0 +1,132 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "util/build_config.h" + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +#include +#endif + +namespace base { + +File::Info::Info() : size(0), is_directory(false), is_symbolic_link(false) {} + +File::Info::~Info() = default; + +File::File() + : error_details_(FILE_ERROR_FAILED), created_(false), async_(false) {} + +#if !defined(OS_NACL) +File::File(const FilePath& path, uint32_t flags) + : error_details_(FILE_OK), created_(false), async_(false) { + Initialize(path, flags); +} +#endif + +File::File(PlatformFile platform_file) + : file_(platform_file), + error_details_(FILE_OK), + created_(false), + async_(false) { +#if defined(OS_POSIX) || defined(OS_FUCHSIA) + DCHECK_GE(platform_file, -1); +#endif +} + +File::File(Error error_details) + : error_details_(error_details), created_(false), async_(false) {} + +File::File(File&& other) + : file_(other.TakePlatformFile()), + error_details_(other.error_details()), + created_(other.created()), + async_(other.async_) {} + +File::~File() { + // Go through the AssertIOAllowed logic. + Close(); +} + +// static +File File::CreateForAsyncHandle(PlatformFile platform_file) { + File file(platform_file); + // It would be nice if we could validate that |platform_file| was opened with + // FILE_FLAG_OVERLAPPED on Windows but this doesn't appear to be possible. + file.async_ = true; + return file; +} + +File& File::operator=(File&& other) { + Close(); + SetPlatformFile(other.TakePlatformFile()); + error_details_ = other.error_details(); + created_ = other.created(); + async_ = other.async_; + return *this; +} + +#if !defined(OS_NACL) +void File::Initialize(const FilePath& path, uint32_t flags) { + if (path.ReferencesParent()) { +#if defined(OS_WIN) + ::SetLastError(ERROR_ACCESS_DENIED); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + errno = EACCES; +#else +#error Unsupported platform +#endif + error_details_ = FILE_ERROR_ACCESS_DENIED; + return; + } + DoInitialize(path, flags); +} +#endif + +std::string File::ErrorToString(Error error) { + switch (error) { + case FILE_OK: + return "FILE_OK"; + case FILE_ERROR_FAILED: + return "FILE_ERROR_FAILED"; + case FILE_ERROR_IN_USE: + return "FILE_ERROR_IN_USE"; + case FILE_ERROR_EXISTS: + return "FILE_ERROR_EXISTS"; + case FILE_ERROR_NOT_FOUND: + return "FILE_ERROR_NOT_FOUND"; + case FILE_ERROR_ACCESS_DENIED: + return "FILE_ERROR_ACCESS_DENIED"; + case FILE_ERROR_TOO_MANY_OPENED: + return "FILE_ERROR_TOO_MANY_OPENED"; + case FILE_ERROR_NO_MEMORY: + return "FILE_ERROR_NO_MEMORY"; + case FILE_ERROR_NO_SPACE: + return "FILE_ERROR_NO_SPACE"; + case FILE_ERROR_NOT_A_DIRECTORY: + return "FILE_ERROR_NOT_A_DIRECTORY"; + case FILE_ERROR_INVALID_OPERATION: + return "FILE_ERROR_INVALID_OPERATION"; + case FILE_ERROR_SECURITY: + return "FILE_ERROR_SECURITY"; + case FILE_ERROR_ABORT: + return "FILE_ERROR_ABORT"; + case FILE_ERROR_NOT_A_FILE: + return "FILE_ERROR_NOT_A_FILE"; + case FILE_ERROR_NOT_EMPTY: + return "FILE_ERROR_NOT_EMPTY"; + case FILE_ERROR_INVALID_URL: + return "FILE_ERROR_INVALID_URL"; + case FILE_ERROR_IO: + return "FILE_ERROR_IO"; + case FILE_ERROR_MAX: + break; + } + + NOTREACHED(); + return ""; +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file.h b/src/3rdparty/gn/base/files/file.h new file mode 100644 index 00000000000..61239adb8e7 --- /dev/null +++ b/src/3rdparty/gn/base/files/file.h @@ -0,0 +1,356 @@ +// 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_FILES_FILE_H_ +#define BASE_FILES_FILE_H_ + +#include + +#include + +#include "base/files/file_path.h" +#include "base/files/platform_file.h" +#include "base/files/scoped_file.h" +#include "base/macros.h" +#include "util/build_config.h" +#include "util/ticks.h" + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +#include +#endif + +namespace base { + +#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) || \ + defined(OS_ANDROID) && __ANDROID_API__ < 21 +typedef struct stat stat_wrapper_t; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +typedef struct stat64 stat_wrapper_t; +#endif + +// Thin wrapper around an OS-level file. +// Note that this class does not provide any support for asynchronous IO, other +// than the ability to create asynchronous handles on Windows. +// +// Note about const: this class does not attempt to determine if the underlying +// file system object is affected by a particular method in order to consider +// that method const or not. Only methods that deal with member variables in an +// obvious non-modifying way are marked as const. Any method that forward calls +// to the OS is not considered const, even if there is no apparent change to +// member variables. +class File { + public: + // FLAG_(OPEN|CREATE).* are mutually exclusive. You should specify exactly one + // of the five (possibly combining with other flags) when opening or creating + // a file. + // FLAG_(WRITE|APPEND) are mutually exclusive. This is so that APPEND behavior + // will be consistent with O_APPEND on POSIX. + // FLAG_EXCLUSIVE_(READ|WRITE) only grant exclusive access to the file on + // creation on POSIX; for existing files, consider using Lock(). + enum Flags { + FLAG_OPEN = 1 << 0, // Opens a file, only if it exists. + FLAG_CREATE = 1 << 1, // Creates a new file, only if it does not + // already exist. + FLAG_OPEN_ALWAYS = 1 << 2, // May create a new file. + FLAG_CREATE_ALWAYS = 1 << 3, // May overwrite an old file. + FLAG_OPEN_TRUNCATED = 1 << 4, // Opens a file and truncates it, only if it + // exists. + FLAG_READ = 1 << 5, + FLAG_WRITE = 1 << 6, + FLAG_APPEND = 1 << 7, + FLAG_EXCLUSIVE_READ = 1 << 8, // EXCLUSIVE is opposite of Windows SHARE. + FLAG_EXCLUSIVE_WRITE = 1 << 9, + FLAG_ASYNC = 1 << 10, + FLAG_TEMPORARY = 1 << 11, // Used on Windows only. + FLAG_HIDDEN = 1 << 12, // Used on Windows only. + FLAG_DELETE_ON_CLOSE = 1 << 13, + FLAG_WRITE_ATTRIBUTES = 1 << 14, // Used on Windows only. + FLAG_SHARE_DELETE = 1 << 15, // Used on Windows only. + FLAG_TERMINAL_DEVICE = 1 << 16, // Serial port flags. + FLAG_BACKUP_SEMANTICS = 1 << 17, // Used on Windows only. + FLAG_EXECUTE = 1 << 18, // Used on Windows only. + FLAG_SEQUENTIAL_SCAN = 1 << 19, // Used on Windows only. + FLAG_CAN_DELETE_ON_CLOSE = 1 << 20, // Requests permission to delete a file + // via DeleteOnClose() (Windows only). + // See DeleteOnClose() for details. + }; + + // This enum has been recorded in multiple histograms using PlatformFileError + // enum. If the order of the fields needs to change, please ensure that those + // histograms are obsolete or have been moved to a different enum. + // + // FILE_ERROR_ACCESS_DENIED is returned when a call fails because of a + // filesystem restriction. FILE_ERROR_SECURITY is returned when a browser + // policy doesn't allow the operation to be executed. + enum Error { + FILE_OK = 0, + FILE_ERROR_FAILED = -1, + FILE_ERROR_IN_USE = -2, + FILE_ERROR_EXISTS = -3, + FILE_ERROR_NOT_FOUND = -4, + FILE_ERROR_ACCESS_DENIED = -5, + FILE_ERROR_TOO_MANY_OPENED = -6, + FILE_ERROR_NO_MEMORY = -7, + FILE_ERROR_NO_SPACE = -8, + FILE_ERROR_NOT_A_DIRECTORY = -9, + FILE_ERROR_INVALID_OPERATION = -10, + FILE_ERROR_SECURITY = -11, + FILE_ERROR_ABORT = -12, + FILE_ERROR_NOT_A_FILE = -13, + FILE_ERROR_NOT_EMPTY = -14, + FILE_ERROR_INVALID_URL = -15, + FILE_ERROR_IO = -16, + // Put new entries here and increment FILE_ERROR_MAX. + FILE_ERROR_MAX = -17 + }; + + // This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux. + enum Whence { FROM_BEGIN = 0, FROM_CURRENT = 1, FROM_END = 2 }; + + // Used to hold information about a given file. + // If you add more fields to this structure (platform-specific fields are OK), + // make sure to update all functions that use it in file_util_{win|posix}.cc, + // too, and the ParamTraits implementation in + // ipc/ipc_message_utils.cc. + struct Info { + Info(); + ~Info(); +#if defined(OS_POSIX) || defined(OS_FUCHSIA) + // Fills this struct with values from |stat_info|. + void FromStat(const stat_wrapper_t& stat_info); +#endif + + // The size of the file in bytes. Undefined when is_directory is true. + int64_t size; + + // True if the file corresponds to a directory. + bool is_directory; + + // True if the file corresponds to a symbolic link. For Windows currently + // not supported and thus always false. + bool is_symbolic_link; + + // The last modified time of a file. + Ticks last_modified; + + // The last accessed time of a file. + Ticks last_accessed; + + // The creation time of a file. + Ticks creation_time; + }; + + File(); + + // Creates or opens the given file. This will fail with 'access denied' if the + // |path| contains path traversal ('..') components. + File(const FilePath& path, uint32_t flags); + + // Takes ownership of |platform_file|. + explicit File(PlatformFile platform_file); + + // Creates an object with a specific error_details code. + explicit File(Error error_details); + + File(File&& other); + + ~File(); + + // Takes ownership of |platform_file|. + static File CreateForAsyncHandle(PlatformFile platform_file); + + File& operator=(File&& other); + + // Creates or opens the given file. + void Initialize(const FilePath& path, uint32_t flags); + + // Returns |true| if the handle / fd wrapped by this object is valid. This + // method doesn't interact with the file system (and is safe to be called from + // ThreadRestrictions::SetIOAllowed(false) threads). + bool IsValid() const; + + // Returns true if a new file was created (or an old one truncated to zero + // length to simulate a new file, which can happen with + // FLAG_CREATE_ALWAYS), and false otherwise. + bool created() const { return created_; } + + // Returns the OS result of opening this file. Note that the way to verify + // the success of the operation is to use IsValid(), not this method: + // File file(path, flags); + // if (!file.IsValid()) + // return; + Error error_details() const { return error_details_; } + + PlatformFile GetPlatformFile() const; + PlatformFile TakePlatformFile(); + + // Destroying this object closes the file automatically. + void Close(); + + // Changes current position in the file to an |offset| relative to an origin + // defined by |whence|. Returns the resultant current position in the file + // (relative to the start) or -1 in case of error. + int64_t Seek(Whence whence, int64_t offset); + + // Reads the given number of bytes (or until EOF is reached) starting with the + // given offset. Returns the number of bytes read, or -1 on error. Note that + // this function makes a best effort to read all data on all platforms, so it + // is not intended for stream oriented files but instead for cases when the + // normal expectation is that actually |size| bytes are read unless there is + // an error. + int Read(int64_t offset, char* data, int size); + + // Same as above but without seek. + int ReadAtCurrentPos(char* data, int size); + + // Reads the given number of bytes (or until EOF is reached) starting with the + // given offset, but does not make any effort to read all data on all + // platforms. Returns the number of bytes read, or -1 on error. + int ReadNoBestEffort(int64_t offset, char* data, int size); + + // Same as above but without seek. + int ReadAtCurrentPosNoBestEffort(char* data, int size); + + // Writes the given buffer into the file at the given offset, overwritting any + // data that was previously there. Returns the number of bytes written, or -1 + // on error. Note that this function makes a best effort to write all data on + // all platforms. |data| can be nullptr when |size| is 0. + // Ignores the offset and writes to the end of the file if the file was opened + // with FLAG_APPEND. + int Write(int64_t offset, const char* data, int size); + + // Save as above but without seek. + int WriteAtCurrentPos(const char* data, int size); + + // Save as above but does not make any effort to write all data on all + // platforms. Returns the number of bytes written, or -1 on error. + int WriteAtCurrentPosNoBestEffort(const char* data, int size); + + // Returns the current size of this file, or a negative number on failure. + int64_t GetLength(); + + // Truncates the file to the given length. If |length| is greater than the + // current size of the file, the file is extended with zeros. If the file + // doesn't exist, |false| is returned. + bool SetLength(int64_t length); + + // Instructs the filesystem to flush the file to disk. (POSIX: fsync, Windows: + // FlushFileBuffers). + // Calling Flush() does not guarantee file integrity and thus is not a valid + // substitute for file integrity checks and recovery codepaths for malformed + // files. It can also be *really* slow, so avoid blocking on Flush(), + // especially please don't block shutdown on Flush(). + // Latency percentiles of Flush() across all platforms as of July 2016: + // 50 % > 5 ms + // 10 % > 58 ms + // 1 % > 357 ms + // 0.1 % > 1.8 seconds + // 0.01 % > 7.6 seconds + bool Flush(); + + // Returns some basic information for the given file. + bool GetInfo(Info* info); + +#if !defined(OS_FUCHSIA) // Fuchsia's POSIX API does not support file locking. + + // Attempts to take an exclusive write lock on the file. Returns immediately + // (i.e. does not wait for another process to unlock the file). If the lock + // was obtained, the result will be FILE_OK. A lock only guarantees + // that other processes may not also take a lock on the same file with the + // same API - it may still be opened, renamed, unlinked, etc. + // + // Common semantics: + // * Locks are held by processes, but not inherited by child processes. + // * Locks are released by the OS on file close or process termination. + // * Locks are reliable only on local filesystems. + // * Duplicated file handles may also write to locked files. + // Windows-specific semantics: + // * Locks are mandatory for read/write APIs, advisory for mapping APIs. + // * Within a process, locking the same file (by the same or new handle) + // will fail. + // POSIX-specific semantics: + // * Locks are advisory only. + // * Within a process, locking the same file (by the same or new handle) + // will succeed. + // * Closing any descriptor on a given file releases the lock. + Error Lock(); + + // Unlock a file previously locked. + Error Unlock(); + +#endif // !defined(OS_FUCHSIA) + + // Returns a new object referencing this file for use within the current + // process. Handling of FLAG_DELETE_ON_CLOSE varies by OS. On POSIX, the File + // object that was created or initialized with this flag will have unlinked + // the underlying file when it was created or opened. On Windows, the + // underlying file is deleted when the last handle to it is closed. + File Duplicate() const; + + bool async() const { return async_; } + +#if defined(OS_WIN) + // Sets or clears the DeleteFile disposition on the handle. Returns true if + // the disposition was set or cleared, as indicated by |delete_on_close|. + // + // Microsoft Windows deletes a file only when the last handle to the + // underlying kernel object is closed when the DeleteFile disposition has been + // set by any handle holder. This disposition is be set by: + // - Calling the Win32 DeleteFile function with the path to a file. + // - Opening/creating a file with FLAG_DELETE_ON_CLOSE. + // - Opening/creating a file with FLAG_CAN_DELETE_ON_CLOSE and subsequently + // calling DeleteOnClose(true). + // + // In all cases, all pre-existing handles to the file must have been opened + // with FLAG_SHARE_DELETE. + // + // So: + // - Use FLAG_SHARE_DELETE when creating/opening a file to allow another + // entity on the system to cause it to be deleted when it is closed. (Note: + // another entity can delete the file the moment after it is closed, so not + // using this permission doesn't provide any protections.) + // - Use FLAG_DELETE_ON_CLOSE for any file that is to be deleted after use. + // The OS will ensure it is deleted even in the face of process termination. + // - Use FLAG_CAN_DELETE_ON_CLOSE in conjunction with DeleteOnClose() to alter + // the DeleteFile disposition on an open handle. This fine-grained control + // allows for marking a file for deletion during processing so that it is + // deleted in the event of untimely process termination, and then clearing + // this state once the file is suitable for persistence. + bool DeleteOnClose(bool delete_on_close); +#endif + +#if defined(OS_WIN) + static Error OSErrorToFileError(DWORD last_error); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + static Error OSErrorToFileError(int saved_errno); +#endif + + // Gets the last global error (errno or GetLastError()) and converts it to the + // closest base::File::Error equivalent via OSErrorToFileError(). The returned + // value is only trustworthy immediately after another base::File method + // fails. base::File never resets the global error to zero. + static Error GetLastFileError(); + + // Converts an error value to a human-readable form. Used for logging. + static std::string ErrorToString(Error error); + + private: + // Creates or opens the given file. Only called if |path| has no + // traversal ('..') components. + void DoInitialize(const FilePath& path, uint32_t flags); + + void SetPlatformFile(PlatformFile file); + + ScopedPlatformFile file_; + + Error error_details_; + bool created_; + bool async_; + + DISALLOW_COPY_AND_ASSIGN(File); +}; + +} // namespace base + +#endif // BASE_FILES_FILE_H_ diff --git a/src/3rdparty/gn/base/files/file_enumerator.cc b/src/3rdparty/gn/base/files/file_enumerator.cc new file mode 100644 index 00000000000..9dfb2ba04b5 --- /dev/null +++ b/src/3rdparty/gn/base/files/file_enumerator.cc @@ -0,0 +1,25 @@ +// 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/files/file_enumerator.h" + +#include "base/files/file_util.h" + +namespace base { + +FileEnumerator::FileInfo::~FileInfo() = default; + +bool FileEnumerator::ShouldSkip(const FilePath& path) { + FilePath::StringType basename = path.BaseName().value(); + return basename == FILE_PATH_LITERAL(".") || + (basename == FILE_PATH_LITERAL("..") && + !(INCLUDE_DOT_DOT & file_type_)); +} + +bool FileEnumerator::IsTypeMatched(bool is_dir) const { + return (file_type_ & + (is_dir ? FileEnumerator::DIRECTORIES : FileEnumerator::FILES)) != 0; +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_enumerator.h b/src/3rdparty/gn/base/files/file_enumerator.h new file mode 100644 index 00000000000..81f757b445a --- /dev/null +++ b/src/3rdparty/gn/base/files/file_enumerator.h @@ -0,0 +1,171 @@ +// 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_FILES_FILE_ENUMERATOR_H_ +#define BASE_FILES_FILE_ENUMERATOR_H_ + +#include +#include + +#include + +#include "base/containers/stack.h" +#include "base/files/file_path.h" +#include "base/macros.h" +#include "util/build_config.h" +#include "util/ticks.h" + +#if defined(OS_WIN) +#include +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +#include +#include +#endif + +namespace base { + +// A class for enumerating the files in a provided path. The order of the +// results is not guaranteed. +// +// This is blocking. Do not use on critical threads. +// +// Example: +// +// base::FileEnumerator enum(my_dir, false, base::FileEnumerator::FILES, +// FILE_PATH_LITERAL("*.txt")); +// for (base::FilePath name = enum.Next(); !name.empty(); name = enum.Next()) +// ... +class FileEnumerator { + public: + // Note: copy & assign supported. + class FileInfo { + public: + FileInfo(); + ~FileInfo(); + + bool IsDirectory() const; + + // The name of the file. This will not include any path information. This + // is in constrast to the value returned by FileEnumerator.Next() which + // includes the |root_path| passed into the FileEnumerator constructor. + FilePath GetName() const; + + int64_t GetSize() const; + Ticks GetLastModifiedTime() const; + +#if defined(OS_WIN) + // Note that the cAlternateFileName (used to hold the "short" 8.3 name) + // of the WIN32_FIND_DATA will be empty. Since we don't use short file + // names, we tell Windows to omit it which speeds up the query slightly. + const WIN32_FIND_DATA& find_data() const { return find_data_; } +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + const struct stat& stat() const { return stat_; } +#endif + + private: + friend class FileEnumerator; + +#if defined(OS_WIN) + WIN32_FIND_DATA find_data_; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + struct stat stat_; + FilePath filename_; +#endif + }; + + enum FileType { + FILES = 1 << 0, + DIRECTORIES = 1 << 1, + INCLUDE_DOT_DOT = 1 << 2, +#if defined(OS_POSIX) || defined(OS_FUCHSIA) + SHOW_SYM_LINKS = 1 << 4, +#endif + }; + + // Search policy for intermediate folders. + enum class FolderSearchPolicy { + // Recursive search will pass through folders whose names match the + // pattern. Inside each one, all files will be returned. Folders with names + // that do not match the pattern will be ignored within their interior. + MATCH_ONLY, + // Recursive search will pass through every folder and perform pattern + // matching inside each one. + ALL, + }; + + // |root_path| is the starting directory to search for. It may or may not end + // in a slash. + // + // If |recursive| is true, this will enumerate all matches in any + // subdirectories matched as well. It does a breadth-first search, so all + // files in one directory will be returned before any files in a + // subdirectory. + // + // |file_type|, a bit mask of FileType, specifies whether the enumerator + // should match files, directories, or both. + // + // |pattern| is an optional pattern for which files to match. This + // works like shell globbing. For example, "*.txt" or "Foo???.doc". + // However, be careful in specifying patterns that aren't cross platform + // since the underlying code uses OS-specific matching routines. In general, + // Windows matching is less featureful than others, so test there first. + // If unspecified, this will match all files. + FileEnumerator(const FilePath& root_path, bool recursive, int file_type); + FileEnumerator(const FilePath& root_path, + bool recursive, + int file_type, + const FilePath::StringType& pattern); + FileEnumerator(const FilePath& root_path, + bool recursive, + int file_type, + const FilePath::StringType& pattern, + FolderSearchPolicy folder_search_policy); + ~FileEnumerator(); + + // Returns the next file or an empty string if there are no more results. + // + // The returned path will incorporate the |root_path| passed in the + // constructor: "/file_name.txt". If the |root_path| is absolute, + // then so will be the result of Next(). + FilePath Next(); + + // Write the file info into |info|. + FileInfo GetInfo() const; + + private: + // Returns true if the given path should be skipped in enumeration. + bool ShouldSkip(const FilePath& path); + + bool IsTypeMatched(bool is_dir) const; + + bool IsPatternMatched(const FilePath& src) const; + +#if defined(OS_WIN) + // True when find_data_ is valid. + bool has_find_data_ = false; + WIN32_FIND_DATA find_data_; + HANDLE find_handle_ = INVALID_HANDLE_VALUE; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + // The files in the current directory + std::vector directory_entries_; + + // The next entry to use from the directory_entries_ vector + size_t current_directory_entry_; +#endif + FilePath root_path_; + const bool recursive_; + const int file_type_; + FilePath::StringType pattern_; + const FolderSearchPolicy folder_search_policy_; + + // A stack that keeps track of which subdirectories we still need to + // enumerate in the breadth-first search. + base::stack pending_paths_; + + DISALLOW_COPY_AND_ASSIGN(FileEnumerator); +}; + +} // namespace base + +#endif // BASE_FILES_FILE_ENUMERATOR_H_ diff --git a/src/3rdparty/gn/base/files/file_enumerator_posix.cc b/src/3rdparty/gn/base/files/file_enumerator_posix.cc new file mode 100644 index 00000000000..41d52b8afdd --- /dev/null +++ b/src/3rdparty/gn/base/files/file_enumerator_posix.cc @@ -0,0 +1,170 @@ +// 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/files/file_enumerator.h" + +#include +#include +#include +#include +#include + +#include "base/logging.h" +#include "util/build_config.h" + +namespace base { +namespace { + +void GetStat(const FilePath& path, bool show_links, struct stat* st) { + DCHECK(st); + const int res = show_links ? lstat(path.value().c_str(), st) + : stat(path.value().c_str(), st); + if (res < 0) { + // Print the stat() error message unless it was ENOENT and we're following + // symlinks. + if (!(errno == ENOENT && !show_links)) + DPLOG(ERROR) << "Couldn't stat" << path.value(); + memset(st, 0, sizeof(*st)); + } +} + +} // namespace + +// FileEnumerator::FileInfo ---------------------------------------------------- + +FileEnumerator::FileInfo::FileInfo() { + memset(&stat_, 0, sizeof(stat_)); +} + +bool FileEnumerator::FileInfo::IsDirectory() const { + return S_ISDIR(stat_.st_mode); +} + +FilePath FileEnumerator::FileInfo::GetName() const { + return filename_; +} + +int64_t FileEnumerator::FileInfo::GetSize() const { + return stat_.st_size; +} + +Ticks FileEnumerator::FileInfo::GetLastModifiedTime() const { + return stat_.st_mtime; +} + +// FileEnumerator -------------------------------------------------------------- + +FileEnumerator::FileEnumerator(const FilePath& root_path, + bool recursive, + int file_type) + : FileEnumerator(root_path, + recursive, + file_type, + FilePath::StringType(), + FolderSearchPolicy::MATCH_ONLY) {} + +FileEnumerator::FileEnumerator(const FilePath& root_path, + bool recursive, + int file_type, + const FilePath::StringType& pattern) + : FileEnumerator(root_path, + recursive, + file_type, + pattern, + FolderSearchPolicy::MATCH_ONLY) {} + +FileEnumerator::FileEnumerator(const FilePath& root_path, + bool recursive, + int file_type, + const FilePath::StringType& pattern, + FolderSearchPolicy folder_search_policy) + : current_directory_entry_(0), + root_path_(root_path), + recursive_(recursive), + file_type_(file_type), + pattern_(pattern), + folder_search_policy_(folder_search_policy) { + // INCLUDE_DOT_DOT must not be specified if recursive. + DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); + + pending_paths_.push(root_path); +} + +FileEnumerator::~FileEnumerator() = default; + +FilePath FileEnumerator::Next() { + ++current_directory_entry_; + + // While we've exhausted the entries in the current directory, do the next + while (current_directory_entry_ >= directory_entries_.size()) { + if (pending_paths_.empty()) + return FilePath(); + + root_path_ = pending_paths_.top(); + root_path_ = root_path_.StripTrailingSeparators(); + pending_paths_.pop(); + + DIR* dir = opendir(root_path_.value().c_str()); + if (!dir) + continue; + + directory_entries_.clear(); + + current_directory_entry_ = 0; + struct dirent* dent; + while ((dent = readdir(dir))) { + FileInfo info; + info.filename_ = FilePath(dent->d_name); + + if (ShouldSkip(info.filename_)) + continue; + + const bool is_pattern_matched = IsPatternMatched(info.filename_); + + // MATCH_ONLY policy enumerates files and directories which matching + // pattern only. So we can early skip further checks. + if (folder_search_policy_ == FolderSearchPolicy::MATCH_ONLY && + !is_pattern_matched) + continue; + + // Do not call OS stat/lstat if there is no sense to do it. If pattern is + // not matched (file will not appear in results) and search is not + // recursive (possible directory will not be added to pending paths) - + // there is no sense to obtain item below. + if (!recursive_ && !is_pattern_matched) + continue; + + const FilePath full_path = root_path_.Append(info.filename_); + GetStat(full_path, file_type_ & SHOW_SYM_LINKS, &info.stat_); + + const bool is_dir = info.IsDirectory(); + + if (recursive_ && is_dir) + pending_paths_.push(full_path); + + if (is_pattern_matched && IsTypeMatched(is_dir)) + directory_entries_.push_back(std::move(info)); + } + closedir(dir); + + // MATCH_ONLY policy enumerates files in matched subfolders by "*" pattern. + // ALL policy enumerates files in all subfolders by origin pattern. + if (folder_search_policy_ == FolderSearchPolicy::MATCH_ONLY) + pattern_.clear(); + } + + return root_path_.Append( + directory_entries_[current_directory_entry_].filename_); +} + +FileEnumerator::FileInfo FileEnumerator::GetInfo() const { + return directory_entries_[current_directory_entry_]; +} + +bool FileEnumerator::IsPatternMatched(const FilePath& path) const { + return pattern_.empty() || + !fnmatch(pattern_.c_str(), path.value().c_str(), FNM_NOESCAPE); +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_enumerator_win.cc b/src/3rdparty/gn/base/files/file_enumerator_win.cc new file mode 100644 index 00000000000..803b7bd4437 --- /dev/null +++ b/src/3rdparty/gn/base/files/file_enumerator_win.cc @@ -0,0 +1,192 @@ +// 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/files/file_enumerator.h" + +#include +#include +#include + +#include "base/logging.h" + +namespace base { + +namespace { + +FilePath BuildSearchFilter(FileEnumerator::FolderSearchPolicy policy, + const FilePath& root_path, + const FilePath::StringType& pattern) { + // MATCH_ONLY policy filters incoming files by pattern on OS side. ALL policy + // collects all files and filters them manually. + switch (policy) { + case FileEnumerator::FolderSearchPolicy::MATCH_ONLY: + return root_path.Append(pattern); + case FileEnumerator::FolderSearchPolicy::ALL: + return root_path.Append(L"*"); + } + NOTREACHED(); + return {}; +} + +} // namespace + +// FileEnumerator::FileInfo ---------------------------------------------------- + +FileEnumerator::FileInfo::FileInfo() { + memset(&find_data_, 0, sizeof(find_data_)); +} + +bool FileEnumerator::FileInfo::IsDirectory() const { + return (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; +} + +FilePath FileEnumerator::FileInfo::GetName() const { + return FilePath(find_data_.cFileName); +} + +int64_t FileEnumerator::FileInfo::GetSize() const { + ULARGE_INTEGER size; + size.HighPart = find_data_.nFileSizeHigh; + size.LowPart = find_data_.nFileSizeLow; + DCHECK_LE(size.QuadPart, + static_cast(std::numeric_limits::max())); + return static_cast(size.QuadPart); +} + +Ticks FileEnumerator::FileInfo::GetLastModifiedTime() const { + return *reinterpret_cast(&find_data_.ftLastWriteTime); +} + +// FileEnumerator -------------------------------------------------------------- + +FileEnumerator::FileEnumerator(const FilePath& root_path, + bool recursive, + int file_type) + : FileEnumerator(root_path, + recursive, + file_type, + FilePath::StringType(), + FolderSearchPolicy::MATCH_ONLY) {} + +FileEnumerator::FileEnumerator(const FilePath& root_path, + bool recursive, + int file_type, + const FilePath::StringType& pattern) + : FileEnumerator(root_path, + recursive, + file_type, + pattern, + FolderSearchPolicy::MATCH_ONLY) {} + +FileEnumerator::FileEnumerator(const FilePath& root_path, + bool recursive, + int file_type, + const FilePath::StringType& pattern, + FolderSearchPolicy folder_search_policy) + : recursive_(recursive), + file_type_(file_type), + pattern_(!pattern.empty() ? pattern : L"*"), + folder_search_policy_(folder_search_policy) { + // INCLUDE_DOT_DOT must not be specified if recursive. + DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); + memset(&find_data_, 0, sizeof(find_data_)); + pending_paths_.push(root_path); +} + +FileEnumerator::~FileEnumerator() { + if (find_handle_ != INVALID_HANDLE_VALUE) + FindClose(find_handle_); +} + +FileEnumerator::FileInfo FileEnumerator::GetInfo() const { + if (!has_find_data_) { + NOTREACHED(); + return FileInfo(); + } + FileInfo ret; + memcpy(&ret.find_data_, &find_data_, sizeof(find_data_)); + return ret; +} + +FilePath FileEnumerator::Next() { + while (has_find_data_ || !pending_paths_.empty()) { + if (!has_find_data_) { + // The last find FindFirstFile operation is done, prepare a new one. + root_path_ = pending_paths_.top(); + pending_paths_.pop(); + + // Start a new find operation. + const FilePath src = + BuildSearchFilter(folder_search_policy_, root_path_, pattern_); + find_handle_ = FindFirstFileEx(src.value().c_str(), + FindExInfoBasic, // Omit short name. + &find_data_, FindExSearchNameMatch, + nullptr, FIND_FIRST_EX_LARGE_FETCH); + has_find_data_ = true; + } else { + // Search for the next file/directory. + if (!FindNextFile(find_handle_, &find_data_)) { + FindClose(find_handle_); + find_handle_ = INVALID_HANDLE_VALUE; + } + } + + if (INVALID_HANDLE_VALUE == find_handle_) { + has_find_data_ = false; + + // MATCH_ONLY policy clears pattern for matched subfolders. ALL policy + // applies pattern for all subfolders. + if (folder_search_policy_ == FolderSearchPolicy::MATCH_ONLY) { + // This is reached when we have finished a directory and are advancing + // to the next one in the queue. We applied the pattern (if any) to the + // files in the root search directory, but for those directories which + // were matched, we want to enumerate all files inside them. This will + // happen when the handle is empty. + pattern_ = L"*"; + } + + continue; + } + + const FilePath filename(find_data_.cFileName); + if (ShouldSkip(filename)) + continue; + + const bool is_dir = + (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + const FilePath abs_path = root_path_.Append(filename); + + // Check if directory should be processed recursive. + if (is_dir && recursive_) { + // If |cur_file| is a directory, and we are doing recursive searching, + // add it to pending_paths_ so we scan it after we finish scanning this + // directory. However, don't do recursion through reparse points or we + // may end up with an infinite cycle. + DWORD attributes = GetFileAttributes(abs_path.value().c_str()); + if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT)) + pending_paths_.push(abs_path); + } + + if (IsTypeMatched(is_dir) && IsPatternMatched(filename)) + return abs_path; + } + return FilePath(); +} + +bool FileEnumerator::IsPatternMatched(const FilePath& src) const { + switch (folder_search_policy_) { + case FolderSearchPolicy::MATCH_ONLY: + // MATCH_ONLY policy filters by pattern on search request, so all found + // files already fits to pattern. + return true; + case FolderSearchPolicy::ALL: + // ALL policy enumerates all files, we need to check pattern match + // manually. + return PathMatchSpec(src.value().c_str(), pattern_.c_str()) == TRUE; + } + NOTREACHED(); + return false; +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_path.cc b/src/3rdparty/gn/base/files/file_path.cc new file mode 100644 index 00000000000..014bc9e0cf8 --- /dev/null +++ b/src/3rdparty/gn/base/files/file_path.cc @@ -0,0 +1,669 @@ +// 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/files/file_path.h" + +#include +#include + +#include "base/logging.h" +#include "base/macros.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "util/build_config.h" + +#if defined(OS_MACOSX) +#include "base/mac/scoped_cftyperef.h" +#include "base/third_party/icu/icu_utf.h" +#endif + +#if defined(OS_WIN) +#include +#elif defined(OS_MACOSX) +#include +#endif + +namespace base { + +using StringType = FilePath::StringType; +using StringPieceType = FilePath::StringPieceType; + +namespace { + +const char* const kCommonDoubleExtensionSuffixes[] = {"gz", "z", "bz2", "bz"}; +const char* const kCommonDoubleExtensions[] = {"user.js"}; + +const FilePath::CharType kStringTerminator = FILE_PATH_LITERAL('\0'); + +// If this FilePath contains a drive letter specification, returns the +// position of the last character of the drive letter specification, +// otherwise returns npos. This can only be true on Windows, when a pathname +// begins with a letter followed by a colon. On other platforms, this always +// returns npos. +StringPieceType::size_type FindDriveLetter(StringPieceType path) { +#if defined(FILE_PATH_USES_DRIVE_LETTERS) + // This is dependent on an ASCII-based character set, but that's a + // reasonable assumption. iswalpha can be too inclusive here. + if (path.length() >= 2 && path[1] == L':' && + ((path[0] >= L'A' && path[0] <= L'Z') || + (path[0] >= L'a' && path[0] <= L'z'))) { + return 1; + } +#endif // FILE_PATH_USES_DRIVE_LETTERS + return StringType::npos; +} + +#if defined(FILE_PATH_USES_DRIVE_LETTERS) +bool EqualDriveLetterCaseInsensitive(StringPieceType a, StringPieceType b) { + size_t a_letter_pos = FindDriveLetter(a); + size_t b_letter_pos = FindDriveLetter(b); + + if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos) + return a == b; + + StringPieceType a_letter(a.substr(0, a_letter_pos + 1)); + StringPieceType b_letter(b.substr(0, b_letter_pos + 1)); + if (!StartsWith(a_letter, b_letter, CompareCase::INSENSITIVE_ASCII)) + return false; + + StringPieceType a_rest(a.substr(a_letter_pos + 1)); + StringPieceType b_rest(b.substr(b_letter_pos + 1)); + return a_rest == b_rest; +} +#endif // defined(FILE_PATH_USES_DRIVE_LETTERS) + +bool IsPathAbsolute(StringPieceType path) { +#if defined(FILE_PATH_USES_DRIVE_LETTERS) + StringType::size_type letter = FindDriveLetter(path); + if (letter != StringType::npos) { + // Look for a separator right after the drive specification. + return path.length() > letter + 1 && + FilePath::IsSeparator(path[letter + 1]); + } + // Look for a pair of leading separators. + return path.length() > 1 && FilePath::IsSeparator(path[0]) && + FilePath::IsSeparator(path[1]); +#else // FILE_PATH_USES_DRIVE_LETTERS + // Look for a separator in the first position. + return path.length() > 0 && FilePath::IsSeparator(path[0]); +#endif // FILE_PATH_USES_DRIVE_LETTERS +} + +bool AreAllSeparators(const StringType& input) { + for (StringType::const_iterator it = input.begin(); it != input.end(); ++it) { + if (!FilePath::IsSeparator(*it)) + return false; + } + + return true; +} + +// Find the position of the '.' that separates the extension from the rest +// of the file name. The position is relative to BaseName(), not value(). +// Returns npos if it can't find an extension. +StringType::size_type FinalExtensionSeparatorPosition(const StringType& path) { + // Special case "." and ".." + if (path == FilePath::kCurrentDirectory || path == FilePath::kParentDirectory) + return StringType::npos; + + return path.rfind(FilePath::kExtensionSeparator); +} + +// Same as above, but allow a second extension component of up to 4 +// characters when the rightmost extension component is a common double +// extension (gz, bz2, Z). For example, foo.tar.gz or foo.tar.Z would have +// extension components of '.tar.gz' and '.tar.Z' respectively. +StringType::size_type ExtensionSeparatorPosition(const StringType& path) { + const StringType::size_type last_dot = FinalExtensionSeparatorPosition(path); + + // No extension, or the extension is the whole filename. + if (last_dot == StringType::npos || last_dot == 0U) + return last_dot; + + const StringType::size_type penultimate_dot = + path.rfind(FilePath::kExtensionSeparator, last_dot - 1); + const StringType::size_type last_separator = path.find_last_of( + FilePath::kSeparators, last_dot - 1, FilePath::kSeparatorsLength - 1); + + if (penultimate_dot == StringType::npos || + (last_separator != StringType::npos && + penultimate_dot < last_separator)) { + return last_dot; + } + + for (size_t i = 0; i < arraysize(kCommonDoubleExtensions); ++i) { + StringType extension(path, penultimate_dot + 1); + if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensions[i])) + return penultimate_dot; + } + + StringType extension(path, last_dot + 1); + for (size_t i = 0; i < arraysize(kCommonDoubleExtensionSuffixes); ++i) { + if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensionSuffixes[i])) { + if ((last_dot - penultimate_dot) <= 5U && + (last_dot - penultimate_dot) > 1U) { + return penultimate_dot; + } + } + } + + return last_dot; +} + +// Returns true if path is "", ".", or "..". +bool IsEmptyOrSpecialCase(const StringType& path) { + // Special cases "", ".", and ".." + if (path.empty() || path == FilePath::kCurrentDirectory || + path == FilePath::kParentDirectory) { + return true; + } + + return false; +} + +} // namespace + +FilePath::FilePath() = default; + +FilePath::FilePath(const FilePath& that) = default; +FilePath::FilePath(FilePath&& that) noexcept = default; + +FilePath::FilePath(StringPieceType path) { + path.CopyToString(&path_); + StringType::size_type nul_pos = path_.find(kStringTerminator); + if (nul_pos != StringType::npos) + path_.erase(nul_pos, StringType::npos); +} + +FilePath::~FilePath() = default; + +FilePath& FilePath::operator=(const FilePath& that) = default; + +FilePath& FilePath::operator=(FilePath&& that) = default; + +bool FilePath::operator==(const FilePath& that) const { +#if defined(FILE_PATH_USES_DRIVE_LETTERS) + return EqualDriveLetterCaseInsensitive(this->path_, that.path_); +#else // defined(FILE_PATH_USES_DRIVE_LETTERS) + return path_ == that.path_; +#endif // defined(FILE_PATH_USES_DRIVE_LETTERS) +} + +bool FilePath::operator!=(const FilePath& that) const { +#if defined(FILE_PATH_USES_DRIVE_LETTERS) + return !EqualDriveLetterCaseInsensitive(this->path_, that.path_); +#else // defined(FILE_PATH_USES_DRIVE_LETTERS) + return path_ != that.path_; +#endif // defined(FILE_PATH_USES_DRIVE_LETTERS) +} + +std::ostream& operator<<(std::ostream& out, const FilePath& file_path) { + return out << file_path.value(); +} + +// static +bool FilePath::IsSeparator(CharType character) { + for (size_t i = 0; i < kSeparatorsLength - 1; ++i) { + if (character == kSeparators[i]) { + return true; + } + } + + return false; +} + +void FilePath::GetComponents(std::vector* components) const { + DCHECK(components); + if (!components) + return; + components->clear(); + if (value().empty()) + return; + + std::vector ret_val; + FilePath current = *this; + FilePath base; + + // Capture path components. + while (current != current.DirName()) { + base = current.BaseName(); + if (!AreAllSeparators(base.value())) + ret_val.push_back(base.value()); + current = current.DirName(); + } + + // Capture root, if any. + base = current.BaseName(); + if (!base.value().empty() && base.value() != kCurrentDirectory) + ret_val.push_back(current.BaseName().value()); + + // Capture drive letter, if any. + FilePath dir = current.DirName(); + StringType::size_type letter = FindDriveLetter(dir.value()); + if (letter != StringType::npos) { + ret_val.push_back(StringType(dir.value(), 0, letter + 1)); + } + + *components = std::vector(ret_val.rbegin(), ret_val.rend()); +} + +bool FilePath::IsParent(const FilePath& child) const { + return AppendRelativePath(child, nullptr); +} + +bool FilePath::AppendRelativePath(const FilePath& child, FilePath* path) const { + std::vector parent_components; + std::vector child_components; + GetComponents(&parent_components); + child.GetComponents(&child_components); + + if (parent_components.empty() || + parent_components.size() >= child_components.size()) + return false; + + std::vector::const_iterator parent_comp = + parent_components.begin(); + std::vector::const_iterator child_comp = child_components.begin(); + +#if defined(FILE_PATH_USES_DRIVE_LETTERS) + // Windows can access case sensitive filesystems, so component + // comparisions must be case sensitive, but drive letters are + // never case sensitive. + if ((FindDriveLetter(*parent_comp) != StringType::npos) && + (FindDriveLetter(*child_comp) != StringType::npos)) { + if (!StartsWith(*parent_comp, *child_comp, CompareCase::INSENSITIVE_ASCII)) + return false; + ++parent_comp; + ++child_comp; + } +#endif // defined(FILE_PATH_USES_DRIVE_LETTERS) + + while (parent_comp != parent_components.end()) { + if (*parent_comp != *child_comp) + return false; + ++parent_comp; + ++child_comp; + } + + if (path != nullptr) { + for (; child_comp != child_components.end(); ++child_comp) { + *path = path->Append(*child_comp); + } + } + return true; +} + +// libgen's dirname and basename aren't guaranteed to be thread-safe and aren't +// guaranteed to not modify their input strings, and in fact are implemented +// differently in this regard on different platforms. Don't use them, but +// adhere to their behavior. +FilePath FilePath::DirName() const { + FilePath new_path(path_); + new_path.StripTrailingSeparatorsInternal(); + + // The drive letter, if any, always needs to remain in the output. If there + // is no drive letter, as will always be the case on platforms which do not + // support drive letters, letter will be npos, or -1, so the comparisons and + // resizes below using letter will still be valid. + StringType::size_type letter = FindDriveLetter(new_path.path_); + + StringType::size_type last_separator = new_path.path_.find_last_of( + kSeparators, StringType::npos, kSeparatorsLength - 1); + if (last_separator == StringType::npos) { + // path_ is in the current directory. + new_path.path_.resize(letter + 1); + } else if (last_separator == letter + 1) { + // path_ is in the root directory. + new_path.path_.resize(letter + 2); + } else if (last_separator == letter + 2 && + IsSeparator(new_path.path_[letter + 1])) { + // path_ is in "//" (possibly with a drive letter); leave the double + // separator intact indicating alternate root. + new_path.path_.resize(letter + 3); + } else if (last_separator != 0) { + // path_ is somewhere else, trim the basename. + new_path.path_.resize(last_separator); + } + + new_path.StripTrailingSeparatorsInternal(); + if (!new_path.path_.length()) + new_path.path_ = kCurrentDirectory; + + return new_path; +} + +FilePath FilePath::BaseName() const { + FilePath new_path(path_); + new_path.StripTrailingSeparatorsInternal(); + + // The drive letter, if any, is always stripped. + StringType::size_type letter = FindDriveLetter(new_path.path_); + if (letter != StringType::npos) { + new_path.path_.erase(0, letter + 1); + } + + // Keep everything after the final separator, but if the pathname is only + // one character and it's a separator, leave it alone. + StringType::size_type last_separator = new_path.path_.find_last_of( + kSeparators, StringType::npos, kSeparatorsLength - 1); + if (last_separator != StringType::npos && + last_separator < new_path.path_.length() - 1) { + new_path.path_.erase(0, last_separator + 1); + } + + return new_path; +} + +StringType FilePath::Extension() const { + FilePath base(BaseName()); + const StringType::size_type dot = ExtensionSeparatorPosition(base.path_); + if (dot == StringType::npos) + return StringType(); + + return base.path_.substr(dot, StringType::npos); +} + +StringType FilePath::FinalExtension() const { + FilePath base(BaseName()); + const StringType::size_type dot = FinalExtensionSeparatorPosition(base.path_); + if (dot == StringType::npos) + return StringType(); + + return base.path_.substr(dot, StringType::npos); +} + +FilePath FilePath::RemoveExtension() const { + if (Extension().empty()) + return *this; + + const StringType::size_type dot = ExtensionSeparatorPosition(path_); + if (dot == StringType::npos) + return *this; + + return FilePath(path_.substr(0, dot)); +} + +FilePath FilePath::RemoveFinalExtension() const { + if (FinalExtension().empty()) + return *this; + + const StringType::size_type dot = FinalExtensionSeparatorPosition(path_); + if (dot == StringType::npos) + return *this; + + return FilePath(path_.substr(0, dot)); +} + +FilePath FilePath::InsertBeforeExtension(StringPieceType suffix) const { + if (suffix.empty()) + return FilePath(path_); + + if (IsEmptyOrSpecialCase(BaseName().value())) + return FilePath(); + + StringType ext = Extension(); + StringType ret = RemoveExtension().value(); + suffix.AppendToString(&ret); + ret.append(ext); + return FilePath(ret); +} + +FilePath FilePath::InsertBeforeExtensionASCII(StringPiece suffix) const { + DCHECK(IsStringASCII(suffix)); +#if defined(OS_WIN) + return InsertBeforeExtension(ASCIIToUTF16(suffix)); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + return InsertBeforeExtension(suffix); +#endif +} + +FilePath FilePath::AddExtension(StringPieceType extension) const { + if (IsEmptyOrSpecialCase(BaseName().value())) + return FilePath(); + + // If the new extension is "" or ".", then just return the current FilePath. + if (extension.empty() || + (extension.size() == 1 && extension[0] == kExtensionSeparator)) + return *this; + + StringType str = path_; + if (extension[0] != kExtensionSeparator && + *(str.end() - 1) != kExtensionSeparator) { + str.append(1, kExtensionSeparator); + } + extension.AppendToString(&str); + return FilePath(str); +} + +FilePath FilePath::ReplaceExtension(StringPieceType extension) const { + if (IsEmptyOrSpecialCase(BaseName().value())) + return FilePath(); + + FilePath no_ext = RemoveExtension(); + // If the new extension is "" or ".", then just remove the current extension. + if (extension.empty() || + (extension.size() == 1 && extension[0] == kExtensionSeparator)) + return no_ext; + + StringType str = no_ext.value(); + if (extension[0] != kExtensionSeparator) + str.append(1, kExtensionSeparator); + extension.AppendToString(&str); + return FilePath(str); +} + +FilePath FilePath::Append(StringPieceType component) const { + StringPieceType appended = component; + StringType without_nuls; + + StringType::size_type nul_pos = component.find(kStringTerminator); + if (nul_pos != StringPieceType::npos) { + component.substr(0, nul_pos).CopyToString(&without_nuls); + appended = StringPieceType(without_nuls); + } + + DCHECK(!IsPathAbsolute(appended)); + + if (path_.compare(kCurrentDirectory) == 0 && !appended.empty()) { + // Append normally doesn't do any normalization, but as a special case, + // when appending to kCurrentDirectory, just return a new path for the + // component argument. Appending component to kCurrentDirectory would + // serve no purpose other than needlessly lengthening the path, and + // it's likely in practice to wind up with FilePath objects containing + // only kCurrentDirectory when calling DirName on a single relative path + // component. + return FilePath(appended); + } + + FilePath new_path(path_); + new_path.StripTrailingSeparatorsInternal(); + + // Don't append a separator if the path is empty (indicating the current + // directory) or if the path component is empty (indicating nothing to + // append). + if (!appended.empty() && !new_path.path_.empty()) { + // Don't append a separator if the path still ends with a trailing + // separator after stripping (indicating the root directory). + if (!IsSeparator(new_path.path_.back())) { + // Don't append a separator if the path is just a drive letter. + if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) { + new_path.path_.append(1, kSeparators[0]); + } + } + } + + appended.AppendToString(&new_path.path_); + return new_path; +} + +FilePath FilePath::Append(const FilePath& component) const { + return Append(component.value()); +} + +FilePath FilePath::AppendASCII(StringPiece component) const { + DCHECK(base::IsStringASCII(component)); +#if defined(OS_WIN) + return Append(ASCIIToUTF16(component)); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + return Append(component); +#endif +} + +bool FilePath::IsAbsolute() const { + return IsPathAbsolute(path_); +} + +bool FilePath::EndsWithSeparator() const { + if (empty()) + return false; + return IsSeparator(path_.back()); +} + +FilePath FilePath::AsEndingWithSeparator() const { + if (EndsWithSeparator() || path_.empty()) + return *this; + + StringType path_str; + path_str.reserve(path_.length() + 1); // Only allocate string once. + + path_str = path_; + path_str.append(&kSeparators[0], 1); + return FilePath(path_str); +} + +FilePath FilePath::StripTrailingSeparators() const { + FilePath new_path(path_); + new_path.StripTrailingSeparatorsInternal(); + + return new_path; +} + +bool FilePath::ReferencesParent() const { + if (path_.find(kParentDirectory) == StringType::npos) { + // GetComponents is quite expensive, so avoid calling it in the majority + // of cases where there isn't a kParentDirectory anywhere in the path. + return false; + } + + std::vector components; + GetComponents(&components); + + std::vector::const_iterator it = components.begin(); + for (; it != components.end(); ++it) { + const StringType& component = *it; + // Windows has odd, undocumented behavior with path components containing + // only whitespace and . characters. So, if all we see is . and + // whitespace, then we treat any .. sequence as referencing parent. + // For simplicity we enforce this on all platforms. + if (component.find_first_not_of(FILE_PATH_LITERAL(". \n\r\t")) == + std::string::npos && + component.find(kParentDirectory) != std::string::npos) { + return true; + } + } + return false; +} + +#if defined(OS_WIN) + +string16 FilePath::LossyDisplayName() const { + return path_; +} + +std::string FilePath::MaybeAsASCII() const { + if (base::IsStringASCII(path_)) + return UTF16ToASCII(path_); + return std::string(); +} + +std::string FilePath::AsUTF8Unsafe() const { + return WideToUTF8(value()); +} + +string16 FilePath::AsUTF16Unsafe() const { + return value(); +} + +// static +FilePath FilePath::FromUTF8Unsafe(StringPiece utf8) { + return FilePath(UTF8ToWide(utf8)); +} + +// static +FilePath FilePath::FromUTF16Unsafe(StringPiece16 utf16) { + return FilePath(utf16); +} + +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + +// See file_path.h for a discussion of the encoding of paths on POSIX +// platforms. These encoding conversion functions are not quite correct. + +std::string FilePath::MaybeAsASCII() const { + if (base::IsStringASCII(path_)) + return path_; + return std::string(); +} + +std::string FilePath::AsUTF8Unsafe() const { + return value(); +} + +string16 FilePath::AsUTF16Unsafe() const { + return UTF8ToUTF16(value()); +} + +// static +FilePath FilePath::FromUTF8Unsafe(StringPiece utf8) { + return FilePath(utf8); +} + +// static +FilePath FilePath::FromUTF16Unsafe(StringPiece16 utf16) { + return FilePath(UTF16ToUTF8(utf16)); +} + +#endif // defined(OS_WIN) + +void FilePath::StripTrailingSeparatorsInternal() { + // If there is no drive letter, start will be 1, which will prevent stripping + // the leading separator if there is only one separator. If there is a drive + // letter, start will be set appropriately to prevent stripping the first + // separator following the drive letter, if a separator immediately follows + // the drive letter. + StringType::size_type start = FindDriveLetter(path_) + 2; + + StringType::size_type last_stripped = StringType::npos; + for (StringType::size_type pos = path_.length(); + pos > start && IsSeparator(path_[pos - 1]); --pos) { + // If the string only has two separators and they're at the beginning, + // don't strip them, unless the string began with more than two separators. + if (pos != start + 1 || last_stripped == start + 2 || + !IsSeparator(path_[start - 1])) { + path_.resize(pos - 1); + last_stripped = pos; + } + } +} + +FilePath FilePath::NormalizePathSeparators() const { + return NormalizePathSeparatorsTo(kSeparators[0]); +} + +FilePath FilePath::NormalizePathSeparatorsTo(CharType separator) const { +#if defined(FILE_PATH_USES_WIN_SEPARATORS) + DCHECK_NE(kSeparators + kSeparatorsLength, + std::find(kSeparators, kSeparators + kSeparatorsLength, separator)); + StringType copy = path_; + for (size_t i = 0; i < kSeparatorsLength; ++i) { + std::replace(copy.begin(), copy.end(), kSeparators[i], separator); + } + return FilePath(copy); +#else + return *this; +#endif +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_path.h b/src/3rdparty/gn/base/files/file_path.h new file mode 100644 index 00000000000..1717cba713f --- /dev/null +++ b/src/3rdparty/gn/base/files/file_path.h @@ -0,0 +1,426 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// FilePath is a container for pathnames stored in a platform's native string +// type, providing containers for manipulation in according with the +// platform's conventions for pathnames. It supports the following path +// types: +// +// POSIX Windows +// --------------- ---------------------------------- +// Fundamental type char[] wchar_t[] +// Encoding unspecified* UTF-16 +// Separator / \, tolerant of / +// Drive letters no case-insensitive A-Z followed by : +// Alternate root // (surprise!) \\, for UNC paths +// +// * The encoding need not be specified on POSIX systems, although some +// POSIX-compliant systems do specify an encoding. Mac OS X uses UTF-8. +// Chrome OS also uses UTF-8. +// Linux does not specify an encoding, but in practice, the locale's +// character set may be used. +// +// For more arcane bits of path trivia, see below. +// +// FilePath objects are intended to be used anywhere paths are. An +// application may pass FilePath objects around internally, masking the +// underlying differences between systems, only differing in implementation +// where interfacing directly with the system. For example, a single +// OpenFile(const FilePath &) function may be made available, allowing all +// callers to operate without regard to the underlying implementation. On +// POSIX-like platforms, OpenFile might wrap fopen, and on Windows, it might +// wrap _wfopen_s, perhaps both by calling file_path.value().c_str(). This +// allows each platform to pass pathnames around without requiring conversions +// between encodings, which has an impact on performance, but more imporantly, +// has an impact on correctness on platforms that do not have well-defined +// encodings for pathnames. +// +// Several methods are available to perform common operations on a FilePath +// object, such as determining the parent directory (DirName), isolating the +// final path component (BaseName), and appending a relative pathname string +// to an existing FilePath object (Append). These methods are highly +// recommended over attempting to split and concatenate strings directly. +// These methods are based purely on string manipulation and knowledge of +// platform-specific pathname conventions, and do not consult the filesystem +// at all, making them safe to use without fear of blocking on I/O operations. +// These methods do not function as mutators but instead return distinct +// instances of FilePath objects, and are therefore safe to use on const +// objects. The objects themselves are safe to share between threads. +// +// To aid in initialization of FilePath objects from string literals, a +// FILE_PATH_LITERAL macro is provided, which accounts for the difference +// between char[]-based pathnames on POSIX systems and wchar_t[]-based +// pathnames on Windows. +// +// As a precaution against premature truncation, paths can't contain NULs. +// +// Because a FilePath object should not be instantiated at the global scope, +// instead, use a FilePath::CharType[] and initialize it with +// FILE_PATH_LITERAL. At runtime, a FilePath object can be created from the +// character array. Example: +// +// | const FilePath::CharType kLogFileName[] = FILE_PATH_LITERAL("log.txt"); +// | +// | void Function() { +// | FilePath log_file_path(kLogFileName); +// | [...] +// | } +// +// WARNING: FilePaths should ALWAYS be displayed with LTR directionality, even +// when the UI language is RTL. This means you always need to pass filepaths +// through base::i18n::WrapPathWithLTRFormatting() before displaying it in the +// RTL UI. +// +// This is a very common source of bugs, please try to keep this in mind. +// +// ARCANE BITS OF PATH TRIVIA +// +// - A double leading slash is actually part of the POSIX standard. Systems +// are allowed to treat // as an alternate root, as Windows does for UNC +// (network share) paths. Most POSIX systems don't do anything special +// with two leading slashes, but FilePath handles this case properly +// in case it ever comes across such a system. FilePath needs this support +// for Windows UNC paths, anyway. +// References: +// The Open Group Base Specifications Issue 7, sections 3.267 ("Pathname") +// and 4.12 ("Pathname Resolution"), available at: +// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_267 +// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_12 +// +// - Windows treats c:\\ the same way it treats \\. This was intended to +// allow older applications that require drive letters to support UNC paths +// like \\server\share\path, by permitting c:\\server\share\path as an +// equivalent. Since the OS treats these paths specially, FilePath needs +// to do the same. Since Windows can use either / or \ as the separator, +// FilePath treats c://, c:\\, //, and \\ all equivalently. +// Reference: +// The Old New Thing, "Why is a drive letter permitted in front of UNC +// paths (sometimes)?", available at: +// http://blogs.msdn.com/oldnewthing/archive/2005/11/22/495740.aspx + +#ifndef BASE_FILES_FILE_PATH_H_ +#define BASE_FILES_FILE_PATH_H_ + +#include + +#include +#include +#include + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/strings/string16.h" +#include "base/strings/string_piece.h" +#include "util/build_config.h" + +// Windows-style drive letter support and pathname separator characters can be +// enabled and disabled independently, to aid testing. These #defines are +// here so that the same setting can be used in both the implementation and +// in the unit test. +#if defined(OS_WIN) +#define FILE_PATH_USES_DRIVE_LETTERS +#define FILE_PATH_USES_WIN_SEPARATORS +#endif // OS_WIN + +// To print path names portably use PRIsFP (based on PRIuS and friends from +// C99 and format_macros.h) like this: +// base::StringPrintf("Path is %" PRIsFP ".\n", path.value().c_str()); +#if defined(OS_WIN) +#define PRIsFP "ls" +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +#define PRIsFP "s" +#endif // OS_WIN + +namespace base { + +class Pickle; +class PickleIterator; + +// An abstraction to isolate users from the differences between native +// pathnames on different platforms. +class FilePath { + public: +#if defined(OS_WIN) + // On Windows, for Unicode-aware applications, native pathnames are wchar_t + // arrays encoded in UTF-16. + typedef std::wstring StringType; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + // On most platforms, native pathnames are char arrays, and the encoding + // may or may not be specified. On Mac OS X, native pathnames are encoded + // in UTF-8. + typedef std::string StringType; +#endif // OS_WIN + + typedef BasicStringPiece StringPieceType; + typedef StringType::value_type CharType; + + // Null-terminated array of separators used to separate components in + // hierarchical paths. Each character in this array is a valid separator, + // but kSeparators[0] is treated as the canonical separator and will be used + // when composing pathnames. + static const CharType kSeparators[]; + + // arraysize(kSeparators). + static const size_t kSeparatorsLength; + + // A special path component meaning "this directory." + static const CharType kCurrentDirectory[]; + + // A special path component meaning "the parent directory." + static const CharType kParentDirectory[]; + + // The character used to identify a file extension. + static const CharType kExtensionSeparator; + + FilePath(); + FilePath(const FilePath& that); + explicit FilePath(StringPieceType path); + ~FilePath(); + FilePath& operator=(const FilePath& that); + + // Constructs FilePath with the contents of |that|, which is left in valid but + // unspecified state. + FilePath(FilePath&& that) noexcept; + // Replaces the contents with those of |that|, which is left in valid but + // unspecified state. + FilePath& operator=(FilePath&& that); + + bool operator==(const FilePath& that) const; + + bool operator!=(const FilePath& that) const; + + // Required for some STL containers and operations + bool operator<(const FilePath& that) const { return path_ < that.path_; } + + const StringType& value() const { return path_; } + + bool empty() const { return path_.empty(); } + + void clear() { path_.clear(); } + + // Returns true if |character| is in kSeparators. + static bool IsSeparator(CharType character); + + // Returns a vector of all of the components of the provided path. It is + // equivalent to calling DirName().value() on the path's root component, + // and BaseName().value() on each child component. + // + // To make sure this is lossless so we can differentiate absolute and + // relative paths, the root slash will be included even though no other + // slashes will be. The precise behavior is: + // + // Posix: "/foo/bar" -> [ "/", "foo", "bar" ] + // Windows: "C:\foo\bar" -> [ "C:", "\\", "foo", "bar" ] + void GetComponents(std::vector* components) const; + + // Returns true if this FilePath is a strict parent of the |child|. Absolute + // and relative paths are accepted i.e. is /foo parent to /foo/bar and + // is foo parent to foo/bar. Does not convert paths to absolute, follow + // symlinks or directory navigation (e.g. ".."). A path is *NOT* its own + // parent. + bool IsParent(const FilePath& child) const; + + // If IsParent(child) holds, appends to path (if non-NULL) the + // relative path to child and returns true. For example, if parent + // holds "/Users/johndoe/Library/Application Support", child holds + // "/Users/johndoe/Library/Application Support/Google/Chrome/Default", and + // *path holds "/Users/johndoe/Library/Caches", then after + // parent.AppendRelativePath(child, path) is called *path will hold + // "/Users/johndoe/Library/Caches/Google/Chrome/Default". Otherwise, + // returns false. + bool AppendRelativePath(const FilePath& child, FilePath* path) const; + + // Returns a FilePath corresponding to the directory containing the path + // named by this object, stripping away the file component. If this object + // only contains one component, returns a FilePath identifying + // kCurrentDirectory. If this object already refers to the root directory, + // returns a FilePath identifying the root directory. Please note that this + // doesn't resolve directory navigation, e.g. the result for "../a" is "..". + FilePath DirName() const WARN_UNUSED_RESULT; + + // Returns a FilePath corresponding to the last path component of this + // object, either a file or a directory. If this object already refers to + // the root directory, returns a FilePath identifying the root directory; + // this is the only situation in which BaseName will return an absolute path. + FilePath BaseName() const WARN_UNUSED_RESULT; + + // Returns ".jpg" for path "C:\pics\jojo.jpg", or an empty string if + // the file has no extension. If non-empty, Extension() will always start + // with precisely one ".". The following code should always work regardless + // of the value of path. For common double-extensions like .tar.gz and + // .user.js, this method returns the combined extension. For a single + // component, use FinalExtension(). + // new_path = path.RemoveExtension().value().append(path.Extension()); + // ASSERT(new_path == path.value()); + // NOTE: this is different from the original file_util implementation which + // returned the extension without a leading "." ("jpg" instead of ".jpg") + StringType Extension() const WARN_UNUSED_RESULT; + + // Returns the path's file extension, as in Extension(), but will + // never return a double extension. + // + // TODO(davidben): Check all our extension-sensitive code to see if + // we can rename this to Extension() and the other to something like + // LongExtension(), defaulting to short extensions and leaving the + // long "extensions" to logic like base::GetUniquePathNumber(). + StringType FinalExtension() const WARN_UNUSED_RESULT; + + // Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg" + // NOTE: this is slightly different from the similar file_util implementation + // which returned simply 'jojo'. + FilePath RemoveExtension() const WARN_UNUSED_RESULT; + + // Removes the path's file extension, as in RemoveExtension(), but + // ignores double extensions. + FilePath RemoveFinalExtension() const WARN_UNUSED_RESULT; + + // Inserts |suffix| after the file name portion of |path| but before the + // extension. Returns "" if BaseName() == "." or "..". + // Examples: + // path == "C:\pics\jojo.jpg" suffix == " (1)", returns "C:\pics\jojo (1).jpg" + // path == "jojo.jpg" suffix == " (1)", returns "jojo (1).jpg" + // path == "C:\pics\jojo" suffix == " (1)", returns "C:\pics\jojo (1)" + // path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)" + FilePath InsertBeforeExtension(StringPieceType suffix) const + WARN_UNUSED_RESULT; + FilePath InsertBeforeExtensionASCII(StringPiece suffix) const + WARN_UNUSED_RESULT; + + // Adds |extension| to |file_name|. Returns the current FilePath if + // |extension| is empty. Returns "" if BaseName() == "." or "..". + FilePath AddExtension(StringPieceType extension) const WARN_UNUSED_RESULT; + + // Replaces the extension of |file_name| with |extension|. If |file_name| + // does not have an extension, then |extension| is added. If |extension| is + // empty, then the extension is removed from |file_name|. + // Returns "" if BaseName() == "." or "..". + FilePath ReplaceExtension(StringPieceType extension) const WARN_UNUSED_RESULT; + + // Returns a FilePath by appending a separator and the supplied path + // component to this object's path. Append takes care to avoid adding + // excessive separators if this object's path already ends with a separator. + // If this object's path is kCurrentDirectory, a new FilePath corresponding + // only to |component| is returned. |component| must be a relative path; + // it is an error to pass an absolute path. + FilePath Append(StringPieceType component) const WARN_UNUSED_RESULT; + FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT; + + // Although Windows StringType is std::wstring, since the encoding it uses for + // paths is well defined, it can handle ASCII path components as well. + // Mac uses UTF8, and since ASCII is a subset of that, it works there as well. + // On Linux, although it can use any 8-bit encoding for paths, we assume that + // ASCII is a valid subset, regardless of the encoding, since many operating + // system paths will always be ASCII. + FilePath AppendASCII(StringPiece component) const WARN_UNUSED_RESULT; + + // Returns true if this FilePath contains an absolute path. On Windows, an + // absolute path begins with either a drive letter specification followed by + // a separator character, or with two separator characters. On POSIX + // platforms, an absolute path begins with a separator character. + bool IsAbsolute() const; + + // Returns true if the patch ends with a path separator character. + bool EndsWithSeparator() const WARN_UNUSED_RESULT; + + // Returns a copy of this FilePath that ends with a trailing separator. If + // the input path is empty, an empty FilePath will be returned. + FilePath AsEndingWithSeparator() const WARN_UNUSED_RESULT; + + // Returns a copy of this FilePath that does not end with a trailing + // separator. + FilePath StripTrailingSeparators() const WARN_UNUSED_RESULT; + + // Returns true if this FilePath contains an attempt to reference a parent + // directory (e.g. has a path component that is ".."). + bool ReferencesParent() const; + + // Return a Unicode human-readable version of this path. + // Warning: you can *not*, in general, go from a display name back to a real + // path. Only use this when displaying paths to users, not just when you + // want to stuff a string16 into some other API. + string16 LossyDisplayName() const; + + // Return the path as ASCII, or the empty string if the path is not ASCII. + // This should only be used for cases where the FilePath is representing a + // known-ASCII filename. + std::string MaybeAsASCII() const; + + // Return the path as UTF-8. + // + // This function is *unsafe* as there is no way to tell what encoding is + // used in file names on POSIX systems other than Mac and Chrome OS, + // although UTF-8 is practically used everywhere these days. To mitigate + // the encoding issue, this function internally calls + // SysNativeMBToWide() on POSIX systems other than Mac and Chrome OS, + // per assumption that the current locale's encoding is used in file + // names, but this isn't a perfect solution. + // + // Once it becomes safe to to stop caring about non-UTF-8 file names, + // the SysNativeMBToWide() hack will be removed from the code, along + // with "Unsafe" in the function name. + std::string AsUTF8Unsafe() const; + + // Similar to AsUTF8Unsafe, but returns UTF-16 instead. + string16 AsUTF16Unsafe() const; + + // Returns a FilePath object from a path name in UTF-8. This function + // should only be used for cases where you are sure that the input + // string is UTF-8. + // + // Like AsUTF8Unsafe(), this function is unsafe. This function + // internally calls SysWideToNativeMB() on POSIX systems other than Mac + // and Chrome OS, to mitigate the encoding issue. See the comment at + // AsUTF8Unsafe() for details. + static FilePath FromUTF8Unsafe(StringPiece utf8); + + // Similar to FromUTF8Unsafe, but accepts UTF-16 instead. + static FilePath FromUTF16Unsafe(StringPiece16 utf16); + + // Normalize all path separators to backslash on Windows + // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems. + FilePath NormalizePathSeparators() const; + + // Normalize all path separattors to given type on Windows + // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems. + FilePath NormalizePathSeparatorsTo(CharType separator) const; + + private: + // Remove trailing separators from this object. If the path is absolute, it + // will never be stripped any more than to refer to the absolute root + // directory, so "////" will become "/", not "". A leading pair of + // separators is never stripped, to support alternate roots. This is used to + // support UNC paths on Windows. + void StripTrailingSeparatorsInternal(); + + StringType path_; +}; + +std::ostream& operator<<(std::ostream& out, const FilePath& file_path); + +} // namespace base + +// Macros for string literal initialization of FilePath::CharType[], and for +// using a FilePath::CharType[] in a printf-style format string. +#if defined(OS_WIN) +#define FILE_PATH_LITERAL(x) L##x +#define PRFilePath "ls" +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +#define FILE_PATH_LITERAL(x) x +#define PRFilePath "s" +#endif // OS_WIN + +namespace std { + +template <> +struct hash { + typedef base::FilePath argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const& f) const { + return hash()(f.value()); + } +}; + +} // namespace std + +#endif // BASE_FILES_FILE_PATH_H_ diff --git a/src/3rdparty/gn/base/files/file_path_constants.cc b/src/3rdparty/gn/base/files/file_path_constants.cc new file mode 100644 index 00000000000..fc7d6636420 --- /dev/null +++ b/src/3rdparty/gn/base/files/file_path_constants.cc @@ -0,0 +1,25 @@ +// 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 + +#include "base/files/file_path.h" +#include "base/macros.h" + +namespace base { + +#if defined(FILE_PATH_USES_WIN_SEPARATORS) +const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/"); +#else // FILE_PATH_USES_WIN_SEPARATORS +const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/"); +#endif // FILE_PATH_USES_WIN_SEPARATORS + +const size_t FilePath::kSeparatorsLength = arraysize(kSeparators); + +const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL("."); +const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL(".."); + +const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.'); + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_posix.cc b/src/3rdparty/gn/base/files/file_posix.cc new file mode 100644 index 00000000000..ed9a5e2a8e3 --- /dev/null +++ b/src/3rdparty/gn/base/files/file_posix.cc @@ -0,0 +1,434 @@ +// 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/files/file.h" + +#include +#include +#include +#include +#include + +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#include "base/strings/utf_string_conversions.h" +#include "util/build_config.h" + +namespace base { + +// Make sure our Whence mappings match the system headers. +static_assert(File::FROM_BEGIN == SEEK_SET && File::FROM_CURRENT == SEEK_CUR && + File::FROM_END == SEEK_END, + "whence mapping must match the system headers"); + +namespace { + +#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) || \ + defined(OS_ANDROID) && __ANDROID_API__ < 21 +int CallFstat(int fd, stat_wrapper_t* sb) { + return fstat(fd, sb); +} +#else +int CallFstat(int fd, stat_wrapper_t* sb) { + return fstat64(fd, sb); +} +#endif + +// NaCl doesn't provide the following system calls, so either simulate them or +// wrap them in order to minimize the number of #ifdef's in this file. +#if !defined(OS_NACL) && !defined(OS_AIX) +bool IsOpenAppend(PlatformFile file) { + return (fcntl(file, F_GETFL) & O_APPEND) != 0; +} + +int CallFtruncate(PlatformFile file, int64_t length) { + return HANDLE_EINTR(ftruncate(file, length)); +} + +#if !defined(OS_FUCHSIA) +File::Error CallFcntlFlock(PlatformFile file, bool do_lock) { + struct flock lock; + lock.l_type = do_lock ? F_WRLCK : F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; // Lock entire file. + if (HANDLE_EINTR(fcntl(file, F_SETLK, &lock)) == -1) + return File::GetLastFileError(); + return File::FILE_OK; +} +#endif + +#else // defined(OS_NACL) && !defined(OS_AIX) + +bool IsOpenAppend(PlatformFile file) { + // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX + // standard and always appends if the file is opened with O_APPEND, just + // return false here. + return false; +} + +int CallFtruncate(PlatformFile file, int64_t length) { + NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate. + return 0; +} + +File::Error CallFcntlFlock(PlatformFile file, bool do_lock) { + NOTIMPLEMENTED(); // NaCl doesn't implement flock struct. + return File::FILE_ERROR_INVALID_OPERATION; +} +#endif // defined(OS_NACL) + +} // namespace + +void File::Info::FromStat(const stat_wrapper_t& stat_info) { + is_directory = S_ISDIR(stat_info.st_mode); + is_symbolic_link = S_ISLNK(stat_info.st_mode); + size = stat_info.st_size; + +#if defined(OS_MACOSX) + time_t last_modified_sec = stat_info.st_mtimespec.tv_sec; + int64_t last_modified_nsec = stat_info.st_mtimespec.tv_nsec; + time_t last_accessed_sec = stat_info.st_atimespec.tv_sec; + int64_t last_accessed_nsec = stat_info.st_atimespec.tv_nsec; + time_t creation_time_sec = stat_info.st_ctimespec.tv_sec; + int64_t creation_time_nsec = stat_info.st_ctimespec.tv_nsec; +#elif defined(OS_AIX) + time_t last_modified_sec = stat_info.st_mtime; + int64_t last_modified_nsec = 0; + time_t last_accessed_sec = stat_info.st_atime; + int64_t last_accessed_nsec = 0; + time_t creation_time_sec = stat_info.st_ctime; + int64_t creation_time_nsec = 0; +#elif defined(OS_POSIX) + time_t last_modified_sec = stat_info.st_mtim.tv_sec; + int64_t last_modified_nsec = stat_info.st_mtim.tv_nsec; + time_t last_accessed_sec = stat_info.st_atim.tv_sec; + int64_t last_accessed_nsec = stat_info.st_atim.tv_nsec; + time_t creation_time_sec = stat_info.st_ctim.tv_sec; + int64_t creation_time_nsec = stat_info.st_ctim.tv_nsec; +#else +#error +#endif + + constexpr uint64_t kNano = 1'000'000'000; + last_modified = last_modified_sec * kNano + last_modified_nsec; + last_accessed = last_accessed_sec * kNano + last_accessed_nsec; + creation_time = creation_time_sec * kNano + creation_time_nsec; +} + +bool File::IsValid() const { + return file_.is_valid(); +} + +PlatformFile File::GetPlatformFile() const { + return file_.get(); +} + +PlatformFile File::TakePlatformFile() { + return file_.release(); +} + +void File::Close() { + if (!IsValid()) + return; + + file_.reset(); +} + +int64_t File::Seek(Whence whence, int64_t offset) { + DCHECK(IsValid()); + + static_assert(sizeof(int64_t) == sizeof(off_t), "off_t must be 64 bits"); + return lseek(file_.get(), static_cast(offset), + static_cast(whence)); +} + +int File::Read(int64_t offset, char* data, int size) { + DCHECK(IsValid()); + if (size < 0) + return -1; + + int bytes_read = 0; + int rv; + do { + rv = HANDLE_EINTR(pread(file_.get(), data + bytes_read, size - bytes_read, + offset + bytes_read)); + if (rv <= 0) + break; + + bytes_read += rv; + } while (bytes_read < size); + + return bytes_read ? bytes_read : rv; +} + +int File::ReadAtCurrentPos(char* data, int size) { + DCHECK(IsValid()); + if (size < 0) + return -1; + + int bytes_read = 0; + int rv; + do { + rv = HANDLE_EINTR(read(file_.get(), data + bytes_read, size - bytes_read)); + if (rv <= 0) + break; + + bytes_read += rv; + } while (bytes_read < size); + + return bytes_read ? bytes_read : rv; +} + +int File::ReadNoBestEffort(int64_t offset, char* data, int size) { + DCHECK(IsValid()); + return HANDLE_EINTR(pread(file_.get(), data, size, offset)); +} + +int File::ReadAtCurrentPosNoBestEffort(char* data, int size) { + DCHECK(IsValid()); + if (size < 0) + return -1; + + return HANDLE_EINTR(read(file_.get(), data, size)); +} + +int File::Write(int64_t offset, const char* data, int size) { + if (IsOpenAppend(file_.get())) + return WriteAtCurrentPos(data, size); + + DCHECK(IsValid()); + if (size < 0) + return -1; + + int bytes_written = 0; + int rv; + do { + rv = HANDLE_EINTR(pwrite(file_.get(), data + bytes_written, + size - bytes_written, offset + bytes_written)); + if (rv <= 0) + break; + + bytes_written += rv; + } while (bytes_written < size); + + return bytes_written ? bytes_written : rv; +} + +int File::WriteAtCurrentPos(const char* data, int size) { + DCHECK(IsValid()); + if (size < 0) + return -1; + + int bytes_written = 0; + int rv; + do { + rv = HANDLE_EINTR( + write(file_.get(), data + bytes_written, size - bytes_written)); + if (rv <= 0) + break; + + bytes_written += rv; + } while (bytes_written < size); + + return bytes_written ? bytes_written : rv; +} + +int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) { + DCHECK(IsValid()); + if (size < 0) + return -1; + + return HANDLE_EINTR(write(file_.get(), data, size)); +} + +int64_t File::GetLength() { + DCHECK(IsValid()); + + stat_wrapper_t file_info; + if (CallFstat(file_.get(), &file_info)) + return -1; + + return file_info.st_size; +} + +bool File::SetLength(int64_t length) { + DCHECK(IsValid()); + + return !CallFtruncate(file_.get(), length); +} + +bool File::GetInfo(Info* info) { + DCHECK(IsValid()); + + stat_wrapper_t file_info; + if (CallFstat(file_.get(), &file_info)) + return false; + + info->FromStat(file_info); + return true; +} + +#if !defined(OS_FUCHSIA) +File::Error File::Lock() { + return CallFcntlFlock(file_.get(), true); +} + +File::Error File::Unlock() { + return CallFcntlFlock(file_.get(), false); +} +#endif + +File File::Duplicate() const { + if (!IsValid()) + return File(); + + PlatformFile other_fd = HANDLE_EINTR(dup(GetPlatformFile())); + if (other_fd == -1) + return File(File::GetLastFileError()); + + File other(other_fd); + if (async()) + other.async_ = true; + return other; +} + +// Static. +File::Error File::OSErrorToFileError(int saved_errno) { + switch (saved_errno) { + case EACCES: + case EISDIR: + case EROFS: + case EPERM: + return FILE_ERROR_ACCESS_DENIED; + case EBUSY: +#if !defined(OS_NACL) // ETXTBSY not defined by NaCl. + case ETXTBSY: +#endif + return FILE_ERROR_IN_USE; + case EEXIST: + return FILE_ERROR_EXISTS; + case EIO: + return FILE_ERROR_IO; + case ENOENT: + return FILE_ERROR_NOT_FOUND; + case ENFILE: // fallthrough + case EMFILE: + return FILE_ERROR_TOO_MANY_OPENED; + case ENOMEM: + return FILE_ERROR_NO_MEMORY; + case ENOSPC: + return FILE_ERROR_NO_SPACE; + case ENOTDIR: + return FILE_ERROR_NOT_A_DIRECTORY; + default: + // This function should only be called for errors. + DCHECK_NE(0, saved_errno); + return FILE_ERROR_FAILED; + } +} + +// NaCl doesn't implement system calls to open files directly. +#if !defined(OS_NACL) +// TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here? +void File::DoInitialize(const FilePath& path, uint32_t flags) { + DCHECK(!IsValid()); + + int open_flags = 0; + if (flags & FLAG_CREATE) + open_flags = O_CREAT | O_EXCL; + + created_ = false; + + if (flags & FLAG_CREATE_ALWAYS) { + DCHECK(!open_flags); + DCHECK(flags & FLAG_WRITE); + open_flags = O_CREAT | O_TRUNC; + } + + if (flags & FLAG_OPEN_TRUNCATED) { + DCHECK(!open_flags); + DCHECK(flags & FLAG_WRITE); + open_flags = O_TRUNC; + } + + if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) { + NOTREACHED(); + errno = EOPNOTSUPP; + error_details_ = FILE_ERROR_FAILED; + return; + } + + if (flags & FLAG_WRITE && flags & FLAG_READ) { + open_flags |= O_RDWR; + } else if (flags & FLAG_WRITE) { + open_flags |= O_WRONLY; + } else if (!(flags & FLAG_READ) && !(flags & FLAG_WRITE_ATTRIBUTES) && + !(flags & FLAG_APPEND) && !(flags & FLAG_OPEN_ALWAYS)) { + NOTREACHED(); + } + + if (flags & FLAG_TERMINAL_DEVICE) + open_flags |= O_NOCTTY | O_NDELAY; + + if (flags & FLAG_APPEND && flags & FLAG_READ) + open_flags |= O_APPEND | O_RDWR; + else if (flags & FLAG_APPEND) + open_flags |= O_APPEND | O_WRONLY; + + static_assert(O_RDONLY == 0, "O_RDONLY must equal zero"); + + int mode = S_IRUSR | S_IWUSR; + int descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode)); + + if (flags & FLAG_OPEN_ALWAYS) { + if (descriptor < 0) { + open_flags |= O_CREAT; + if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE) + open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW + + descriptor = HANDLE_EINTR(open(path.value().c_str(), open_flags, mode)); + if (descriptor >= 0) + created_ = true; + } + } + + if (descriptor < 0) { + error_details_ = File::GetLastFileError(); + return; + } + + if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE)) + created_ = true; + + if (flags & FLAG_DELETE_ON_CLOSE) + unlink(path.value().c_str()); + + async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC); + error_details_ = FILE_OK; + file_.reset(descriptor); +} +#endif // !defined(OS_NACL) + +bool File::Flush() { + DCHECK(IsValid()); + +#if defined(OS_LINUX) + return !HANDLE_EINTR(fdatasync(file_.get())); +#else + return !HANDLE_EINTR(fsync(file_.get())); +#endif +} + +void File::SetPlatformFile(PlatformFile file) { + DCHECK(!file_.is_valid()); + file_.reset(file); +} + +// static +File::Error File::GetLastFileError() { + return base::File::OSErrorToFileError(errno); +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_util.cc b/src/3rdparty/gn/base/files/file_util.cc new file mode 100644 index 00000000000..9a98a0b81e0 --- /dev/null +++ b/src/3rdparty/gn/base/files/file_util.cc @@ -0,0 +1,263 @@ +// 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/files/file_util.h" + +#if defined(OS_WIN) +#include +#endif +#include + +#include +#include + +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "util/build_config.h" + +namespace base { + +#if !defined(OS_NACL_NONSFI) +namespace { + +// The maximum number of 'uniquified' files we will try to create. +// This is used when the filename we're trying to download is already in use, +// so we create a new unique filename by appending " (nnn)" before the +// extension, where 1 <= nnn <= kMaxUniqueFiles. +// Also used by code that cleans up said files. +static const int kMaxUniqueFiles = 100; + +} // namespace + +int64_t ComputeDirectorySize(const FilePath& root_path) { + int64_t running_size = 0; + FileEnumerator file_iter(root_path, true, FileEnumerator::FILES); + while (!file_iter.Next().empty()) + running_size += file_iter.GetInfo().GetSize(); + return running_size; +} + +bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) { + // We open the file in binary format even if they are text files because + // we are just comparing that bytes are exactly same in both files and not + // doing anything smart with text formatting. + std::ifstream file1(filename1.value().c_str(), + std::ios::in | std::ios::binary); + std::ifstream file2(filename2.value().c_str(), + std::ios::in | std::ios::binary); + + // Even if both files aren't openable (and thus, in some sense, "equal"), + // any unusable file yields a result of "false". + if (!file1.is_open() || !file2.is_open()) + return false; + + const int BUFFER_SIZE = 2056; + char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE]; + do { + file1.read(buffer1, BUFFER_SIZE); + file2.read(buffer2, BUFFER_SIZE); + + if ((file1.eof() != file2.eof()) || (file1.gcount() != file2.gcount()) || + (memcmp(buffer1, buffer2, static_cast(file1.gcount())))) { + file1.close(); + file2.close(); + return false; + } + } while (!file1.eof() || !file2.eof()); + + file1.close(); + file2.close(); + return true; +} + +bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) { + std::ifstream file1(filename1.value().c_str(), std::ios::in); + std::ifstream file2(filename2.value().c_str(), std::ios::in); + + // Even if both files aren't openable (and thus, in some sense, "equal"), + // any unusable file yields a result of "false". + if (!file1.is_open() || !file2.is_open()) + return false; + + do { + std::string line1, line2; + getline(file1, line1); + getline(file2, line2); + + // Check for mismatched EOF states, or any error state. + if ((file1.eof() != file2.eof()) || file1.bad() || file2.bad()) { + return false; + } + + // Trim all '\r' and '\n' characters from the end of the line. + std::string::size_type end1 = line1.find_last_not_of("\r\n"); + if (end1 == std::string::npos) + line1.clear(); + else if (end1 + 1 < line1.length()) + line1.erase(end1 + 1); + + std::string::size_type end2 = line2.find_last_not_of("\r\n"); + if (end2 == std::string::npos) + line2.clear(); + else if (end2 + 1 < line2.length()) + line2.erase(end2 + 1); + + if (line1 != line2) + return false; + } while (!file1.eof() || !file2.eof()); + + return true; +} +#endif // !defined(OS_NACL_NONSFI) + +bool ReadFileToStringWithMaxSize(const FilePath& path, + std::string* contents, + size_t max_size) { + if (contents) + contents->clear(); + if (path.ReferencesParent()) + return false; + FILE* file = OpenFile(path, "rb"); + if (!file) { + return false; + } + + // Many files supplied in |path| have incorrect size (proc files etc). + // Hence, the file is read sequentially as opposed to a one-shot read, using + // file size as a hint for chunk size if available. + constexpr int64_t kDefaultChunkSize = 1 << 16; + int64_t chunk_size; +#if !defined(OS_NACL_NONSFI) + if (!GetFileSize(path, &chunk_size) || chunk_size <= 0) + chunk_size = kDefaultChunkSize - 1; + // We need to attempt to read at EOF for feof flag to be set so here we + // use |chunk_size| + 1. + chunk_size = std::min(chunk_size, max_size) + 1; +#else + chunk_size = kDefaultChunkSize; +#endif // !defined(OS_NACL_NONSFI) + size_t bytes_read_this_pass; + size_t bytes_read_so_far = 0; + bool read_status = true; + std::string local_contents; + local_contents.resize(chunk_size); + + while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1, + chunk_size, file)) > 0) { + if ((max_size - bytes_read_so_far) < bytes_read_this_pass) { + // Read more than max_size bytes, bail out. + bytes_read_so_far = max_size; + read_status = false; + break; + } + // In case EOF was not reached, iterate again but revert to the default + // chunk size. + if (bytes_read_so_far == 0) + chunk_size = kDefaultChunkSize; + + bytes_read_so_far += bytes_read_this_pass; + // Last fread syscall (after EOF) can be avoided via feof, which is just a + // flag check. + if (feof(file)) + break; + local_contents.resize(bytes_read_so_far + chunk_size); + } + read_status = read_status && !ferror(file); + CloseFile(file); + if (contents) { + contents->swap(local_contents); + contents->resize(bytes_read_so_far); + } + + return read_status; +} + +bool ReadFileToString(const FilePath& path, std::string* contents) { + return ReadFileToStringWithMaxSize(path, contents, + std::numeric_limits::max()); +} + +#if !defined(OS_NACL_NONSFI) +bool IsDirectoryEmpty(const FilePath& dir_path) { + FileEnumerator files(dir_path, false, + FileEnumerator::FILES | FileEnumerator::DIRECTORIES); + if (files.Next().empty()) + return true; + return false; +} + +FILE* CreateAndOpenTemporaryFile(FilePath* path) { + FilePath directory; + if (!GetTempDir(&directory)) + return nullptr; + + return CreateAndOpenTemporaryFileInDir(directory, path); +} + +bool CreateDirectory(const FilePath& full_path) { + return CreateDirectoryAndGetError(full_path, nullptr); +} + +bool GetFileSize(const FilePath& file_path, int64_t* file_size) { + File::Info info; + if (!GetFileInfo(file_path, &info)) + return false; + *file_size = info.size; + return true; +} + +#endif // !defined(OS_NACL_NONSFI) + +bool CloseFile(FILE* file) { + if (file == nullptr) + return true; + return fclose(file) == 0; +} + +#if !defined(OS_NACL_NONSFI) +bool TruncateFile(FILE* file) { + if (file == nullptr) + return false; + long current_offset = ftell(file); + if (current_offset == -1) + return false; +#if defined(OS_WIN) + int fd = _fileno(file); + if (_chsize(fd, current_offset) != 0) + return false; +#else + int fd = fileno(file); + if (ftruncate(fd, current_offset) != 0) + return false; +#endif + return true; +} + +int GetUniquePathNumber(const FilePath& path, + const FilePath::StringType& suffix) { + bool have_suffix = !suffix.empty(); + if (!PathExists(path) && + (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) { + return 0; + } + + FilePath new_path; + for (int count = 1; count <= kMaxUniqueFiles; ++count) { + new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count)); + if (!PathExists(new_path) && + (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) { + return count; + } + } + + return -1; +} +#endif // !defined(OS_NACL_NONSFI) + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_util.h b/src/3rdparty/gn/base/files/file_util.h new file mode 100644 index 00000000000..e22f40f8f53 --- /dev/null +++ b/src/3rdparty/gn/base/files/file_util.h @@ -0,0 +1,395 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains utility functions for dealing with the local +// filesystem. + +#ifndef BASE_FILES_FILE_UTIL_H_ +#define BASE_FILES_FILE_UTIL_H_ + +#include +#include +#include + +#include +#include +#include + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +#include +#include +#endif + +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/strings/string16.h" +#include "util/build_config.h" + +#if defined(OS_WIN) +#include "base/win/windows_types.h" +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" +#endif + +namespace base { + +class Environment; + +//----------------------------------------------------------------------------- +// Functions that involve filesystem access or modification: + +// Returns an absolute version of a relative path. Returns an empty path on +// error. On POSIX, this function fails if the path does not exist. This +// function can result in I/O so it can be slow. +FilePath MakeAbsoluteFilePath(const FilePath& input); + +// Returns the total number of bytes used by all the files under |root_path|. +// If the path does not exist the function returns 0. +// +// This function is implemented using the FileEnumerator class so it is not +// particularly speedy in any platform. +int64_t ComputeDirectorySize(const FilePath& root_path); + +// Deletes the given path, whether it's a file or a directory. +// If it's a directory, it's perfectly happy to delete all of the +// directory's contents. Passing true to recursive deletes +// subdirectories and their contents as well. +// Returns true if successful, false otherwise. It is considered successful +// to attempt to delete a file that does not exist. +// +// In posix environment and if |path| is a symbolic link, this deletes only +// the symlink. (even if the symlink points to a non-existent file) +// +// WARNING: USING THIS WITH recursive==true IS EQUIVALENT +// TO "rm -rf", SO USE WITH CAUTION. +bool DeleteFile(const FilePath& path, bool recursive); + +#if defined(OS_WIN) +// Schedules to delete the given path, whether it's a file or a directory, until +// the operating system is restarted. +// Note: +// 1) The file/directory to be deleted should exist in a temp folder. +// 2) The directory to be deleted must be empty. +bool DeleteFileAfterReboot(const FilePath& path); +#endif + +// Renames file |from_path| to |to_path|. Both paths must be on the same +// volume, or the function will fail. Destination file will be created +// if it doesn't exist. Prefer this function over Move when dealing with +// temporary files. On Windows it preserves attributes of the target file. +// Returns true on success, leaving *error unchanged. +// Returns false on failure and sets *error appropriately, if it is non-NULL. +bool ReplaceFile(const FilePath& from_path, + const FilePath& to_path, + File::Error* error); + +// Returns true if the given path exists on the local filesystem, +// false otherwise. +bool PathExists(const FilePath& path); + +// Returns true if the given path is writable by the user, false otherwise. +bool PathIsWritable(const FilePath& path); + +// Returns true if the given path exists and is a directory, false otherwise. +bool DirectoryExists(const FilePath& path); + +// Returns true if the contents of the two files given are equal, false +// otherwise. If either file can't be read, returns false. +bool ContentsEqual(const FilePath& filename1, const FilePath& filename2); + +// Returns true if the contents of the two text files given are equal, false +// otherwise. This routine treats "\r\n" and "\n" as equivalent. +bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2); + +// Reads the file at |path| into |contents| and returns true on success and +// false on error. For security reasons, a |path| containing path traversal +// components ('..') is treated as a read error and |contents| is set to empty. +// In case of I/O error, |contents| holds the data that could be read from the +// file before the error occurred. +// |contents| may be NULL, in which case this function is useful for its side +// effect of priming the disk cache (could be used for unit tests). +bool ReadFileToString(const FilePath& path, std::string* contents); + +// Reads the file at |path| into |contents| and returns true on success and +// false on error. For security reasons, a |path| containing path traversal +// components ('..') is treated as a read error and |contents| is set to empty. +// In case of I/O error, |contents| holds the data that could be read from the +// file before the error occurred. When the file size exceeds |max_size|, the +// function returns false with |contents| holding the file truncated to +// |max_size|. +// |contents| may be NULL, in which case this function is useful for its side +// effect of priming the disk cache (could be used for unit tests). +bool ReadFileToStringWithMaxSize(const FilePath& path, + std::string* contents, + size_t max_size); + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) + +// Read exactly |bytes| bytes from file descriptor |fd|, storing the result +// in |buffer|. This function is protected against EINTR and partial reads. +// Returns true iff |bytes| bytes have been successfully read from |fd|. +bool ReadFromFD(int fd, char* buffer, size_t bytes); + +// Performs the same function as CreateAndOpenTemporaryFileInDir(), but returns +// the file-descriptor directly, rather than wrapping it into a FILE. Returns +// -1 on failure. +int CreateAndOpenFdForTemporaryFileInDir(const FilePath& dir, FilePath* path); + +#endif // OS_POSIX || OS_FUCHSIA + +#if defined(OS_POSIX) + +// Creates a symbolic link at |symlink| pointing to |target|. Returns +// false on failure. +bool CreateSymbolicLink(const FilePath& target, const FilePath& symlink); + +// Reads the given |symlink| and returns where it points to in |target|. +// Returns false upon failure. +bool ReadSymbolicLink(const FilePath& symlink, FilePath* target); + +// Bits and masks of the file permission. +enum FilePermissionBits { + FILE_PERMISSION_MASK = S_IRWXU | S_IRWXG | S_IRWXO, + FILE_PERMISSION_USER_MASK = S_IRWXU, + FILE_PERMISSION_GROUP_MASK = S_IRWXG, + FILE_PERMISSION_OTHERS_MASK = S_IRWXO, + + FILE_PERMISSION_READ_BY_USER = S_IRUSR, + FILE_PERMISSION_WRITE_BY_USER = S_IWUSR, + FILE_PERMISSION_EXECUTE_BY_USER = S_IXUSR, + FILE_PERMISSION_READ_BY_GROUP = S_IRGRP, + FILE_PERMISSION_WRITE_BY_GROUP = S_IWGRP, + FILE_PERMISSION_EXECUTE_BY_GROUP = S_IXGRP, + FILE_PERMISSION_READ_BY_OTHERS = S_IROTH, + FILE_PERMISSION_WRITE_BY_OTHERS = S_IWOTH, + FILE_PERMISSION_EXECUTE_BY_OTHERS = S_IXOTH, +}; + +// Reads the permission of the given |path|, storing the file permission +// bits in |mode|. If |path| is symbolic link, |mode| is the permission of +// a file which the symlink points to. +bool GetPosixFilePermissions(const FilePath& path, int* mode); +// Sets the permission of the given |path|. If |path| is symbolic link, sets +// the permission of a file which the symlink points to. +bool SetPosixFilePermissions(const FilePath& path, int mode); + +// Returns true iff |executable| can be found in any directory specified by the +// environment variable in |env|. +bool ExecutableExistsInPath(Environment* env, + const FilePath::StringType& executable); + +#endif // OS_POSIX + +// Returns true if the given directory is empty +bool IsDirectoryEmpty(const FilePath& dir_path); + +// Get the temporary directory provided by the system. +// +// WARNING: In general, you should use CreateTemporaryFile variants below +// instead of this function. Those variants will ensure that the proper +// permissions are set so that other users on the system can't edit them while +// they're open (which can lead to security issues). +bool GetTempDir(FilePath* path); + +// Creates a temporary file. The full path is placed in |path|, and the +// function returns true if was successful in creating the file. The file will +// be empty and all handles closed after this function returns. +bool CreateTemporaryFile(FilePath* path); + +// Same as CreateTemporaryFile but the file is created in |dir|. +bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file); + +// Create and open a temporary file. File is opened for read/write. +// The full path is placed in |path|. +// Returns a handle to the opened file or NULL if an error occurred. +FILE* CreateAndOpenTemporaryFile(FilePath* path); + +// Similar to CreateAndOpenTemporaryFile, but the file is created in |dir|. +FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path); + +// Create a new directory. If prefix is provided, the new directory name is in +// the format of prefixyyyy. +// NOTE: prefix is ignored in the POSIX implementation. +// If success, return true and output the full path of the directory created. +bool CreateNewTempDirectory(const FilePath::StringType& prefix, + FilePath* new_temp_path); + +// Create a directory within another directory. +// Extra characters will be appended to |prefix| to ensure that the +// new directory does not have the same name as an existing directory. +bool CreateTemporaryDirInDir(const FilePath& base_dir, + const FilePath::StringType& prefix, + FilePath* new_dir); + +// Creates a directory, as well as creating any parent directories, if they +// don't exist. Returns 'true' on successful creation, or if the directory +// already exists. The directory is only readable by the current user. +// Returns true on success, leaving *error unchanged. +// Returns false on failure and sets *error appropriately, if it is non-NULL. +bool CreateDirectoryAndGetError(const FilePath& full_path, File::Error* error); + +// Backward-compatible convenience method for the above. +bool CreateDirectory(const FilePath& full_path); + +// Returns the file size. Returns true on success. +bool GetFileSize(const FilePath& file_path, int64_t* file_size); + +// Sets |real_path| to |path| with symbolic links and junctions expanded. +// On windows, make sure the path starts with a lettered drive. +// |path| must reference a file. Function will fail if |path| points to +// a directory or to a nonexistent path. On windows, this function will +// fail if |path| is a junction or symlink that points to an empty file, +// or if |real_path| would be longer than MAX_PATH characters. +bool NormalizeFilePath(const FilePath& path, FilePath* real_path); + +#if defined(OS_WIN) + +// Given a path in NT native form ("\Device\HarddiskVolumeXX\..."), +// return in |drive_letter_path| the equivalent path that starts with +// a drive letter ("C:\..."). Return false if no such path exists. +bool DevicePathToDriveLetterPath(const FilePath& device_path, + FilePath* drive_letter_path); + +// Given an existing file in |path|, set |real_path| to the path +// in native NT format, of the form "\Device\HarddiskVolumeXX\..". +// Returns false if the path can not be found. Empty files cannot +// be resolved with this function. +bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path); +#endif + +// This function will return if the given file is a symlink or not. +bool IsLink(const FilePath& file_path); + +// Returns information about the given file path. +bool GetFileInfo(const FilePath& file_path, File::Info* info); + +// Wrapper for fopen-like calls. Returns non-NULL FILE* on success. The +// underlying file descriptor (POSIX) or handle (Windows) is unconditionally +// configured to not be propagated to child processes. +FILE* OpenFile(const FilePath& filename, const char* mode); + +// Closes file opened by OpenFile. Returns true on success. +bool CloseFile(FILE* file); + +// Associates a standard FILE stream with an existing File. Note that this +// functions take ownership of the existing File. +FILE* FileToFILE(File file, const char* mode); + +// Truncates an open file to end at the location of the current file pointer. +// This is a cross-platform analog to Windows' SetEndOfFile() function. +bool TruncateFile(FILE* file); + +// Reads at most the given number of bytes from the file into the buffer. +// Returns the number of read bytes, or -1 on error. +int ReadFile(const FilePath& filename, char* data, int max_size); + +// Writes the given buffer into the file, overwriting any data that was +// previously there. Returns the number of bytes written, or -1 on error. +int WriteFile(const FilePath& filename, const char* data, int size); + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +// Appends |data| to |fd|. Does not close |fd| when done. Returns true iff +// |size| bytes of |data| were written to |fd|. +bool WriteFileDescriptor(const int fd, const char* data, int size); +#endif + +// Appends |data| to |filename|. Returns true iff |size| bytes of |data| were +// written to |filename|. +bool AppendToFile(const FilePath& filename, const char* data, int size); + +// Gets the current working directory for the process. +bool GetCurrentDirectory(FilePath* path); + +// Sets the current working directory for the process. +bool SetCurrentDirectory(const FilePath& path); + +// Attempts to find a number that can be appended to the |path| to make it +// unique. If |path| does not exist, 0 is returned. If it fails to find such +// a number, -1 is returned. If |suffix| is not empty, also checks the +// existence of it with the given suffix. +int GetUniquePathNumber(const FilePath& path, + const FilePath::StringType& suffix); + +// Sets the given |fd| to non-blocking mode. +// Returns true if it was able to set it in the non-blocking mode, otherwise +// false. +bool SetNonBlocking(int fd); + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +// Creates a non-blocking, close-on-exec pipe. +// This creates a non-blocking pipe that is not intended to be shared with any +// child process. This will be done atomically if the operating system supports +// it. Returns true if it was able to create the pipe, otherwise false. +bool CreateLocalNonBlockingPipe(int fds[2]); + +// Sets the given |fd| to close-on-exec mode. +// Returns true if it was able to set it in the close-on-exec mode, otherwise +// false. +bool SetCloseOnExec(int fd); + +// Test that |path| can only be changed by a given user and members of +// a given set of groups. +// Specifically, test that all parts of |path| under (and including) |base|: +// * Exist. +// * Are owned by a specific user. +// * Are not writable by all users. +// * Are owned by a member of a given set of groups, or are not writable by +// their group. +// * Are not symbolic links. +// This is useful for checking that a config file is administrator-controlled. +// |base| must contain |path|. +bool VerifyPathControlledByUser(const base::FilePath& base, + const base::FilePath& path, + uid_t owner_uid, + const std::set& group_gids); +#endif // defined(OS_POSIX) || defined(OS_FUCHSIA) + +#if defined(OS_MACOSX) && !defined(OS_IOS) +// Is |path| writable only by a user with administrator privileges? +// This function uses Mac OS conventions. The super user is assumed to have +// uid 0, and the administrator group is assumed to be named "admin". +// Testing that |path|, and every parent directory including the root of +// the filesystem, are owned by the superuser, controlled by the group +// "admin", are not writable by all users, and contain no symbolic links. +// Will return false if |path| does not exist. +bool VerifyPathControlledByAdmin(const base::FilePath& path); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + +// Returns the maximum length of path component on the volume containing +// the directory |path|, in the number of FilePath::CharType, or -1 on failure. +int GetMaximumPathComponentLength(const base::FilePath& path); + +#if defined(OS_LINUX) || defined(OS_AIX) +// Broad categories of file systems as returned by statfs() on Linux. +enum FileSystemType { + FILE_SYSTEM_UNKNOWN, // statfs failed. + FILE_SYSTEM_0, // statfs.f_type == 0 means unknown, may indicate AFS. + FILE_SYSTEM_ORDINARY, // on-disk filesystem like ext2 + FILE_SYSTEM_NFS, + FILE_SYSTEM_SMB, + FILE_SYSTEM_CODA, + FILE_SYSTEM_MEMORY, // in-memory file system + FILE_SYSTEM_CGROUP, // cgroup control. + FILE_SYSTEM_OTHER, // any other value. + FILE_SYSTEM_TYPE_COUNT +}; + +// Attempts determine the FileSystemType for |path|. +// Returns false if |path| doesn't exist. +bool GetFileSystemType(const FilePath& path, FileSystemType* type); +#endif + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +// Get a temporary directory for shared memory files. The directory may depend +// on whether the destination is intended for executable files, which in turn +// depends on how /dev/shmem was mounted. As a result, you must supply whether +// you intend to create executable shmem segments so this function can find +// an appropriate location. +bool GetShmemTempDir(bool executable, FilePath* path); +#endif + +} // namespace base + +#endif // BASE_FILES_FILE_UTIL_H_ diff --git a/src/3rdparty/gn/base/files/file_util_linux.cc b/src/3rdparty/gn/base/files/file_util_linux.cc new file mode 100644 index 00000000000..b230fd96484 --- /dev/null +++ b/src/3rdparty/gn/base/files/file_util_linux.cc @@ -0,0 +1,63 @@ +// 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/files/file_util.h" + +#include +#include +#include + +#include "base/files/file_path.h" + +namespace base { + +bool GetFileSystemType(const FilePath& path, FileSystemType* type) { + struct statfs statfs_buf; + if (statfs(path.value().c_str(), &statfs_buf) < 0) { + if (errno == ENOENT) + return false; + *type = FILE_SYSTEM_UNKNOWN; + return true; + } + + // Not all possible |statfs_buf.f_type| values are in linux/magic.h. + // Missing values are copied from the statfs man page. + switch (statfs_buf.f_type) { + case 0: + *type = FILE_SYSTEM_0; + break; + case EXT2_SUPER_MAGIC: // Also ext3 and ext4 + case MSDOS_SUPER_MAGIC: + case REISERFS_SUPER_MAGIC: + case BTRFS_SUPER_MAGIC: + case 0x5346544E: // NTFS + case 0x58465342: // XFS + case 0x3153464A: // JFS + *type = FILE_SYSTEM_ORDINARY; + break; + case NFS_SUPER_MAGIC: + *type = FILE_SYSTEM_NFS; + break; + case SMB_SUPER_MAGIC: + case 0xFF534D42: // CIFS + *type = FILE_SYSTEM_SMB; + break; + case CODA_SUPER_MAGIC: + *type = FILE_SYSTEM_CODA; + break; + case HUGETLBFS_MAGIC: + case RAMFS_MAGIC: + case TMPFS_MAGIC: + *type = FILE_SYSTEM_MEMORY; + break; + case CGROUP_SUPER_MAGIC: + *type = FILE_SYSTEM_CGROUP; + break; + default: + *type = FILE_SYSTEM_OTHER; + } + return true; +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_util_posix.cc b/src/3rdparty/gn/base/files/file_util_posix.cc new file mode 100644 index 00000000000..eb07e64f8e2 --- /dev/null +++ b/src/3rdparty/gn/base/files/file_util_posix.cc @@ -0,0 +1,787 @@ +// 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/files/file_util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "base/command_line.h" +#include "base/containers/stack.h" +#include "base/environment.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/files/scoped_file.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/posix/eintr_wrapper.h" +#include "base/stl_util.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "util/build_config.h" + +#if defined(OS_MACOSX) +#include +#endif + +#if !defined(OS_IOS) +#include +#endif + +// We need to do this on AIX due to some inconsistencies in how AIX +// handles XOPEN_SOURCE and ALL_SOURCE. +#if defined(OS_AIX) +extern "C" char* mkdtemp(char* path); +#endif + +namespace base { + +namespace { + +#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) || \ + defined(OS_ANDROID) && __ANDROID_API__ < 21 +int CallStat(const char* path, stat_wrapper_t* sb) { + return stat(path, sb); +} +int CallLstat(const char* path, stat_wrapper_t* sb) { + return lstat(path, sb); +} +#else +int CallStat(const char* path, stat_wrapper_t* sb) { + return stat64(path, sb); +} +int CallLstat(const char* path, stat_wrapper_t* sb) { + return lstat64(path, sb); +} +#endif + +#if !defined(OS_NACL_NONSFI) +// Helper for VerifyPathControlledByUser. +bool VerifySpecificPathControlledByUser(const FilePath& path, + uid_t owner_uid, + const std::set& group_gids) { + stat_wrapper_t stat_info; + if (CallLstat(path.value().c_str(), &stat_info) != 0) { + DPLOG(ERROR) << "Failed to get information on path " << path.value(); + return false; + } + + if (S_ISLNK(stat_info.st_mode)) { + DLOG(ERROR) << "Path " << path.value() << " is a symbolic link."; + return false; + } + + if (stat_info.st_uid != owner_uid) { + DLOG(ERROR) << "Path " << path.value() << " is owned by the wrong user."; + return false; + } + + if ((stat_info.st_mode & S_IWGRP) && + !ContainsKey(group_gids, stat_info.st_gid)) { + DLOG(ERROR) << "Path " << path.value() + << " is writable by an unprivileged group."; + return false; + } + + if (stat_info.st_mode & S_IWOTH) { + DLOG(ERROR) << "Path " << path.value() << " is writable by any user."; + return false; + } + + return true; +} + +std::string TempFileName() { + return std::string(".org.chromium.Chromium.XXXXXX"); +} + +#if defined(OS_LINUX) || defined(OS_AIX) +// Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC. +// This depends on the mount options used for /dev/shm, which vary among +// different Linux distributions and possibly local configuration. It also +// depends on details of kernel--ChromeOS uses the noexec option for /dev/shm +// but its kernel allows mprotect with PROT_EXEC anyway. +bool DetermineDevShmExecutable() { + bool result = false; + FilePath path; + + ScopedFD fd( + CreateAndOpenFdForTemporaryFileInDir(FilePath("/dev/shm"), &path)); + if (fd.is_valid()) { + DeleteFile(path, false); + long sysconf_result = sysconf(_SC_PAGESIZE); + CHECK_GE(sysconf_result, 0); + size_t pagesize = static_cast(sysconf_result); + CHECK_GE(sizeof(pagesize), sizeof(sysconf_result)); + void* mapping = mmap(nullptr, pagesize, PROT_READ, MAP_SHARED, fd.get(), 0); + if (mapping != MAP_FAILED) { + if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0) + result = true; + munmap(mapping, pagesize); + } + } + return result; +} +#endif // defined(OS_LINUX) || defined(OS_AIX) + +bool AdvanceEnumeratorWithStat(FileEnumerator* traversal, + FilePath* out_next_path, + struct stat* out_next_stat) { + DCHECK(out_next_path); + DCHECK(out_next_stat); + *out_next_path = traversal->Next(); + if (out_next_path->empty()) + return false; + + *out_next_stat = traversal->GetInfo().stat(); + return true; +} + +bool CopyFileContents(File* infile, File* outfile) { + static constexpr size_t kBufferSize = 32768; + std::vector buffer(kBufferSize); + + for (;;) { + ssize_t bytes_read = infile->ReadAtCurrentPos(buffer.data(), buffer.size()); + if (bytes_read < 0) + return false; + if (bytes_read == 0) + return true; + // Allow for partial writes + ssize_t bytes_written_per_read = 0; + do { + ssize_t bytes_written_partial = outfile->WriteAtCurrentPos( + &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read); + if (bytes_written_partial < 0) + return false; + + bytes_written_per_read += bytes_written_partial; + } while (bytes_written_per_read < bytes_read); + } + + NOTREACHED(); + return false; +} +#endif // !defined(OS_NACL_NONSFI) + +#if !defined(OS_MACOSX) +// Appends |mode_char| to |mode| before the optional character set encoding; see +// https://www.gnu.org/software/libc/manual/html_node/Opening-Streams.html for +// details. +std::string AppendModeCharacter(StringPiece mode, char mode_char) { + std::string result(mode.as_string()); + size_t comma_pos = result.find(','); + result.insert(comma_pos == std::string::npos ? result.length() : comma_pos, 1, + mode_char); + return result; +} +#endif + +} // namespace + +#if !defined(OS_NACL_NONSFI) +FilePath MakeAbsoluteFilePath(const FilePath& input) { + char full_path[PATH_MAX]; + if (realpath(input.value().c_str(), full_path) == nullptr) + return FilePath(); + return FilePath(full_path); +} + +// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*" +// which works both with and without the recursive flag. I'm not sure we need +// that functionality. If not, remove from file_util_win.cc, otherwise add it +// here. +bool DeleteFile(const FilePath& path, bool recursive) { + const char* path_str = path.value().c_str(); + stat_wrapper_t file_info; + if (CallLstat(path_str, &file_info) != 0) { + // The Windows version defines this condition as success. + return (errno == ENOENT || errno == ENOTDIR); + } + if (!S_ISDIR(file_info.st_mode)) + return (unlink(path_str) == 0); + if (!recursive) + return (rmdir(path_str) == 0); + + bool success = true; + stack directories; + directories.push(path.value()); + FileEnumerator traversal(path, true, + FileEnumerator::FILES | FileEnumerator::DIRECTORIES | + FileEnumerator::SHOW_SYM_LINKS); + for (FilePath current = traversal.Next(); !current.empty(); + current = traversal.Next()) { + if (traversal.GetInfo().IsDirectory()) + directories.push(current.value()); + else + success &= (unlink(current.value().c_str()) == 0); + } + + while (!directories.empty()) { + FilePath dir = FilePath(directories.top()); + directories.pop(); + success &= (rmdir(dir.value().c_str()) == 0); + } + return success; +} + +bool ReplaceFile(const FilePath& from_path, + const FilePath& to_path, + File::Error* error) { + if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) + return true; + if (error) + *error = File::GetLastFileError(); + return false; +} +#endif // !defined(OS_NACL_NONSFI) + +bool CreateLocalNonBlockingPipe(int fds[2]) { +#if defined(OS_LINUX) + return pipe2(fds, O_CLOEXEC | O_NONBLOCK) == 0; +#else + int raw_fds[2]; + if (pipe(raw_fds) != 0) + return false; + ScopedFD fd_out(raw_fds[0]); + ScopedFD fd_in(raw_fds[1]); + if (!SetCloseOnExec(fd_out.get())) + return false; + if (!SetCloseOnExec(fd_in.get())) + return false; + if (!SetNonBlocking(fd_out.get())) + return false; + if (!SetNonBlocking(fd_in.get())) + return false; + fds[0] = fd_out.release(); + fds[1] = fd_in.release(); + return true; +#endif +} + +bool SetNonBlocking(int fd) { + const int flags = fcntl(fd, F_GETFL); + if (flags == -1) + return false; + if (flags & O_NONBLOCK) + return true; + if (HANDLE_EINTR(fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) + return false; + return true; +} + +bool SetCloseOnExec(int fd) { +#if defined(OS_NACL_NONSFI) + const int flags = 0; +#else + const int flags = fcntl(fd, F_GETFD); + if (flags == -1) + return false; + if (flags & FD_CLOEXEC) + return true; +#endif // defined(OS_NACL_NONSFI) + if (HANDLE_EINTR(fcntl(fd, F_SETFD, flags | FD_CLOEXEC)) == -1) + return false; + return true; +} + +bool PathExists(const FilePath& path) { + return access(path.value().c_str(), F_OK) == 0; +} + +#if !defined(OS_NACL_NONSFI) +bool PathIsWritable(const FilePath& path) { + return access(path.value().c_str(), W_OK) == 0; +} +#endif // !defined(OS_NACL_NONSFI) + +bool DirectoryExists(const FilePath& path) { + stat_wrapper_t file_info; + if (CallStat(path.value().c_str(), &file_info) != 0) + return false; + return S_ISDIR(file_info.st_mode); +} + +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; +} + +#if !defined(OS_NACL_NONSFI) + +int CreateAndOpenFdForTemporaryFileInDir(const FilePath& directory, + FilePath* path) { + *path = directory.Append(TempFileName()); + const std::string& tmpdir_string = path->value(); + // this should be OK since mkstemp just replaces characters in place + char* buffer = const_cast(tmpdir_string.c_str()); + + return HANDLE_EINTR(mkstemp(buffer)); +} + +#if !defined(OS_FUCHSIA) +bool CreateSymbolicLink(const FilePath& target_path, + const FilePath& symlink_path) { + DCHECK(!symlink_path.empty()); + DCHECK(!target_path.empty()); + return ::symlink(target_path.value().c_str(), symlink_path.value().c_str()) != + -1; +} + +bool ReadSymbolicLink(const FilePath& symlink_path, FilePath* target_path) { + DCHECK(!symlink_path.empty()); + DCHECK(target_path); + char buf[PATH_MAX]; + ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf)); + + if (count <= 0) { + target_path->clear(); + return false; + } + + *target_path = FilePath(FilePath::StringType(buf, count)); + return true; +} + +bool GetPosixFilePermissions(const FilePath& path, int* mode) { + DCHECK(mode); + + stat_wrapper_t file_info; + // Uses stat(), because on symbolic link, lstat() does not return valid + // permission bits in st_mode + if (CallStat(path.value().c_str(), &file_info) != 0) + return false; + + *mode = file_info.st_mode & FILE_PERMISSION_MASK; + return true; +} + +bool SetPosixFilePermissions(const FilePath& path, int mode) { + DCHECK_EQ(mode & ~FILE_PERMISSION_MASK, 0); + + // Calls stat() so that we can preserve the higher bits like S_ISGID. + stat_wrapper_t stat_buf; + if (CallStat(path.value().c_str(), &stat_buf) != 0) + return false; + + // Clears the existing permission bits, and adds the new ones. + mode_t updated_mode_bits = stat_buf.st_mode & ~FILE_PERMISSION_MASK; + updated_mode_bits |= mode & FILE_PERMISSION_MASK; + + if (HANDLE_EINTR(chmod(path.value().c_str(), updated_mode_bits)) != 0) + return false; + + return true; +} + +bool ExecutableExistsInPath(Environment* env, + const FilePath::StringType& executable) { + std::string path; + if (!env->GetVar("PATH", &path)) { + LOG(ERROR) << "No $PATH variable. Assuming no " << executable << "."; + return false; + } + + for (const StringPiece& cur_path : + SplitStringPiece(path, ":", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) { + FilePath file(cur_path); + int permissions; + if (GetPosixFilePermissions(file.Append(executable), &permissions) && + (permissions & FILE_PERMISSION_EXECUTE_BY_USER)) + return true; + } + return false; +} + +#endif // !OS_FUCHSIA + +bool GetTempDir(FilePath* path) { + const char* tmp = getenv("TMPDIR"); + if (tmp) { + *path = FilePath(tmp); + return true; + } + + *path = FilePath("/tmp"); + return true; +} + +#if !defined(OS_MACOSX) // Mac implementation is in file_util_mac.mm. +FilePath GetHomeDir() { + const char* home_dir = getenv("HOME"); + if (home_dir && home_dir[0]) + return FilePath(home_dir); + + FilePath rv; + if (GetTempDir(&rv)) + return rv; + + // Last resort. + return FilePath("/tmp"); +} +#endif // !defined(OS_MACOSX) + +bool CreateTemporaryFile(FilePath* path) { + FilePath directory; + if (!GetTempDir(&directory)) + return false; + int fd = CreateAndOpenFdForTemporaryFileInDir(directory, path); + if (fd < 0) + return false; + close(fd); + return true; +} + +FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { + int fd = CreateAndOpenFdForTemporaryFileInDir(dir, path); + if (fd < 0) + return nullptr; + + FILE* file = fdopen(fd, "a+"); + if (!file) + close(fd); + return file; +} + +bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) { + int fd = CreateAndOpenFdForTemporaryFileInDir(dir, temp_file); + return ((fd >= 0) && !IGNORE_EINTR(close(fd))); +} + +static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir, + const FilePath::StringType& name_tmpl, + FilePath* new_dir) { + DCHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos) + << "Directory name template must contain \"XXXXXX\"."; + + FilePath sub_dir = base_dir.Append(name_tmpl); + std::string sub_dir_string = sub_dir.value(); + + // this should be OK since mkdtemp just replaces characters in place + char* buffer = const_cast(sub_dir_string.c_str()); + char* dtemp = mkdtemp(buffer); + if (!dtemp) { + DPLOG(ERROR) << "mkdtemp"; + return false; + } + *new_dir = FilePath(dtemp); + return true; +} + +bool CreateTemporaryDirInDir(const FilePath& base_dir, + const FilePath::StringType& prefix, + FilePath* new_dir) { + FilePath::StringType mkdtemp_template = prefix; + mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX")); + return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir); +} + +bool CreateNewTempDirectory(const FilePath::StringType& prefix, + FilePath* new_temp_path) { + FilePath tmpdir; + if (!GetTempDir(&tmpdir)) + return false; + + return CreateTemporaryDirInDirImpl(tmpdir, TempFileName(), new_temp_path); +} + +bool CreateDirectoryAndGetError(const FilePath& full_path, File::Error* error) { + std::vector subpaths; + + // Collect a list of all parent directories. + FilePath last_path = full_path; + subpaths.push_back(full_path); + for (FilePath path = full_path.DirName(); path.value() != last_path.value(); + path = path.DirName()) { + subpaths.push_back(path); + last_path = path; + } + + // Iterate through the parents and create the missing ones. + for (std::vector::reverse_iterator i = subpaths.rbegin(); + i != subpaths.rend(); ++i) { + if (DirectoryExists(*i)) + continue; + if (mkdir(i->value().c_str(), 0700) == 0) + continue; + // Mkdir failed, but it might have failed with EEXIST, or some other error + // due to the the directory appearing out of thin air. This can occur if + // two processes are trying to create the same file system tree at the same + // time. Check to see if it exists and make sure it is a directory. + int saved_errno = errno; + if (!DirectoryExists(*i)) { + if (error) + *error = File::OSErrorToFileError(saved_errno); + return false; + } + } + return true; +} + +bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) { + FilePath real_path_result = MakeAbsoluteFilePath(path); + if (real_path_result.empty()) + return false; + + // To be consistant with windows, fail if |real_path_result| is a + // directory. + if (DirectoryExists(real_path_result)) + return false; + + *normalized_path = real_path_result; + return true; +} + +// TODO(rkc): Refactor GetFileInfo and FileEnumerator to handle symlinks +// correctly. http://code.google.com/p/chromium-os/issues/detail?id=15948 +bool IsLink(const FilePath& file_path) { + stat_wrapper_t st; + // If we can't lstat the file, it's safe to assume that the file won't at + // least be a 'followable' link. + if (CallLstat(file_path.value().c_str(), &st) != 0) + return false; + return S_ISLNK(st.st_mode); +} + +bool GetFileInfo(const FilePath& file_path, File::Info* results) { + stat_wrapper_t file_info; + if (CallStat(file_path.value().c_str(), &file_info) != 0) + return false; + + results->FromStat(file_info); + return true; +} +#endif // !defined(OS_NACL_NONSFI) + +FILE* OpenFile(const FilePath& filename, const char* mode) { + // 'e' is unconditionally added below, so be sure there is not one already + // present before a comma in |mode|. + DCHECK( + strchr(mode, 'e') == nullptr || + (strchr(mode, ',') != nullptr && strchr(mode, 'e') > strchr(mode, ','))); + FILE* result = nullptr; +#if defined(OS_MACOSX) + // macOS does not provide a mode character to set O_CLOEXEC; see + // https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man3/fopen.3.html. + const char* the_mode = mode; +#else + std::string mode_with_e(AppendModeCharacter(mode, 'e')); + const char* the_mode = mode_with_e.c_str(); +#endif + do { + result = fopen(filename.value().c_str(), the_mode); + } while (!result && errno == EINTR); +#if defined(OS_MACOSX) + // Mark the descriptor as close-on-exec. + if (result) + SetCloseOnExec(fileno(result)); +#endif + return result; +} + +// NaCl doesn't implement system calls to open files directly. +#if !defined(OS_NACL) +FILE* FileToFILE(File file, const char* mode) { + FILE* stream = fdopen(file.GetPlatformFile(), mode); + if (stream) + file.TakePlatformFile(); + return stream; +} +#endif // !defined(OS_NACL) + +int ReadFile(const FilePath& filename, char* data, int max_size) { + int fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY)); + if (fd < 0) + return -1; + + ssize_t bytes_read = HANDLE_EINTR(read(fd, data, max_size)); + if (IGNORE_EINTR(close(fd)) < 0) + return -1; + return bytes_read; +} + +int WriteFile(const FilePath& filename, const char* data, int size) { + int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666)); + if (fd < 0) + return -1; + + int bytes_written = WriteFileDescriptor(fd, data, size) ? size : -1; + if (IGNORE_EINTR(close(fd)) < 0) + return -1; + return bytes_written; +} + +bool WriteFileDescriptor(const int fd, const char* data, int size) { + // Allow for partial writes. + ssize_t bytes_written_total = 0; + for (ssize_t bytes_written_partial = 0; bytes_written_total < size; + bytes_written_total += bytes_written_partial) { + bytes_written_partial = HANDLE_EINTR( + write(fd, data + bytes_written_total, size - bytes_written_total)); + if (bytes_written_partial < 0) + return false; + } + + return true; +} + +#if !defined(OS_NACL_NONSFI) + +bool AppendToFile(const FilePath& filename, const char* data, int size) { + bool ret = true; + int fd = HANDLE_EINTR(open(filename.value().c_str(), O_WRONLY | O_APPEND)); + if (fd < 0) { + return false; + } + + // This call will either write all of the data or return false. + if (!WriteFileDescriptor(fd, data, size)) { + ret = false; + } + + if (IGNORE_EINTR(close(fd)) < 0) { + return false; + } + + return ret; +} + +bool GetCurrentDirectory(FilePath* dir) { + char system_buffer[PATH_MAX] = ""; + if (!getcwd(system_buffer, sizeof(system_buffer))) { + NOTREACHED(); + return false; + } + *dir = FilePath(system_buffer); + return true; +} + +bool SetCurrentDirectory(const FilePath& path) { + return chdir(path.value().c_str()) == 0; +} + +bool VerifyPathControlledByUser(const FilePath& base, + const FilePath& path, + uid_t owner_uid, + const std::set& group_gids) { + if (base != path && !base.IsParent(path)) { + DLOG(ERROR) << "|base| must be a subdirectory of |path|. base = \"" + << base.value() << "\", path = \"" << path.value() << "\""; + return false; + } + + std::vector base_components; + std::vector path_components; + + base.GetComponents(&base_components); + path.GetComponents(&path_components); + + std::vector::const_iterator ib, ip; + for (ib = base_components.begin(), ip = path_components.begin(); + ib != base_components.end(); ++ib, ++ip) { + // |base| must be a subpath of |path|, so all components should match. + // If these CHECKs fail, look at the test that base is a parent of + // path at the top of this function. + DCHECK(ip != path_components.end()); + DCHECK(*ip == *ib); + } + + FilePath current_path = base; + if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gids)) + return false; + + for (; ip != path_components.end(); ++ip) { + current_path = current_path.Append(*ip); + if (!VerifySpecificPathControlledByUser(current_path, owner_uid, + group_gids)) + return false; + } + return true; +} + +#if defined(OS_MACOSX) && !defined(OS_IOS) +bool VerifyPathControlledByAdmin(const FilePath& path) { + const unsigned kRootUid = 0; + const FilePath kFileSystemRoot("/"); + + // The name of the administrator group on mac os. + const char* const kAdminGroupNames[] = {"admin", "wheel"}; + + std::set allowed_group_ids; + for (int i = 0, ie = arraysize(kAdminGroupNames); i < ie; ++i) { + struct group* group_record = getgrnam(kAdminGroupNames[i]); + if (!group_record) { + DPLOG(ERROR) << "Could not get the group ID of group \"" + << kAdminGroupNames[i] << "\"."; + continue; + } + + allowed_group_ids.insert(group_record->gr_gid); + } + + return VerifyPathControlledByUser(kFileSystemRoot, path, kRootUid, + allowed_group_ids); +} +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + +int GetMaximumPathComponentLength(const FilePath& path) { + return pathconf(path.value().c_str(), _PC_NAME_MAX); +} + +bool GetShmemTempDir(bool executable, FilePath* path) { +#if defined(OS_LINUX) || defined(OS_AIX) + bool use_dev_shm = true; + if (executable) { + static const bool s_dev_shm_executable = DetermineDevShmExecutable(); + use_dev_shm = s_dev_shm_executable; + } + if (use_dev_shm) { + *path = FilePath("/dev/shm"); + return true; + } +#endif // defined(OS_LINUX) || defined(OS_AIX) + return GetTempDir(path); +} + +#if !defined(OS_MACOSX) +// Mac has its own implementation, this is for all other Posix systems. +bool CopyFile(const FilePath& from_path, const FilePath& to_path) { + File infile; + infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ); + if (!infile.IsValid()) + return false; + + File outfile(to_path, File::FLAG_WRITE | File::FLAG_CREATE_ALWAYS); + if (!outfile.IsValid()) + return false; + + return CopyFileContents(&infile, &outfile); +} +#endif // !defined(OS_MACOSX) + +#endif // !defined(OS_NACL_NONSFI) +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_util_win.cc b/src/3rdparty/gn/base/files/file_util_win.cc new file mode 100644 index 00000000000..34d328b5fca --- /dev/null +++ b/src/3rdparty/gn/base/files/file_util_win.cc @@ -0,0 +1,697 @@ +// 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/files/file_util.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/macros.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_conversions.h" +#include "base/win/scoped_handle.h" + +// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the +// "Community Additions" comment on MSDN here: +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx +#define SystemFunction036 NTAPI SystemFunction036 +#include +#undef SystemFunction036 + +namespace base { + +namespace { + +const DWORD kFileShareAll = + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + +// Deletes all files and directories in a path. +// Returns ERROR_SUCCESS on success or the Windows error code corresponding to +// the first error encountered. +DWORD DeleteFileRecursive(const FilePath& path, + const FilePath::StringType& pattern, + bool recursive) { + FileEnumerator traversal(path, false, + FileEnumerator::FILES | FileEnumerator::DIRECTORIES, + pattern); + DWORD result = ERROR_SUCCESS; + for (FilePath current = traversal.Next(); !current.empty(); + current = traversal.Next()) { + // Try to clear the read-only bit if we find it. + FileEnumerator::FileInfo info = traversal.GetInfo(); + if ((info.find_data().dwFileAttributes & FILE_ATTRIBUTE_READONLY) && + (recursive || !info.IsDirectory())) { + ::SetFileAttributes( + current.value().c_str(), + info.find_data().dwFileAttributes & ~FILE_ATTRIBUTE_READONLY); + } + + DWORD this_result = ERROR_SUCCESS; + if (info.IsDirectory()) { + if (recursive) { + this_result = DeleteFileRecursive(current, pattern, true); + if (this_result == ERROR_SUCCESS && + !::RemoveDirectory(current.value().c_str())) { + this_result = ::GetLastError(); + } + } + } else if (!::DeleteFile(current.value().c_str())) { + this_result = ::GetLastError(); + } + if (result == ERROR_SUCCESS) + result = this_result; + } + return result; +} + +// Appends |mode_char| to |mode| before the optional character set encoding; see +// https://msdn.microsoft.com/library/yeby3zcb.aspx for details. +void AppendModeCharacter(base::char16 mode_char, base::string16* mode) { + size_t comma_pos = mode->find(L','); + mode->insert(comma_pos == base::string16::npos ? mode->length() : comma_pos, + 1, mode_char); +} + +// Returns ERROR_SUCCESS on success, or a Windows error code on failure. +DWORD DoDeleteFile(const FilePath& path, bool recursive) { + if (path.empty()) + return ERROR_SUCCESS; + + if (path.value().length() >= MAX_PATH) + return ERROR_BAD_PATHNAME; + + // Handle any path with wildcards. + if (path.BaseName().value().find_first_of(L"*?") != + FilePath::StringType::npos) { + return DeleteFileRecursive(path.DirName(), path.BaseName().value(), + recursive); + } + + // Report success if the file or path does not exist. + const DWORD attr = ::GetFileAttributes(path.value().c_str()); + if (attr == INVALID_FILE_ATTRIBUTES) { + const DWORD error_code = ::GetLastError(); + return (error_code == ERROR_FILE_NOT_FOUND || + error_code == ERROR_PATH_NOT_FOUND) + ? ERROR_SUCCESS + : error_code; + } + + // Clear the read-only bit if it is set. + if ((attr & FILE_ATTRIBUTE_READONLY) && + !::SetFileAttributes(path.value().c_str(), + attr & ~FILE_ATTRIBUTE_READONLY)) { + return ::GetLastError(); + } + + // Perform a simple delete on anything that isn't a directory. + if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { + return ::DeleteFile(path.value().c_str()) ? ERROR_SUCCESS + : ::GetLastError(); + } + + if (recursive) { + const DWORD error_code = DeleteFileRecursive(path, L"*", true); + if (error_code != ERROR_SUCCESS) + return error_code; + } + return ::RemoveDirectory(path.value().c_str()) ? ERROR_SUCCESS + : ::GetLastError(); +} + +std::string RandomDataToGUIDString(const uint64_t bytes[2]) { + return base::StringPrintf( + "%08x-%04x-%04x-%04x-%012llx", static_cast(bytes[0] >> 32), + static_cast((bytes[0] >> 16) & 0x0000ffff), + static_cast(bytes[0] & 0x0000ffff), + static_cast(bytes[1] >> 48), + bytes[1] & 0x0000ffff'ffffffffULL); +} + +void RandBytes(void* output, size_t output_length) { + char* output_ptr = static_cast(output); + while (output_length > 0) { + const ULONG output_bytes_this_pass = static_cast(std::min( + output_length, static_cast(std::numeric_limits::max()))); + const bool success = + RtlGenRandom(output_ptr, output_bytes_this_pass) != FALSE; + CHECK(success); + output_length -= output_bytes_this_pass; + output_ptr += output_bytes_this_pass; + } +} + +std::string GenerateGUID() { + uint64_t sixteen_bytes[2]; + // Use base::RandBytes instead of crypto::RandBytes, because crypto calls the + // base version directly, and to prevent the dependency from base/ to crypto/. + RandBytes(&sixteen_bytes, sizeof(sixteen_bytes)); + + // 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] &= 0xffffffff'ffff0fffULL; + sixteen_bytes[0] |= 0x00000000'00004000ULL; + + // 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] &= 0x3fffffff'ffffffffULL; + sixteen_bytes[1] |= 0x80000000'00000000ULL; + + return RandomDataToGUIDString(sixteen_bytes); +} + +} // namespace + +FilePath MakeAbsoluteFilePath(const FilePath& input) { + wchar_t file_path[MAX_PATH]; + if (!_wfullpath(file_path, input.value().c_str(), MAX_PATH)) + return FilePath(); + return FilePath(file_path); +} + +bool DeleteFile(const FilePath& path, bool recursive) { + static constexpr char kRecursive[] = "DeleteFile.Recursive"; + static constexpr char kNonRecursive[] = "DeleteFile.NonRecursive"; + const StringPiece operation(recursive ? kRecursive : kNonRecursive); + + // Metrics for delete failures tracked in https://crbug.com/599084. Delete may + // fail for a number of reasons. Log some metrics relating to failures in the + // current code so that any improvements or regressions resulting from + // subsequent code changes can be detected. + const DWORD error = DoDeleteFile(path, recursive); + return error == ERROR_SUCCESS; +} + +bool DeleteFileAfterReboot(const FilePath& path) { + if (path.value().length() >= MAX_PATH) + return false; + + return MoveFileEx(path.value().c_str(), NULL, + MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING) != + FALSE; +} + +bool ReplaceFile(const FilePath& from_path, + const FilePath& to_path, + File::Error* error) { + // Try a simple move first. It will only succeed when |to_path| doesn't + // already exist. + if (::MoveFile(from_path.value().c_str(), to_path.value().c_str())) + return true; + File::Error move_error = File::OSErrorToFileError(GetLastError()); + + // Try the full-blown replace if the move fails, as ReplaceFile will only + // succeed when |to_path| does exist. When writing to a network share, we may + // not be able to change the ACLs. Ignore ACL errors then + // (REPLACEFILE_IGNORE_MERGE_ERRORS). + if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL, + REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) { + return true; + } + // In the case of FILE_ERROR_NOT_FOUND from ReplaceFile, it is likely that + // |to_path| does not exist. In this case, the more relevant error comes + // from the call to MoveFile. + if (error) { + File::Error replace_error = File::OSErrorToFileError(GetLastError()); + *error = replace_error == File::FILE_ERROR_NOT_FOUND ? move_error + : replace_error; + } + return false; +} + +bool PathExists(const FilePath& path) { + return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES); +} + +bool PathIsWritable(const FilePath& path) { + HANDLE dir = + CreateFile(path.value().c_str(), FILE_ADD_FILE, kFileShareAll, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + + if (dir == INVALID_HANDLE_VALUE) + return false; + + CloseHandle(dir); + return true; +} + +bool DirectoryExists(const FilePath& path) { + DWORD fileattr = GetFileAttributes(path.value().c_str()); + if (fileattr != INVALID_FILE_ATTRIBUTES) + return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0; + return false; +} + +bool GetTempDir(FilePath* path) { + wchar_t temp_path[MAX_PATH + 1]; + DWORD path_len = ::GetTempPath(MAX_PATH, temp_path); + if (path_len >= MAX_PATH || path_len <= 0) + return false; + // TODO(evanm): the old behavior of this function was to always strip the + // trailing slash. We duplicate this here, but it shouldn't be necessary + // when everyone is using the appropriate FilePath APIs. + *path = FilePath(temp_path).StripTrailingSeparators(); + return true; +} + +bool CreateTemporaryFile(FilePath* path) { + FilePath temp_file; + + if (!GetTempDir(path)) + return false; + + if (CreateTemporaryFileInDir(*path, &temp_file)) { + *path = temp_file; + return true; + } + + return false; +} + +// On POSIX we have semantics to create and open a temporary file +// atomically. +// TODO(jrg): is there equivalent call to use on Windows instead of +// going 2-step? +FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { + if (!CreateTemporaryFileInDir(dir, path)) { + return NULL; + } + // Open file in binary mode, to avoid problems with fwrite. On Windows + // it replaces \n's with \r\n's, which may surprise you. + // Reference: http://msdn.microsoft.com/en-us/library/h9t88zwz(VS.71).aspx + return OpenFile(*path, "wb+"); +} + +bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) { + // Use GUID instead of ::GetTempFileName() to generate unique file names. + // "Due to the algorithm used to generate file names, GetTempFileName can + // perform poorly when creating a large number of files with the same prefix. + // In such cases, it is recommended that you construct unique file names based + // on GUIDs." + // https://msdn.microsoft.com/library/windows/desktop/aa364991.aspx + + FilePath temp_name; + bool create_file_success = false; + + // Although it is nearly impossible to get a duplicate name with GUID, we + // still use a loop here in case it happens. + for (int i = 0; i < 100; ++i) { + temp_name = dir.Append(ASCIIToUTF16(base::GenerateGUID()) + L".tmp"); + File file(temp_name, + File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE); + if (file.IsValid()) { + file.Close(); + create_file_success = true; + break; + } + } + + if (!create_file_success) { + DPLOG(WARNING) << "Failed to get temporary file name in " + << UTF16ToUTF8(dir.value()); + return false; + } + + wchar_t long_temp_name[MAX_PATH + 1]; + DWORD long_name_len = + GetLongPathName(temp_name.value().c_str(), long_temp_name, MAX_PATH); + if (long_name_len > MAX_PATH || long_name_len == 0) { + // GetLongPathName() failed, but we still have a temporary file. + *temp_file = std::move(temp_name); + return true; + } + + FilePath::StringType long_temp_name_str; + long_temp_name_str.assign(long_temp_name, long_name_len); + *temp_file = FilePath(std::move(long_temp_name_str)); + return true; +} + +bool CreateTemporaryDirInDir(const FilePath& base_dir, + const FilePath::StringType& prefix, + FilePath* new_dir) { + FilePath path_to_create; + + for (int count = 0; count < 50; ++count) { + // Try create a new temporary directory with random generated name. If + // the one exists, keep trying another path name until we reach some limit. + string16 new_dir_name; + new_dir_name.assign(prefix); + new_dir_name.append(IntToString16(::GetCurrentProcessId())); + new_dir_name.push_back('_'); + new_dir_name.append(UTF8ToUTF16(GenerateGUID())); + + path_to_create = base_dir.Append(new_dir_name); + if (::CreateDirectory(path_to_create.value().c_str(), NULL)) { + *new_dir = path_to_create; + return true; + } + } + + return false; +} + +bool CreateNewTempDirectory(const FilePath::StringType& prefix, + FilePath* new_temp_path) { + FilePath system_temp_dir; + if (!GetTempDir(&system_temp_dir)) + return false; + + return CreateTemporaryDirInDir(system_temp_dir, prefix, new_temp_path); +} + +bool CreateDirectoryAndGetError(const FilePath& full_path, File::Error* error) { + // If the path exists, we've succeeded if it's a directory, failed otherwise. + const wchar_t* full_path_str = full_path.value().c_str(); + DWORD fileattr = ::GetFileAttributes(full_path_str); + if (fileattr != INVALID_FILE_ATTRIBUTES) { + if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) { + return true; + } + DLOG(WARNING) << "CreateDirectory(" << full_path_str << "), " + << "conflicts with existing file."; + if (error) { + *error = File::FILE_ERROR_NOT_A_DIRECTORY; + } + return false; + } + + // Invariant: Path does not exist as file or directory. + + // Attempt to create the parent recursively. This will immediately return + // true if it already exists, otherwise will create all required parent + // directories starting with the highest-level missing parent. + FilePath parent_path(full_path.DirName()); + if (parent_path.value() == full_path.value()) { + if (error) { + *error = File::FILE_ERROR_NOT_FOUND; + } + return false; + } + if (!CreateDirectoryAndGetError(parent_path, error)) { + DLOG(WARNING) << "Failed to create one of the parent directories."; + if (error) { + DCHECK(*error != File::FILE_OK); + } + return false; + } + + if (!::CreateDirectory(full_path_str, NULL)) { + DWORD error_code = ::GetLastError(); + if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) { + // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we + // were racing with someone creating the same directory, or a file + // with the same path. If DirectoryExists() returns true, we lost the + // race to create the same directory. + return true; + } else { + if (error) + *error = File::OSErrorToFileError(error_code); + DLOG(WARNING) << "Failed to create directory " << full_path_str + << ", last error is " << error_code << "."; + return false; + } + } else { + return true; + } +} + +bool NormalizeFilePath(const FilePath& path, FilePath* real_path) { + FilePath mapped_file; + if (!NormalizeToNativeFilePath(path, &mapped_file)) + return false; + // NormalizeToNativeFilePath() will return a path that starts with + // "\Device\Harddisk...". Helper DevicePathToDriveLetterPath() + // will find a drive letter which maps to the path's device, so + // that we return a path starting with a drive letter. + return DevicePathToDriveLetterPath(mapped_file, real_path); +} + +bool DevicePathToDriveLetterPath(const FilePath& nt_device_path, + FilePath* out_drive_letter_path) { + // Get the mapping of drive letters to device paths. + const int kDriveMappingSize = 1024; + wchar_t drive_mapping[kDriveMappingSize] = {'\0'}; + if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) { + DLOG(ERROR) << "Failed to get drive mapping."; + return false; + } + + // The drive mapping is a sequence of null terminated strings. + // The last string is empty. + wchar_t* drive_map_ptr = drive_mapping; + wchar_t device_path_as_string[MAX_PATH]; + wchar_t drive[] = L" :"; + + // For each string in the drive mapping, get the junction that links + // to it. If that junction is a prefix of |device_path|, then we + // know that |drive| is the real path prefix. + while (*drive_map_ptr) { + drive[0] = drive_map_ptr[0]; // Copy the drive letter. + + if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) { + FilePath device_path(device_path_as_string); + if (device_path == nt_device_path || + device_path.IsParent(nt_device_path)) { + *out_drive_letter_path = + FilePath(drive + nt_device_path.value().substr( + wcslen(device_path_as_string))); + return true; + } + } + // Move to the next drive letter string, which starts one + // increment after the '\0' that terminates the current string. + while (*drive_map_ptr++) { + } + } + + // No drive matched. The path does not start with a device junction + // that is mounted as a drive letter. This means there is no drive + // letter path to the volume that holds |device_path|, so fail. + return false; +} + +bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) { + // In Vista, GetFinalPathNameByHandle() would give us the real path + // from a file handle. If we ever deprecate XP, consider changing the + // code below to a call to GetFinalPathNameByHandle(). The method this + // function uses is explained in the following msdn article: + // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx + win::ScopedHandle file_handle(::CreateFile(path.value().c_str(), GENERIC_READ, + kFileShareAll, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL)); + if (!file_handle.IsValid()) + return false; + + // Create a file mapping object. Can't easily use MemoryMappedFile, because + // we only map the first byte, and need direct access to the handle. You can + // not map an empty file, this call fails in that case. + win::ScopedHandle file_map_handle( + ::CreateFileMapping(file_handle.Get(), NULL, PAGE_READONLY, 0, + 1, // Just one byte. No need to look at the data. + NULL)); + if (!file_map_handle.IsValid()) + return false; + + // Use a view of the file to get the path to the file. + void* file_view = + MapViewOfFile(file_map_handle.Get(), FILE_MAP_READ, 0, 0, 1); + if (!file_view) + return false; + + // The expansion of |path| into a full path may make it longer. + // GetMappedFileName() will fail if the result is longer than MAX_PATH. + // Pad a bit to be safe. If kMaxPathLength is ever changed to be less + // than MAX_PATH, it would be nessisary to test that GetMappedFileName() + // not return kMaxPathLength. This would mean that only part of the + // path fit in |mapped_file_path|. + const int kMaxPathLength = MAX_PATH + 10; + wchar_t mapped_file_path[kMaxPathLength]; + bool success = false; + HANDLE cp = GetCurrentProcess(); + if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) { + *nt_path = FilePath(mapped_file_path); + success = true; + } + ::UnmapViewOfFile(file_view); + return success; +} + +// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle +// them if we do decide to. +bool IsLink(const FilePath& file_path) { + return false; +} + +bool GetFileInfo(const FilePath& file_path, File::Info* results) { + WIN32_FILE_ATTRIBUTE_DATA attr; + if (!GetFileAttributesEx(file_path.value().c_str(), GetFileExInfoStandard, + &attr)) { + return false; + } + + ULARGE_INTEGER size; + size.HighPart = attr.nFileSizeHigh; + size.LowPart = attr.nFileSizeLow; + results->size = size.QuadPart; + + results->is_directory = + (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + results->last_modified = *reinterpret_cast(&attr.ftLastWriteTime); + results->last_accessed = *reinterpret_cast(&attr.ftLastAccessTime); + results->creation_time = *reinterpret_cast(&attr.ftCreationTime); + + return true; +} + +FILE* OpenFile(const FilePath& filename, const char* mode) { + // 'N' is unconditionally added below, so be sure there is not one already + // present before a comma in |mode|. + DCHECK( + strchr(mode, 'N') == nullptr || + (strchr(mode, ',') != nullptr && strchr(mode, 'N') > strchr(mode, ','))); + string16 w_mode = ASCIIToUTF16(mode); + AppendModeCharacter(L'N', &w_mode); + return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO); +} + +FILE* FileToFILE(File file, const char* mode) { + if (!file.IsValid()) + return NULL; + int fd = + _open_osfhandle(reinterpret_cast(file.GetPlatformFile()), 0); + if (fd < 0) + return NULL; + file.TakePlatformFile(); + FILE* stream = _fdopen(fd, mode); + if (!stream) + _close(fd); + return stream; +} + +int ReadFile(const FilePath& filename, char* data, int max_size) { + win::ScopedHandle file(CreateFile(filename.value().c_str(), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, + NULL)); + if (!file.IsValid()) + return -1; + + DWORD read; + if (::ReadFile(file.Get(), data, max_size, &read, NULL)) + return read; + + return -1; +} + +int WriteFile(const FilePath& filename, const char* data, int size) { + win::ScopedHandle file(CreateFile(filename.value().c_str(), GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, + NULL)); + if (!file.IsValid()) { + DPLOG(WARNING) << "CreateFile failed for path " + << UTF16ToUTF8(filename.value()); + return -1; + } + + DWORD written; + BOOL result = ::WriteFile(file.Get(), data, size, &written, NULL); + if (result && static_cast(written) == size) + return written; + + if (!result) { + // WriteFile failed. + DPLOG(WARNING) << "writing file " << UTF16ToUTF8(filename.value()) + << " failed"; + } else { + // Didn't write all the bytes. + DLOG(WARNING) << "wrote" << written << " bytes to " + << UTF16ToUTF8(filename.value()) << " expected " << size; + } + return -1; +} + +bool AppendToFile(const FilePath& filename, const char* data, int size) { + win::ScopedHandle file(CreateFile(filename.value().c_str(), FILE_APPEND_DATA, + 0, NULL, OPEN_EXISTING, 0, NULL)); + if (!file.IsValid()) { + return false; + } + + DWORD written; + BOOL result = ::WriteFile(file.Get(), data, size, &written, NULL); + if (result && static_cast(written) == size) + return true; + + return false; +} + +bool GetCurrentDirectory(FilePath* dir) { + wchar_t system_buffer[MAX_PATH]; + system_buffer[0] = 0; + DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer); + if (len == 0 || len > MAX_PATH) + return false; + // TODO(evanm): the old behavior of this function was to always strip the + // trailing slash. We duplicate this here, but it shouldn't be necessary + // when everyone is using the appropriate FilePath APIs. + std::wstring dir_str(system_buffer); + *dir = FilePath(dir_str).StripTrailingSeparators(); + return true; +} + +bool SetCurrentDirectory(const FilePath& directory) { + return ::SetCurrentDirectory(directory.value().c_str()) != 0; +} + +int GetMaximumPathComponentLength(const FilePath& path) { + wchar_t volume_path[MAX_PATH]; + if (!GetVolumePathNameW(path.NormalizePathSeparators().value().c_str(), + volume_path, arraysize(volume_path))) { + return -1; + } + + DWORD max_length = 0; + if (!GetVolumeInformationW(volume_path, NULL, 0, NULL, &max_length, NULL, + NULL, 0)) { + return -1; + } + + // Length of |path| with path separator appended. + size_t prefix = path.StripTrailingSeparators().value().size() + 1; + // The whole path string must be shorter than MAX_PATH. That is, it must be + // prefix + component_length < MAX_PATH (or equivalently, <= MAX_PATH - 1). + int whole_path_limit = std::max(0, MAX_PATH - 1 - static_cast(prefix)); + return std::min(whole_path_limit, static_cast(max_length)); +} + +bool SetNonBlocking(int fd) { + unsigned long nonblocking = 1; + if (ioctlsocket(fd, FIONBIO, &nonblocking) == 0) + return true; + return false; +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/file_win.cc b/src/3rdparty/gn/base/files/file_win.cc new file mode 100644 index 00000000000..aff859c94fc --- /dev/null +++ b/src/3rdparty/gn/base/files/file_win.cc @@ -0,0 +1,381 @@ +// 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/files/file.h" + +#include +#include + +#include "base/logging.h" + +#include + +namespace base { + +// Make sure our Whence mappings match the system headers. +static_assert(File::FROM_BEGIN == FILE_BEGIN && + File::FROM_CURRENT == FILE_CURRENT && + File::FROM_END == FILE_END, + "whence mapping must match the system headers"); + +bool File::IsValid() const { + return file_.IsValid(); +} + +PlatformFile File::GetPlatformFile() const { + return file_.Get(); +} + +PlatformFile File::TakePlatformFile() { + return file_.Take(); +} + +void File::Close() { + if (!file_.IsValid()) + return; + + file_.Close(); +} + +int64_t File::Seek(Whence whence, int64_t offset) { + DCHECK(IsValid()); + + LARGE_INTEGER distance, res; + distance.QuadPart = offset; + DWORD move_method = static_cast(whence); + if (!SetFilePointerEx(file_.Get(), distance, &res, move_method)) + return -1; + return res.QuadPart; +} + +int File::Read(int64_t offset, char* data, int size) { + DCHECK(IsValid()); + DCHECK(!async_); + if (size < 0) + return -1; + + LARGE_INTEGER offset_li; + offset_li.QuadPart = offset; + + OVERLAPPED overlapped = {0}; + overlapped.Offset = offset_li.LowPart; + overlapped.OffsetHigh = offset_li.HighPart; + + DWORD bytes_read; + if (::ReadFile(file_.Get(), data, size, &bytes_read, &overlapped)) + return bytes_read; + if (ERROR_HANDLE_EOF == GetLastError()) + return 0; + + return -1; +} + +int File::ReadAtCurrentPos(char* data, int size) { + DCHECK(IsValid()); + DCHECK(!async_); + if (size < 0) + return -1; + + DWORD bytes_read; + if (::ReadFile(file_.Get(), data, size, &bytes_read, NULL)) + return bytes_read; + if (ERROR_HANDLE_EOF == GetLastError()) + return 0; + + return -1; +} + +int File::ReadNoBestEffort(int64_t offset, char* data, int size) { + // TODO(dbeam): trace this separately? + return Read(offset, data, size); +} + +int File::ReadAtCurrentPosNoBestEffort(char* data, int size) { + // TODO(dbeam): trace this separately? + return ReadAtCurrentPos(data, size); +} + +int File::Write(int64_t offset, const char* data, int size) { + DCHECK(IsValid()); + DCHECK(!async_); + + LARGE_INTEGER offset_li; + offset_li.QuadPart = offset; + + OVERLAPPED overlapped = {0}; + overlapped.Offset = offset_li.LowPart; + overlapped.OffsetHigh = offset_li.HighPart; + + DWORD bytes_written; + if (::WriteFile(file_.Get(), data, size, &bytes_written, &overlapped)) + return bytes_written; + + return -1; +} + +int File::WriteAtCurrentPos(const char* data, int size) { + DCHECK(IsValid()); + DCHECK(!async_); + if (size < 0) + return -1; + + DWORD bytes_written; + if (::WriteFile(file_.Get(), data, size, &bytes_written, NULL)) + return bytes_written; + + return -1; +} + +int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) { + return WriteAtCurrentPos(data, size); +} + +int64_t File::GetLength() { + DCHECK(IsValid()); + + LARGE_INTEGER size; + if (!::GetFileSizeEx(file_.Get(), &size)) + return -1; + + return static_cast(size.QuadPart); +} + +bool File::SetLength(int64_t length) { + DCHECK(IsValid()); + + // Get the current file pointer. + LARGE_INTEGER file_pointer; + LARGE_INTEGER zero; + zero.QuadPart = 0; + if (!::SetFilePointerEx(file_.Get(), zero, &file_pointer, FILE_CURRENT)) + return false; + + LARGE_INTEGER length_li; + length_li.QuadPart = length; + // If length > file size, SetFilePointerEx() should extend the file + // with zeroes on all Windows standard file systems (NTFS, FATxx). + if (!::SetFilePointerEx(file_.Get(), length_li, NULL, FILE_BEGIN)) + return false; + + // Set the new file length and move the file pointer to its old position. + // This is consistent with ftruncate()'s behavior, even when the file + // pointer points to a location beyond the end of the file. + // TODO(rvargas): Emulating ftruncate details seem suspicious and it is not + // promised by the interface (nor was promised by PlatformFile). See if this + // implementation detail can be removed. + return ((::SetEndOfFile(file_.Get()) != FALSE) && + (::SetFilePointerEx(file_.Get(), file_pointer, NULL, FILE_BEGIN) != + FALSE)); +} + +bool File::GetInfo(Info* info) { + DCHECK(IsValid()); + + BY_HANDLE_FILE_INFORMATION file_info; + if (!GetFileInformationByHandle(file_.Get(), &file_info)) + return false; + + LARGE_INTEGER size; + size.HighPart = file_info.nFileSizeHigh; + size.LowPart = file_info.nFileSizeLow; + info->size = size.QuadPart; + info->is_directory = + (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + info->is_symbolic_link = false; // Windows doesn't have symbolic links. + info->last_modified = + *reinterpret_cast(&file_info.ftLastWriteTime); + info->last_accessed = + *reinterpret_cast(&file_info.ftLastAccessTime); + info->creation_time = *reinterpret_cast(&file_info.ftCreationTime); + return true; +} + +File::Error File::Lock() { + DCHECK(IsValid()); + + BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD); + if (!result) + return GetLastFileError(); + return FILE_OK; +} + +File::Error File::Unlock() { + DCHECK(IsValid()); + + BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD); + if (!result) + return GetLastFileError(); + return FILE_OK; +} + +File File::Duplicate() const { + if (!IsValid()) + return File(); + + HANDLE other_handle = nullptr; + + if (!::DuplicateHandle(GetCurrentProcess(), // hSourceProcessHandle + GetPlatformFile(), + GetCurrentProcess(), // hTargetProcessHandle + &other_handle, + 0, // dwDesiredAccess ignored due to SAME_ACCESS + FALSE, // !bInheritHandle + DUPLICATE_SAME_ACCESS)) { + return File(GetLastFileError()); + } + + File other(other_handle); + if (async()) + other.async_ = true; + return other; +} + +bool File::DeleteOnClose(bool delete_on_close) { + FILE_DISPOSITION_INFO disposition = { BOOLEAN(delete_on_close ? TRUE : FALSE) }; + return ::SetFileInformationByHandle(GetPlatformFile(), FileDispositionInfo, + &disposition, sizeof(disposition)) != 0; +} + +// Static. +File::Error File::OSErrorToFileError(DWORD last_error) { + switch (last_error) { + case ERROR_SHARING_VIOLATION: + return FILE_ERROR_IN_USE; + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + return FILE_ERROR_EXISTS; + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return FILE_ERROR_NOT_FOUND; + case ERROR_ACCESS_DENIED: + return FILE_ERROR_ACCESS_DENIED; + case ERROR_TOO_MANY_OPEN_FILES: + return FILE_ERROR_TOO_MANY_OPENED; + case ERROR_OUTOFMEMORY: + case ERROR_NOT_ENOUGH_MEMORY: + return FILE_ERROR_NO_MEMORY; + case ERROR_HANDLE_DISK_FULL: + case ERROR_DISK_FULL: + case ERROR_DISK_RESOURCES_EXHAUSTED: + return FILE_ERROR_NO_SPACE; + case ERROR_USER_MAPPED_FILE: + return FILE_ERROR_INVALID_OPERATION; + case ERROR_NOT_READY: + case ERROR_SECTOR_NOT_FOUND: + case ERROR_DEV_NOT_EXIST: + case ERROR_IO_DEVICE: + case ERROR_FILE_CORRUPT: + case ERROR_DISK_CORRUPT: + return FILE_ERROR_IO; + default: + // This function should only be called for errors. + DCHECK_NE(static_cast(ERROR_SUCCESS), last_error); + return FILE_ERROR_FAILED; + } +} + +void File::DoInitialize(const FilePath& path, uint32_t flags) { + DCHECK(!IsValid()); + + DWORD disposition = 0; + + if (flags & FLAG_OPEN) + disposition = OPEN_EXISTING; + + if (flags & FLAG_CREATE) { + DCHECK(!disposition); + disposition = CREATE_NEW; + } + + if (flags & FLAG_OPEN_ALWAYS) { + DCHECK(!disposition); + disposition = OPEN_ALWAYS; + } + + if (flags & FLAG_CREATE_ALWAYS) { + DCHECK(!disposition); + DCHECK(flags & FLAG_WRITE); + disposition = CREATE_ALWAYS; + } + + if (flags & FLAG_OPEN_TRUNCATED) { + DCHECK(!disposition); + DCHECK(flags & FLAG_WRITE); + disposition = TRUNCATE_EXISTING; + } + + if (!disposition) { + ::SetLastError(ERROR_INVALID_PARAMETER); + error_details_ = FILE_ERROR_FAILED; + NOTREACHED(); + return; + } + + DWORD access = 0; + if (flags & FLAG_WRITE) + access = GENERIC_WRITE; + if (flags & FLAG_APPEND) { + DCHECK(!access); + access = FILE_APPEND_DATA; + } + if (flags & FLAG_READ) + access |= GENERIC_READ; + if (flags & FLAG_WRITE_ATTRIBUTES) + access |= FILE_WRITE_ATTRIBUTES; + if (flags & FLAG_EXECUTE) + access |= GENERIC_EXECUTE; + if (flags & FLAG_CAN_DELETE_ON_CLOSE) + access |= DELETE; + + DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ; + if (!(flags & FLAG_EXCLUSIVE_WRITE)) + sharing |= FILE_SHARE_WRITE; + if (flags & FLAG_SHARE_DELETE) + sharing |= FILE_SHARE_DELETE; + + DWORD create_flags = 0; + if (flags & FLAG_ASYNC) + create_flags |= FILE_FLAG_OVERLAPPED; + if (flags & FLAG_TEMPORARY) + create_flags |= FILE_ATTRIBUTE_TEMPORARY; + if (flags & FLAG_HIDDEN) + create_flags |= FILE_ATTRIBUTE_HIDDEN; + if (flags & FLAG_DELETE_ON_CLOSE) + create_flags |= FILE_FLAG_DELETE_ON_CLOSE; + if (flags & FLAG_BACKUP_SEMANTICS) + create_flags |= FILE_FLAG_BACKUP_SEMANTICS; + if (flags & FLAG_SEQUENTIAL_SCAN) + create_flags |= FILE_FLAG_SEQUENTIAL_SCAN; + + file_.Set(CreateFile(path.value().c_str(), access, sharing, NULL, disposition, + create_flags, NULL)); + + if (file_.IsValid()) { + error_details_ = FILE_OK; + async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC); + + if (flags & (FLAG_OPEN_ALWAYS)) + created_ = (ERROR_ALREADY_EXISTS != GetLastError()); + else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE)) + created_ = true; + } else { + error_details_ = GetLastFileError(); + } +} + +bool File::Flush() { + DCHECK(IsValid()); + return ::FlushFileBuffers(file_.Get()) != FALSE; +} + +void File::SetPlatformFile(PlatformFile file) { + file_.Set(file); +} + +// static +File::Error File::GetLastFileError() { + return File::OSErrorToFileError(GetLastError()); +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/platform_file.h b/src/3rdparty/gn/base/files/platform_file.h new file mode 100644 index 00000000000..cba2fc8ad6c --- /dev/null +++ b/src/3rdparty/gn/base/files/platform_file.h @@ -0,0 +1,43 @@ +// Copyright 2017 The Chromium 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_FILES_PLATFORM_FILE_H_ +#define BASE_FILES_PLATFORM_FILE_H_ + +#include "base/files/scoped_file.h" +#include "util/build_config.h" + +#if defined(OS_WIN) +#include "base/win/scoped_handle.h" +#include "base/win/windows_types.h" +#endif + +// This file defines platform-independent types for dealing with +// platform-dependent files. If possible, use the higher-level base::File class +// rather than these primitives. + +namespace base { + +#if defined(OS_WIN) + +using PlatformFile = HANDLE; +using ScopedPlatformFile = ::base::win::ScopedHandle; + +// It would be nice to make this constexpr but INVALID_HANDLE_VALUE is a +// ((void*)(-1)) which Clang rejects since reinterpret_cast is technically +// disallowed in constexpr. Visual Studio accepts this, however. +const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE; + +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + +using PlatformFile = int; +using ScopedPlatformFile = ::base::ScopedFD; + +constexpr PlatformFile kInvalidPlatformFile = -1; + +#endif + +} // namespace base + +#endif // BASE_FILES_PLATFORM_FILE_H_ diff --git a/src/3rdparty/gn/base/files/scoped_file.cc b/src/3rdparty/gn/base/files/scoped_file.cc new file mode 100644 index 00000000000..11afedd695e --- /dev/null +++ b/src/3rdparty/gn/base/files/scoped_file.cc @@ -0,0 +1,49 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/files/scoped_file.h" + +#include "base/logging.h" +#include "util/build_config.h" + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +#include +#include + +#include "base/posix/eintr_wrapper.h" +#endif + +namespace base { +namespace internal { + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) + +// static +void ScopedFDCloseTraits::Free(int fd) { + // It's important to crash here. + // There are security implications to not closing a file descriptor + // properly. As file descriptors are "capabilities", keeping them open + // would make the current process keep access to a resource. Much of + // Chrome relies on being able to "drop" such access. + // It's especially problematic on Linux with the setuid sandbox, where + // a single open directory would bypass the entire security model. + int ret = IGNORE_EINTR(close(fd)); + +#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_FUCHSIA) || \ + defined(OS_ANDROID) + // NB: Some file descriptors can return errors from close() e.g. network + // filesystems such as NFS and Linux input devices. On Linux, macOS, and + // Fuchsia's POSIX layer, errors from close other than EBADF do not indicate + // failure to actually close the fd. + if (ret != 0 && errno != EBADF) + ret = 0; +#endif + + PCHECK(0 == ret); +} + +#endif // OS_POSIX || OS_FUCHSIA + +} // namespace internal +} // namespace base diff --git a/src/3rdparty/gn/base/files/scoped_file.h b/src/3rdparty/gn/base/files/scoped_file.h new file mode 100644 index 00000000000..0d896504300 --- /dev/null +++ b/src/3rdparty/gn/base/files/scoped_file.h @@ -0,0 +1,59 @@ +// 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_FILES_SCOPED_FILE_H_ +#define BASE_FILES_SCOPED_FILE_H_ + +#include + +#include + +#include "base/logging.h" +#include "base/scoped_generic.h" +#include "util/build_config.h" + +namespace base { + +namespace internal { + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +struct ScopedFDCloseTraits { + static int InvalidValue() { return -1; } + static void Free(int fd); +}; +#endif + +// Functor for |ScopedFILE| (below). +struct ScopedFILECloser { + inline void operator()(FILE* x) const { + if (x) + fclose(x); + } +}; + +} // namespace internal + +// ----------------------------------------------------------------------------- + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +// A low-level Posix file descriptor closer class. Use this when writing +// platform-specific code, especially that does non-file-like things with the +// FD (like sockets). +// +// If you're writing low-level Windows code, see base/win/scoped_handle.h +// which provides some additional functionality. +// +// If you're writing cross-platform code that deals with actual files, you +// should generally use base::File instead which can be constructed with a +// handle, and in addition to handling ownership, has convenient cross-platform +// file manipulation functions on it. +typedef ScopedGeneric ScopedFD; +#endif + +// Automatically closes |FILE*|s. +typedef std::unique_ptr ScopedFILE; + +} // namespace base + +#endif // BASE_FILES_SCOPED_FILE_H_ diff --git a/src/3rdparty/gn/base/files/scoped_temp_dir.cc b/src/3rdparty/gn/base/files/scoped_temp_dir.cc new file mode 100644 index 00000000000..01ec0f0caab --- /dev/null +++ b/src/3rdparty/gn/base/files/scoped_temp_dir.cc @@ -0,0 +1,97 @@ +// 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/files/scoped_temp_dir.h" + +#include "base/files/file_util.h" +#include "base/logging.h" + +namespace base { + +namespace { + +constexpr FilePath::CharType kScopedDirPrefix[] = + FILE_PATH_LITERAL("scoped_dir"); + +} // namespace + +ScopedTempDir::ScopedTempDir() = default; + +ScopedTempDir::~ScopedTempDir() { + if (!path_.empty() && !Delete()) + DLOG(WARNING) << "Could not delete temp dir in dtor."; +} + +bool ScopedTempDir::CreateUniqueTempDir() { + if (!path_.empty()) + return false; + + // This "scoped_dir" prefix is only used on Windows and serves as a template + // for the unique name. + if (!base::CreateNewTempDirectory(kScopedDirPrefix, &path_)) + return false; + + return true; +} + +bool ScopedTempDir::CreateUniqueTempDirUnderPath(const FilePath& base_path) { + if (!path_.empty()) + return false; + + // If |base_path| does not exist, create it. + if (!base::CreateDirectory(base_path)) + return false; + + // Create a new, uniquely named directory under |base_path|. + if (!base::CreateTemporaryDirInDir(base_path, kScopedDirPrefix, &path_)) + return false; + + return true; +} + +bool ScopedTempDir::Set(const FilePath& path) { + if (!path_.empty()) + return false; + + if (!DirectoryExists(path) && !base::CreateDirectory(path)) + return false; + + path_ = path; + return true; +} + +bool ScopedTempDir::Delete() { + if (path_.empty()) + return false; + + bool ret = base::DeleteFile(path_, true); + if (ret) { + // We only clear the path if deleted the directory. + path_.clear(); + } + + return ret; +} + +FilePath ScopedTempDir::Take() { + FilePath ret = path_; + path_ = FilePath(); + return ret; +} + +const FilePath& ScopedTempDir::GetPath() const { + DCHECK(!path_.empty()) << "Did you call CreateUniqueTempDir* before?"; + return path_; +} + +bool ScopedTempDir::IsValid() const { + return !path_.empty() && DirectoryExists(path_); +} + +// static +const FilePath::CharType* ScopedTempDir::GetTempDirPrefix() { + return kScopedDirPrefix; +} + +} // namespace base diff --git a/src/3rdparty/gn/base/files/scoped_temp_dir.h b/src/3rdparty/gn/base/files/scoped_temp_dir.h new file mode 100644 index 00000000000..4ddb690945c --- /dev/null +++ b/src/3rdparty/gn/base/files/scoped_temp_dir.h @@ -0,0 +1,70 @@ +// 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_FILES_SCOPED_TEMP_DIR_H_ +#define BASE_FILES_SCOPED_TEMP_DIR_H_ + +// An object representing a temporary / scratch directory that should be +// cleaned up (recursively) when this object goes out of scope. Since deletion +// occurs during the destructor, no further error handling is possible if the +// directory fails to be deleted. As a result, deletion is not guaranteed by +// this class. (However note that, whenever possible, by default +// CreateUniqueTempDir creates the directory in a location that is +// automatically cleaned up on reboot, or at other appropriate times.) +// +// Multiple calls to the methods which establish a temporary directory +// (CreateUniqueTempDir, CreateUniqueTempDirUnderPath, and Set) must have +// intervening calls to Delete or Take, or the calls will fail. + +#include "base/files/file_path.h" +#include "base/macros.h" + +namespace base { + +class ScopedTempDir { + public: + // No directory is owned/created initially. + ScopedTempDir(); + + // Recursively delete path. + ~ScopedTempDir(); + + // Creates a unique directory in TempPath, and takes ownership of it. + // See file_util::CreateNewTemporaryDirectory. + bool CreateUniqueTempDir() WARN_UNUSED_RESULT; + + // Creates a unique directory under a given path, and takes ownership of it. + bool CreateUniqueTempDirUnderPath(const FilePath& path) WARN_UNUSED_RESULT; + + // Takes ownership of directory at |path|, creating it if necessary. + // Don't call multiple times unless Take() has been called first. + bool Set(const FilePath& path) WARN_UNUSED_RESULT; + + // Deletes the temporary directory wrapped by this object. + bool Delete() WARN_UNUSED_RESULT; + + // Caller takes ownership of the temporary directory so it won't be destroyed + // when this object goes out of scope. + FilePath Take(); + + // Returns the path to the created directory. Call one of the + // CreateUniqueTempDir* methods before getting the path. + const FilePath& GetPath() const; + + // Returns true if path_ is non-empty and exists. + bool IsValid() const; + + // Returns the prefix used for temp directory names generated by + // ScopedTempDirs. + static const FilePath::CharType* GetTempDirPrefix(); + + private: + FilePath path_; + + DISALLOW_COPY_AND_ASSIGN(ScopedTempDir); +}; + +} // namespace base + +#endif // BASE_FILES_SCOPED_TEMP_DIR_H_ diff --git a/src/3rdparty/gn/base/gtest_prod_util.h b/src/3rdparty/gn/base/gtest_prod_util.h new file mode 100644 index 00000000000..664dded781f --- /dev/null +++ b/src/3rdparty/gn/base/gtest_prod_util.h @@ -0,0 +1,16 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_GTEST_PROD_UTIL_H_ +#define BASE_GTEST_PROD_UTIL_H_ + +// TODO: Remove me. +#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \ + friend class test_case_name##test_name + +// TODO: Remove me. +#define FORWARD_DECLARE_TEST(test_case_name, test_name) \ + class test_case_name##test_name + +#endif // BASE_GTEST_PROD_UTIL_H_ diff --git a/src/3rdparty/gn/base/json/json_parser.cc b/src/3rdparty/gn/base/json/json_parser.cc new file mode 100644 index 00000000000..713f69223b1 --- /dev/null +++ b/src/3rdparty/gn/base/json/json_parser.cc @@ -0,0 +1,747 @@ +// 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 +#include +#include + +#include "base/logging.h" +#include "base/macros.h" +#include "base/numerics/safe_conversions.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/strings/utf_string_conversions.h" +#include "base/third_party/icu/icu_utf.h" +#include "base/values.h" + +namespace base { +namespace internal { + +namespace { + +const int32_t kExtendedASCIIStart = 0x80; + +// Simple class that checks for maximum recursion/"stack overflow." +class StackMarker { + public: + StackMarker(int max_depth, int* depth) + : max_depth_(max_depth), depth_(depth) { + ++(*depth_); + DCHECK_LE(*depth_, max_depth_); + } + ~StackMarker() { --(*depth_); } + + bool IsTooDeep() const { return *depth_ >= max_depth_; } + + private: + const int max_depth_; + int* const depth_; + + DISALLOW_COPY_AND_ASSIGN(StackMarker); +}; + +constexpr uint32_t kUnicodeReplacementPoint = 0xFFFD; + +} // namespace + +// This is U+FFFD. +const char kUnicodeReplacementString[] = "\xEF\xBF\xBD"; + +JSONParser::JSONParser(int options, int max_depth) + : options_(options), + max_depth_(max_depth), + index_(0), + stack_depth_(0), + line_number_(0), + index_last_line_(0), + error_code_(JSONReader::JSON_NO_ERROR), + error_line_(0), + error_column_(0) { + CHECK_LE(max_depth, JSONReader::kStackMaxDepth); +} + +JSONParser::~JSONParser() = default; + +Optional JSONParser::Parse(StringPiece input) { + input_ = input; + index_ = 0; + line_number_ = 1; + index_last_line_ = 0; + + error_code_ = JSONReader::JSON_NO_ERROR; + error_line_ = 0; + error_column_ = 0; + + // ICU and ReadUnicodeCharacter() use int32_t for lengths, so ensure + // that the index_ will not overflow when parsing. + if (!base::IsValueInRangeForNumericType(input.length())) { + ReportError(JSONReader::JSON_TOO_LARGE, 0); + return nullopt; + } + + // When the input JSON string starts with a UTF-8 Byte-Order-Mark, + // advance the start position to avoid the ParseNextToken function mis- + // treating a Unicode BOM as an invalid character and returning NULL. + ConsumeIfMatch("\xEF\xBB\xBF"); + + // Parse the first and any nested tokens. + Optional root(ParseNextToken()); + if (!root) + return nullopt; + + // Make sure the input stream is at an end. + if (GetNextToken() != T_END_OF_INPUT) { + ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1); + return nullopt; + } + + return root; +} + +JSONReader::JsonParseError JSONParser::error_code() const { + return error_code_; +} + +std::string JSONParser::GetErrorMessage() const { + return FormatErrorMessage(error_line_, error_column_, + JSONReader::ErrorCodeToString(error_code_)); +} + +int JSONParser::error_line() const { + return error_line_; +} + +int JSONParser::error_column() const { + return error_column_; +} + +// StringBuilder /////////////////////////////////////////////////////////////// + +JSONParser::StringBuilder::StringBuilder() : StringBuilder(nullptr) {} + +JSONParser::StringBuilder::StringBuilder(const char* pos) + : pos_(pos), length_(0) {} + +JSONParser::StringBuilder::~StringBuilder() = default; + +JSONParser::StringBuilder& JSONParser::StringBuilder::operator=( + StringBuilder&& other) = default; + +void JSONParser::StringBuilder::Append(uint32_t point) { + DCHECK(IsValidCharacter(point)); + + if (point < kExtendedASCIIStart && !string_) { + DCHECK_EQ(static_cast(point), pos_[length_]); + ++length_; + } else { + Convert(); + if (UNLIKELY(point == kUnicodeReplacementPoint)) { + string_->append(kUnicodeReplacementString); + } else { + WriteUnicodeCharacter(point, &*string_); + } + } +} + +void JSONParser::StringBuilder::Convert() { + if (string_) + return; + string_.emplace(pos_, length_); +} + +std::string JSONParser::StringBuilder::DestructiveAsString() { + if (string_) + return std::move(*string_); + return std::string(pos_, length_); +} + +// JSONParser private ////////////////////////////////////////////////////////// + +Optional JSONParser::PeekChars(int count) { + if (static_cast(index_) + count > input_.length()) + return nullopt; + // Using StringPiece::substr() is significantly slower (according to + // base_perftests) than constructing a substring manually. + return StringPiece(input_.data() + index_, count); +} + +Optional JSONParser::PeekChar() { + Optional chars = PeekChars(1); + if (chars) + return (*chars)[0]; + return nullopt; +} + +Optional JSONParser::ConsumeChars(int count) { + Optional chars = PeekChars(count); + if (chars) + index_ += count; + return chars; +} + +Optional JSONParser::ConsumeChar() { + Optional chars = ConsumeChars(1); + if (chars) + return (*chars)[0]; + return nullopt; +} + +const char* JSONParser::pos() { + CHECK_LE(static_cast(index_), input_.length()); + return input_.data() + index_; +} + +JSONParser::Token JSONParser::GetNextToken() { + EatWhitespaceAndComments(); + + Optional c = PeekChar(); + if (!c) + return T_END_OF_INPUT; + + switch (*c) { + 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 (Optional c = PeekChar()) { + switch (*c) { + case '\r': + case '\n': + index_last_line_ = index_; + // Don't increment line_number_ twice for "\r\n". + if (!(c == '\n' && index_ > 0 && input_[index_ - 1] == '\r')) { + ++line_number_; + } + FALLTHROUGH; + case ' ': + case '\t': + ConsumeChar(); + break; + case '/': + if (!EatComment()) + return; + break; + default: + return; + } + } +} + +bool JSONParser::EatComment() { + Optional comment_start = ConsumeChars(2); + if (!comment_start) + return false; + + if (comment_start == "//") { + // Single line comment, read to newline. + while (Optional c = PeekChar()) { + if (c == '\n' || c == '\r') + return true; + ConsumeChar(); + } + } else if (comment_start == "/*") { + char previous_char = '\0'; + // Block comment, read until end marker. + while (Optional c = PeekChar()) { + if (previous_char == '*' && c == '/') { + // 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). + ConsumeChar(); + return true; + } + previous_char = *ConsumeChar(); + } + + // If the comment is unterminated, GetNextToken will report T_END_OF_INPUT. + } + + return false; +} + +Optional JSONParser::ParseNextToken() { + return ParseToken(GetNextToken()); +} + +Optional 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 nullopt; + } +} + +Optional JSONParser::ConsumeDictionary() { + if (ConsumeChar() != '{') { + ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); + return nullopt; + } + + StackMarker depth_check(max_depth_, &stack_depth_); + if (depth_check.IsTooDeep()) { + ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 0); + return nullopt; + } + + std::vector dict_storage; + + Token token = GetNextToken(); + while (token != T_OBJECT_END) { + if (token != T_STRING) { + ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 1); + return nullopt; + } + + // First consume the key. + StringBuilder key; + if (!ConsumeStringRaw(&key)) { + return nullopt; + } + + // Read the separator. + token = GetNextToken(); + if (token != T_OBJECT_PAIR_SEPARATOR) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return nullopt; + } + + // The next token is the value. Ownership transfers to |dict|. + ConsumeChar(); + Optional value = ParseNextToken(); + if (!value) { + // ReportError from deeper level. + return nullopt; + } + + dict_storage.emplace_back(key.DestructiveAsString(), + std::make_unique(std::move(*value))); + + token = GetNextToken(); + if (token == T_LIST_SEPARATOR) { + ConsumeChar(); + token = GetNextToken(); + if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { + ReportError(JSONReader::JSON_TRAILING_COMMA, 1); + return nullopt; + } + } else if (token != T_OBJECT_END) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + return nullopt; + } + } + + ConsumeChar(); // Closing '}'. + + return Value(Value::DictStorage(std::move(dict_storage), KEEP_LAST_OF_DUPES)); +} + +Optional JSONParser::ConsumeList() { + if (ConsumeChar() != '[') { + ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); + return nullopt; + } + + StackMarker depth_check(max_depth_, &stack_depth_); + if (depth_check.IsTooDeep()) { + ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 0); + return nullopt; + } + + Value::ListStorage list_storage; + + Token token = GetNextToken(); + while (token != T_ARRAY_END) { + Optional item = ParseToken(token); + if (!item) { + // ReportError from deeper level. + return nullopt; + } + + list_storage.push_back(std::move(*item)); + + token = GetNextToken(); + if (token == T_LIST_SEPARATOR) { + ConsumeChar(); + token = GetNextToken(); + if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { + ReportError(JSONReader::JSON_TRAILING_COMMA, 1); + return nullopt; + } + } else if (token != T_ARRAY_END) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return nullopt; + } + } + + ConsumeChar(); // Closing ']'. + + return Value(std::move(list_storage)); +} + +Optional JSONParser::ConsumeString() { + StringBuilder string; + if (!ConsumeStringRaw(&string)) + return nullopt; + + return Value(string.DestructiveAsString()); +} + +bool JSONParser::ConsumeStringRaw(StringBuilder* out) { + if (ConsumeChar() != '"') { + 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(pos()); + + while (PeekChar()) { + uint32_t next_char = 0; + if (!ReadUnicodeCharacter(input_.data(), + static_cast(input_.length()), &index_, + &next_char) || + !IsValidCharacter(next_char)) { + if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) { + ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 1); + return false; + } + ConsumeChar(); + string.Append(kUnicodeReplacementPoint); + continue; + } + + if (next_char == '"') { + ConsumeChar(); + *out = std::move(string); + return true; + } else if (next_char != '\\') { + // If this character is not an escape sequence... + ConsumeChar(); + string.Append(next_char); + } else { + // And if it is an escape sequence, 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(); + + // Read past the escape '\' and ensure there's a character following. + Optional escape_sequence = ConsumeChars(2); + if (!escape_sequence) { + ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); + return false; + } + + switch ((*escape_sequence)[1]) { + // 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. + escape_sequence = ConsumeChars(2); + if (!escape_sequence) { + ReportError(JSONReader::JSON_INVALID_ESCAPE, -2); + return false; + } + + int hex_digit = 0; + if (!HexStringToInt(*escape_sequence, &hex_digit) || + !IsValidCharacter(hex_digit)) { + ReportError(JSONReader::JSON_INVALID_ESCAPE, -2); + return false; + } + + string.Append(hex_digit); + break; + } + case 'u': { // UTF-16 sequence. + // UTF units are of the form \uXXXX. + uint32_t code_point; + if (!DecodeUTF16(&code_point)) { + ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); + return false; + } + string.Append(code_point); + 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; + } + } + } + + ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); + return false; +} + +// Entry is at the first X in \uXXXX. +bool JSONParser::DecodeUTF16(uint32_t* out_code_point) { + Optional escape_sequence = ConsumeChars(4); + if (!escape_sequence) + return false; + + // Consume the UTF-16 code unit, which may be a high surrogate. + int code_unit16_high = 0; + if (!HexStringToInt(*escape_sequence, &code_unit16_high)) + return false; + + // 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 (!ConsumeIfMatch("\\u")) + return false; + + escape_sequence = ConsumeChars(4); + if (!escape_sequence) + return false; + + int code_unit16_low = 0; + if (!HexStringToInt(*escape_sequence, &code_unit16_low)) + return false; + + if (!CBU16_IS_TRAIL(code_unit16_low)) + return false; + + uint32_t code_point = + CBU16_GET_SUPPLEMENTARY(code_unit16_high, code_unit16_low); + if (!IsValidCharacter(code_point)) + return false; + + *out_code_point = code_point; + } else { + // Not a surrogate. + DCHECK(CBU16_IS_SINGLE(code_unit16_high)); + if (!IsValidCharacter(code_unit16_high)) { + if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) { + return false; + } + *out_code_point = kUnicodeReplacementPoint; + return true; + } + + *out_code_point = code_unit16_high; + } + + return true; +} + +Optional JSONParser::ConsumeNumber() { + const char* num_start = pos(); + const int start_index = index_; + int end_index = start_index; + + if (PeekChar() == '-') + ConsumeChar(); + + if (!ReadInt(false)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return nullopt; + } + end_index = index_; + + // The optional fraction part. + if (PeekChar() == '.') { + ConsumeChar(); + if (!ReadInt(true)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return nullopt; + } + end_index = index_; + } + + // Optional exponent part. + Optional c = PeekChar(); + if (c == 'e' || c == 'E') { + ConsumeChar(); + if (PeekChar() == '-' || PeekChar() == '+') { + ConsumeChar(); + } + if (!ReadInt(true)) { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return nullopt; + } + 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. + int exit_index = index_; + + 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 nullopt; + } + + index_ = exit_index; + + StringPiece num_string(num_start, end_index - start_index); + + int num_int; + if (StringToInt(num_string, &num_int)) + return Value(num_int); + + return nullopt; +} + +bool JSONParser::ReadInt(bool allow_leading_zeros) { + size_t len = 0; + char first = 0; + + while (Optional c = PeekChar()) { + if (!IsAsciiDigit(c)) + break; + + if (len == 0) + first = *c; + + ++len; + ConsumeChar(); + } + + if (len == 0) + return false; + + if (!allow_leading_zeros && len > 1 && first == '0') + return false; + + return true; +} + +Optional JSONParser::ConsumeLiteral() { + if (ConsumeIfMatch("true")) { + return Value(true); + } else if (ConsumeIfMatch("false")) { + return Value(false); + } else if (ConsumeIfMatch("null")) { + return Value(Value::Type::NONE); + } else { + ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); + return nullopt; + } +} + +bool JSONParser::ConsumeIfMatch(StringPiece match) { + if (match == PeekChars(match.size())) { + ConsumeChars(match.size()); + return true; + } + return false; +} + +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/src/3rdparty/gn/base/json/json_parser.h b/src/3rdparty/gn/base/json/json_parser.h new file mode 100644 index 00000000000..1289560983b --- /dev/null +++ b/src/3rdparty/gn/base/json/json_parser.h @@ -0,0 +1,260 @@ +// 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 +#include + +#include +#include + +#include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" +#include "base/json/json_reader.h" +#include "base/macros.h" +#include "base/optional.h" +#include "base/strings/string_piece.h" + +namespace base { + +class Value; + +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. Iteration happens +// on the byte level, with the functions ConsumeChars() and ConsumeChar(). 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 first byte +// after the token that was just consumed, which would likely be the first byte +// of the next token. +class JSONParser { + public: + JSONParser(int options, int max_depth = JSONReader::kStackMaxDepth); + ~JSONParser(); + + // Parses the input string according to the set options and returns the + // result as a Value. + // Wrap this in base::FooValue::From() to check the Value is of type Foo and + // convert to a FooValue at the same time. + Optional Parse(StringPiece input); + + // Returns the error code. + JSONReader::JsonParseError error_code() const; + + // Returns the human-friendly error message. + std::string GetErrorMessage() const; + + // Returns the error line number if parse error happened. Otherwise always + // returns 0. + int error_line() const; + + // Returns the error column number if parse error happened. Otherwise always + // returns 0. + int error_column() 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 assign to. + StringBuilder(); + + // |pos| is the beginning of an input string, excluding the |"|. + explicit StringBuilder(const char* pos); + + ~StringBuilder(); + + StringBuilder& operator=(StringBuilder&& other); + + // Appends the Unicode code point |point| to the string, either by + // increasing the |length_| of the string if the string has not been + // converted, or by appending the UTF8 bytes for the code point. + void Append(uint32_t point); + + // 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 the builder as a string, invalidating all state. This allows + // the internal string buffer representation to be destructively moved + // in cases where the builder will not be needed any more. + std::string DestructiveAsString(); + + 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. Will be unset until Convert() is + // called. + base::Optional string_; + }; + + // Returns the next |count| bytes of the input stream, or nullopt if fewer + // than |count| bytes remain. + Optional PeekChars(int count); + + // Calls PeekChars() with a |count| of 1. + Optional PeekChar(); + + // Returns the next |count| bytes of the input stream, or nullopt if fewer + // than |count| bytes remain, and advances the parser position by |count|. + Optional ConsumeChars(int count); + + // Calls ConsumeChars() with a |count| of 1. + Optional ConsumeChar(); + + // Returns a pointer to the current character position. + const char* pos(); + + // 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(). + Optional ParseNextToken(); + + // Takes a token that represents the start of a Value ("a structural token" + // in RFC terms) and consumes it, returning the result as a Value. + Optional ParseToken(Token token); + + // Assuming that the parser is currently wound to '{', this parses a JSON + // object into a Value. + Optional ConsumeDictionary(); + + // Assuming that the parser is wound to '[', this parses a JSON list into a + // Value. + Optional ConsumeList(); + + // Calls through ConsumeStringRaw and wraps it in a value. + Optional 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 places 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 code point |out_code_point|, and false on failure. + bool DecodeUTF16(uint32_t* out_code_point); + + // 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. + Optional 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. + Optional ConsumeLiteral(); + + // Helper function that returns true if the byte squence |match| can be + // consumed at the current parser position. Returns false if there are fewer + // than |match|-length bytes or if the sequence does not match, and the + // parser state is unchanged. + bool ConsumeIfMatch(StringPiece match); + + // 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. + const int options_; + + // Maximum depth to parse. + const int max_depth_; + + // The input stream being parsed. Note: Not guaranteed to NUL-terminated. + StringPiece input_; + + // 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); + FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ReplaceInvalidCharacters); + FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ReplaceInvalidUTF16EscapeSequence); + + DISALLOW_COPY_AND_ASSIGN(JSONParser); +}; + +// Used when decoding and an invalid utf-8 sequence is encountered. +extern const char kUnicodeReplacementString[]; + +} // namespace internal +} // namespace base + +#endif // BASE_JSON_JSON_PARSER_H_ diff --git a/src/3rdparty/gn/base/json/json_reader.cc b/src/3rdparty/gn/base/json/json_reader.cc new file mode 100644 index 00000000000..3d5475e8065 --- /dev/null +++ b/src/3rdparty/gn/base/json/json_reader.cc @@ -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. + +#include "base/json/json_reader.h" + +#include +#include + +#include "base/json/json_parser.h" +#include "base/logging.h" +#include "base/optional.h" +#include "base/values.h" + +namespace base { + +// Chosen to support 99.9% of documents found in the wild late 2016. +// http://crbug.com/673263 +const int JSONReader::kStackMaxDepth = 200; + +// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError. +static_assert(JSONReader::JSON_PARSE_ERROR_COUNT < 1000, + "JSONReader 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."; +const char JSONReader::kInputTooLarge[] = "Input string is too large (>2GB)."; + +JSONReader::JSONReader(int options, int max_depth) + : parser_(new internal::JSONParser(options, max_depth)) {} + +JSONReader::~JSONReader() = default; + +// static +std::unique_ptr JSONReader::Read(StringPiece json, + int options, + int max_depth) { + internal::JSONParser parser(options, max_depth); + Optional root = parser.Parse(json); + return root ? std::make_unique(std::move(*root)) : nullptr; +} + +// static +std::unique_ptr JSONReader::ReadAndReturnError( + StringPiece json, + int options, + int* error_code_out, + std::string* error_msg_out, + int* error_line_out, + int* error_column_out) { + internal::JSONParser parser(options); + Optional 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(); + if (error_line_out) + *error_line_out = parser.error_line(); + if (error_column_out) + *error_column_out = parser.error_column(); + } + + return root ? std::make_unique(std::move(*root)) : nullptr; +} + +// 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; + case JSON_TOO_LARGE: + return kInputTooLarge; + case JSON_PARSE_ERROR_COUNT: + break; + } + NOTREACHED(); + return std::string(); +} + +std::unique_ptr JSONReader::ReadToValue(StringPiece json) { + Optional value = parser_->Parse(json); + return value ? std::make_unique(std::move(*value)) : nullptr; +} + +JSONReader::JsonParseError JSONReader::error_code() const { + return parser_->error_code(); +} + +std::string JSONReader::GetErrorMessage() const { + return parser_->GetErrorMessage(); +} + +} // namespace base diff --git a/src/3rdparty/gn/base/json/json_reader.h b/src/3rdparty/gn/base/json/json_reader.h new file mode 100644 index 00000000000..c4f7c8fc738 --- /dev/null +++ b/src/3rdparty/gn/base/json/json_reader.h @@ -0,0 +1,134 @@ +// 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 +#include + +#include "base/strings/string_piece.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, + + // If set the parser replaces invalid characters with the Unicode replacement + // character (U+FFFD). If not set, invalid characters trigger a hard error and + // parsing fails. + JSON_REPLACE_INVALID_CHARACTERS = 1 << 1, +}; + +class JSONReader { + public: + static const int kStackMaxDepth; + + // 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_TOO_LARGE, + 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[]; + static const char kInputTooLarge[]; + + // Constructs a reader. + JSONReader(int options = JSON_PARSE_RFC, int max_depth = kStackMaxDepth); + + ~JSONReader(); + + // Reads and parses |json|, returning a Value. + // If |json| is not a properly formed JSON string, returns nullptr. + // Wrap this in base::FooValue::From() to check the Value is of type Foo and + // convert to a FooValue at the same time. + static std::unique_ptr Read(StringPiece json, + int options = JSON_PARSE_RFC, + int max_depth = kStackMaxDepth); + + // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out| + // are optional. If specified and nullptr 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 std::unique_ptr ReadAndReturnError( + StringPiece json, + int options, // JSONParserOptions + int* error_code_out, + std::string* error_msg_out, + int* error_line_out = nullptr, + int* error_column_out = nullptr); + + // 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); + + // Non-static version of Read() above. + std::unique_ptr ReadToValue(StringPiece 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: + std::unique_ptr parser_; +}; + +} // namespace base + +#endif // BASE_JSON_JSON_READER_H_ diff --git a/src/3rdparty/gn/base/json/json_value_converter.cc b/src/3rdparty/gn/base/json/json_value_converter.cc new file mode 100644 index 00000000000..55506e6b592 --- /dev/null +++ b/src/3rdparty/gn/base/json/json_value_converter.cc @@ -0,0 +1,36 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/json/json_value_converter.h" + +namespace base { +namespace internal { + +bool BasicValueConverter::Convert(const base::Value& value, + int* field) const { + return value.GetAsInteger(field); +} + +bool BasicValueConverter::Convert(const base::Value& value, + std::string* field) const { + return value.GetAsString(field); +} + +bool BasicValueConverter::Convert(const base::Value& value, + string16* field) const { + return value.GetAsString(field); +} + +bool BasicValueConverter::Convert(const base::Value& value, + double* field) const { + return value.GetAsDouble(field); +} + +bool BasicValueConverter::Convert(const base::Value& value, + bool* field) const { + return value.GetAsBoolean(field); +} + +} // namespace internal +} // namespace base diff --git a/src/3rdparty/gn/base/json/json_value_converter.h b/src/3rdparty/gn/base/json/json_value_converter.h new file mode 100644 index 00000000000..d91bead803f --- /dev/null +++ b/src/3rdparty/gn/base/json/json_value_converter.h @@ -0,0 +1,512 @@ +// 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_VALUE_CONVERTER_H_ +#define BASE_JSON_JSON_VALUE_CONVERTER_H_ + +#include + +#include +#include +#include + +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string16.h" +#include "base/strings/string_piece.h" +#include "base/values.h" + +// JSONValueConverter converts a JSON value into a C++ struct in a +// lightweight way. +// +// Usage: +// For real examples, you may want to refer to _unittest.cc file. +// +// Assume that you have a struct like this: +// struct Message { +// int foo; +// std::string bar; +// static void RegisterJSONConverter( +// JSONValueConverter* converter); +// }; +// +// And you want to parse a json data into this struct. First, you +// need to declare RegisterJSONConverter() method in your struct. +// // static +// void Message::RegisterJSONConverter( +// JSONValueConverter* converter) { +// converter->RegisterIntField("foo", &Message::foo); +// converter->RegisterStringField("bar", &Message::bar); +// } +// +// Then, you just instantiate your JSONValueConverter of your type and call +// Convert() method. +// Message message; +// JSONValueConverter converter; +// converter.Convert(json, &message); +// +// Convert() returns false when it fails. Here "fail" means that the value is +// structurally different from expected, such like a string value appears +// for an int field. Do not report failures for missing fields. +// Also note that Convert() will modify the passed |message| even when it +// fails for performance reason. +// +// For nested field, the internal message also has to implement the registration +// method. Then, just use RegisterNestedField() from the containing struct's +// RegisterJSONConverter method. +// struct Nested { +// Message foo; +// static void RegisterJSONConverter(...) { +// ... +// converter->RegisterNestedField("foo", &Nested::foo); +// } +// }; +// +// For repeated field, we just assume std::vector> +// for its container and you can put RegisterRepeatedInt or some other types. +// Use RegisterRepeatedMessage for nested repeated fields. +// +// Sometimes JSON format uses string representations for other types such +// like enum, timestamp, or URL. You can use RegisterCustomField method +// and specify a function to convert a StringPiece to your type. +// bool ConvertFunc(StringPiece s, YourEnum* result) { +// // do something and return true if succeed... +// } +// struct Message { +// YourEnum ye; +// ... +// static void RegisterJSONConverter(...) { +// ... +// converter->RegsiterCustomField( +// "your_enum", &Message::ye, &ConvertFunc); +// } +// }; + +namespace base { + +template +class JSONValueConverter; + +namespace internal { + +template +class FieldConverterBase { + public: + explicit FieldConverterBase(const std::string& path) : field_path_(path) {} + virtual ~FieldConverterBase() = default; + virtual bool ConvertField(const base::Value& value, + StructType* obj) const = 0; + const std::string& field_path() const { return field_path_; } + + private: + std::string field_path_; + DISALLOW_COPY_AND_ASSIGN(FieldConverterBase); +}; + +template +class ValueConverter { + public: + virtual ~ValueConverter() = default; + virtual bool Convert(const base::Value& value, FieldType* field) const = 0; +}; + +template +class FieldConverter : public FieldConverterBase { + public: + explicit FieldConverter(const std::string& path, + FieldType StructType::*field, + ValueConverter* converter) + : FieldConverterBase(path), + field_pointer_(field), + value_converter_(converter) {} + + bool ConvertField(const base::Value& value, StructType* dst) const override { + return value_converter_->Convert(value, &(dst->*field_pointer_)); + } + + private: + FieldType StructType::*field_pointer_; + std::unique_ptr> value_converter_; + DISALLOW_COPY_AND_ASSIGN(FieldConverter); +}; + +template +class BasicValueConverter; + +template <> +class BasicValueConverter : public ValueConverter { + public: + BasicValueConverter() = default; + + bool Convert(const base::Value& value, int* field) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); +}; + +template <> +class BasicValueConverter : public ValueConverter { + public: + BasicValueConverter() = default; + + bool Convert(const base::Value& value, std::string* field) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); +}; + +template <> +class BasicValueConverter : public ValueConverter { + public: + BasicValueConverter() = default; + + bool Convert(const base::Value& value, string16* field) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); +}; + +template <> +class BasicValueConverter : public ValueConverter { + public: + BasicValueConverter() = default; + + bool Convert(const base::Value& value, double* field) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); +}; + +template <> +class BasicValueConverter : public ValueConverter { + public: + BasicValueConverter() = default; + + bool Convert(const base::Value& value, bool* field) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); +}; + +template +class ValueFieldConverter : public ValueConverter { + public: + typedef bool (*ConvertFunc)(const base::Value* value, FieldType* field); + + explicit ValueFieldConverter(ConvertFunc convert_func) + : convert_func_(convert_func) {} + + bool Convert(const base::Value& value, FieldType* field) const override { + return convert_func_(&value, field); + } + + private: + ConvertFunc convert_func_; + + DISALLOW_COPY_AND_ASSIGN(ValueFieldConverter); +}; + +template +class CustomFieldConverter : public ValueConverter { + public: + typedef bool (*ConvertFunc)(StringPiece value, FieldType* field); + + explicit CustomFieldConverter(ConvertFunc convert_func) + : convert_func_(convert_func) {} + + bool Convert(const base::Value& value, FieldType* field) const override { + std::string string_value; + return value.GetAsString(&string_value) && + convert_func_(string_value, field); + } + + private: + ConvertFunc convert_func_; + + DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter); +}; + +template +class NestedValueConverter : public ValueConverter { + public: + NestedValueConverter() = default; + + bool Convert(const base::Value& value, NestedType* field) const override { + return converter_.Convert(value, field); + } + + private: + JSONValueConverter converter_; + DISALLOW_COPY_AND_ASSIGN(NestedValueConverter); +}; + +template +class RepeatedValueConverter + : public ValueConverter>> { + public: + RepeatedValueConverter() = default; + + bool Convert(const base::Value& value, + std::vector>* field) const override { + const base::ListValue* list = NULL; + if (!value.GetAsList(&list)) { + // The field is not a list. + return false; + } + + field->reserve(list->GetSize()); + for (size_t i = 0; i < list->GetSize(); ++i) { + const base::Value* element = NULL; + if (!list->Get(i, &element)) + continue; + + std::unique_ptr e(new Element); + if (basic_converter_.Convert(*element, e.get())) { + field->push_back(std::move(e)); + } else { + return false; + } + } + return true; + } + + private: + BasicValueConverter basic_converter_; + DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter); +}; + +template +class RepeatedMessageConverter + : public ValueConverter>> { + public: + RepeatedMessageConverter() = default; + + bool Convert(const base::Value& value, + std::vector>* field) const override { + const base::ListValue* list = NULL; + if (!value.GetAsList(&list)) + return false; + + field->reserve(list->GetSize()); + for (size_t i = 0; i < list->GetSize(); ++i) { + const base::Value* element = NULL; + if (!list->Get(i, &element)) + continue; + + std::unique_ptr nested(new NestedType); + if (converter_.Convert(*element, nested.get())) { + field->push_back(std::move(nested)); + } else { + return false; + } + } + return true; + } + + private: + JSONValueConverter converter_; + DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter); +}; + +template +class RepeatedCustomValueConverter + : public ValueConverter>> { + public: + typedef bool (*ConvertFunc)(const base::Value* value, NestedType* field); + + explicit RepeatedCustomValueConverter(ConvertFunc convert_func) + : convert_func_(convert_func) {} + + bool Convert(const base::Value& value, + std::vector>* field) const override { + const base::ListValue* list = NULL; + if (!value.GetAsList(&list)) + return false; + + field->reserve(list->GetSize()); + for (size_t i = 0; i < list->GetSize(); ++i) { + const base::Value* element = NULL; + if (!list->Get(i, &element)) + continue; + + std::unique_ptr nested(new NestedType); + if ((*convert_func_)(element, nested.get())) { + field->push_back(std::move(nested)); + } else { + return false; + } + } + return true; + } + + private: + ConvertFunc convert_func_; + DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter); +}; + +} // namespace internal + +template +class JSONValueConverter { + public: + JSONValueConverter() { StructType::RegisterJSONConverter(this); } + + void RegisterIntField(const std::string& field_name, int StructType::*field) { + fields_.push_back( + std::make_unique>( + field_name, field, new internal::BasicValueConverter)); + } + + void RegisterStringField(const std::string& field_name, + std::string StructType::*field) { + fields_.push_back( + std::make_unique>( + field_name, field, new internal::BasicValueConverter)); + } + + void RegisterStringField(const std::string& field_name, + string16 StructType::*field) { + fields_.push_back( + std::make_unique>( + field_name, field, new internal::BasicValueConverter)); + } + + void RegisterBoolField(const std::string& field_name, + bool StructType::*field) { + fields_.push_back( + std::make_unique>( + field_name, field, new internal::BasicValueConverter)); + } + + void RegisterDoubleField(const std::string& field_name, + double StructType::*field) { + fields_.push_back( + std::make_unique>( + field_name, field, new internal::BasicValueConverter)); + } + + template + void RegisterNestedField(const std::string& field_name, + NestedType StructType::*field) { + fields_.push_back( + std::make_unique>( + field_name, field, new internal::NestedValueConverter)); + } + + template + void RegisterCustomField(const std::string& field_name, + FieldType StructType::*field, + bool (*convert_func)(StringPiece, FieldType*)) { + fields_.push_back( + std::make_unique>( + field_name, field, + new internal::CustomFieldConverter(convert_func))); + } + + template + void RegisterCustomValueField(const std::string& field_name, + FieldType StructType::*field, + bool (*convert_func)(const base::Value*, + FieldType*)) { + fields_.push_back( + std::make_unique>( + field_name, field, + new internal::ValueFieldConverter(convert_func))); + } + + void RegisterRepeatedInt( + const std::string& field_name, + std::vector> StructType::*field) { + fields_.push_back(std::make_unique>>>( + field_name, field, new internal::RepeatedValueConverter)); + } + + void RegisterRepeatedString( + const std::string& field_name, + std::vector> StructType::*field) { + fields_.push_back( + std::make_unique>>>( + field_name, field, + new internal::RepeatedValueConverter)); + } + + void RegisterRepeatedString( + const std::string& field_name, + std::vector> StructType::*field) { + fields_.push_back(std::make_unique>>>( + field_name, field, new internal::RepeatedValueConverter)); + } + + void RegisterRepeatedDouble( + const std::string& field_name, + std::vector> StructType::*field) { + fields_.push_back(std::make_unique>>>( + field_name, field, new internal::RepeatedValueConverter)); + } + + void RegisterRepeatedBool( + const std::string& field_name, + std::vector> StructType::*field) { + fields_.push_back(std::make_unique>>>( + field_name, field, new internal::RepeatedValueConverter)); + } + + template + void RegisterRepeatedCustomValue( + const std::string& field_name, + std::vector> StructType::*field, + bool (*convert_func)(const base::Value*, NestedType*)) { + fields_.push_back( + std::make_unique>>>( + field_name, field, + new internal::RepeatedCustomValueConverter( + convert_func))); + } + + template + void RegisterRepeatedMessage( + const std::string& field_name, + std::vector> StructType::*field) { + fields_.push_back( + std::make_unique>>>( + field_name, field, + new internal::RepeatedMessageConverter)); + } + + bool Convert(const base::Value& value, StructType* output) const { + const DictionaryValue* dictionary_value = NULL; + if (!value.GetAsDictionary(&dictionary_value)) + return false; + + for (size_t i = 0; i < fields_.size(); ++i) { + const internal::FieldConverterBase* field_converter = + fields_[i].get(); + const base::Value* field = NULL; + if (dictionary_value->Get(field_converter->field_path(), &field)) { + if (!field_converter->ConvertField(*field, output)) { + return false; + } + } + } + return true; + } + + private: + std::vector>> + fields_; + + DISALLOW_COPY_AND_ASSIGN(JSONValueConverter); +}; + +} // namespace base + +#endif // BASE_JSON_JSON_VALUE_CONVERTER_H_ diff --git a/src/3rdparty/gn/base/json/json_writer.cc b/src/3rdparty/gn/base/json/json_writer.cc new file mode 100644 index 00000000000..656a87c22ee --- /dev/null +++ b/src/3rdparty/gn/base/json/json_writer.cc @@ -0,0 +1,177 @@ +// 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 + +#include +#include + +#include "base/json/string_escape.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "base/values.h" +#include "util/build_config.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.type()) { + case Value::Type::NONE: { + 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::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 = nullptr; + bool first_value_has_been_output = false; + bool result = node.GetAsList(&list); + DCHECK(result); + for (const auto& value : *list) { + if (omit_binary_values_ && value.type() == 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 = nullptr; + 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().type() == 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/src/3rdparty/gn/base/json/json_writer.h b/src/3rdparty/gn/base/json/json_writer.h new file mode 100644 index 00000000000..7edd3a68680 --- /dev/null +++ b/src/3rdparty/gn/base/json/json_writer.h @@ -0,0 +1,74 @@ +// 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 + +#include + +#include "base/macros.h" + +namespace base { + +class Value; + +class 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|. + // The output string is overwritten and not appended. + // + // 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/src/3rdparty/gn/base/json/string_escape.cc b/src/3rdparty/gn/base/json/string_escape.cc new file mode 100644 index 00000000000..471a9d30cfa --- /dev/null +++ b/src/3rdparty/gn/base/json/string_escape.cc @@ -0,0 +1,167 @@ +// 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 +#include + +#include +#include + +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversion_utils.h" +#include "base/strings/utf_string_conversions.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_t kReplacementCodePoint = 0xFFFD; + +// Used below in EscapeSpecialCodePoint(). +static_assert('<' == 0x3C, "less than sign must be 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_t 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; + // Escape the "Line Separator" and "Paragraph Separator" characters, since + // they should be treated like a new line \r or \n. + case 0x2028: + dest->append("\\u2028"); + break; + case 0x2029: + dest->append("\\u2029"); + break; + default: + return false; + } + return true; +} + +template +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_t. Try and do so safely. + CHECK_LE(str.length(), + static_cast(std::numeric_limits::max())); + const int32_t length = static_cast(str.length()); + + for (int32_t i = 0; i < length; ++i) { + uint32_t code_point; + if (!ReadUnicodeCharacter(str.data(), length, &i, &code_point) || + code_point == static_cast(CBU_SENTINEL) || + !IsValidCharacter(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(StringPiece str, bool put_in_quotes, std::string* dest) { + return EscapeJSONStringImpl(str, put_in_quotes, dest); +} + +bool EscapeJSONString(StringPiece16 str, + bool put_in_quotes, + std::string* dest) { + return EscapeJSONStringImpl(str, put_in_quotes, dest); +} + +std::string GetQuotedJSONString(StringPiece str) { + std::string dest; + bool ok = EscapeJSONStringImpl(str, true, &dest); + DCHECK(ok); + return dest; +} + +std::string GetQuotedJSONString(StringPiece16 str) { + std::string dest; + bool ok = EscapeJSONStringImpl(str, true, &dest); + DCHECK(ok); + return dest; +} + +std::string EscapeBytesAsInvalidJSONString(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/src/3rdparty/gn/base/json/string_escape.h b/src/3rdparty/gn/base/json/string_escape.h new file mode 100644 index 00000000000..d318b6aa1c1 --- /dev/null +++ b/src/3rdparty/gn/base/json/string_escape.h @@ -0,0 +1,55 @@ +// 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 + +#include "base/strings/string_piece.h" + +namespace base { + +// Appends to |dest| an escaped version of |str|. Valid UTF-8 code units and +// characters will pass through from the input to the output. Invalid code +// units and characters 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(StringPiece str, bool put_in_quotes, std::string* dest); + +// Performs a similar function to the UTF-8 StringPiece version above, +// converting UTF-16 code units to UTF-8 code units and escaping non-printing +// control characters. On return, |dest| will contain a valid UTF-8 JSON string. +bool EscapeJSONString(StringPiece16 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(StringPiece str); +std::string GetQuotedJSONString(StringPiece16 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(StringPiece str, bool put_in_quotes); + +} // namespace base + +#endif // BASE_JSON_STRING_ESCAPE_H_ diff --git a/src/3rdparty/gn/base/logging.cc b/src/3rdparty/gn/base/logging.cc new file mode 100644 index 00000000000..c2c243f38f0 --- /dev/null +++ b/src/3rdparty/gn/base/logging.cc @@ -0,0 +1,330 @@ +// 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 +#include + +#include + +#include "base/macros.h" +#include "util/build_config.h" + +#if defined(OS_WIN) +#include +#include +// Windows warns on using write(). It prefers _write(). +#define write(fd, buf, count) _write(fd, buf, static_cast(count)) +// Windows doesn't define STDERR_FILENO. Define it here. +#define STDERR_FILENO 2 + +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +#include +#include +#endif + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "base/callback.h" +#include "base/containers/stack.h" +#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_conversions.h" + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +#include "base/posix/safe_strerror.h" +#endif + +namespace logging { + +namespace { + +const char* const log_severity_names[] = {"INFO", "WARNING", "ERROR", "FATAL"}; +static_assert(LOG_NUM_SEVERITIES == arraysize(log_severity_names), + "Incorrect number of log_severity_names"); + +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; + +// For LOG_ERROR and above, always print to stderr. +const int kAlwaysPrintErrorLevel = LOG_ERROR; + +} // namespace + +#if DCHECK_IS_CONFIGURABLE +// In DCHECK-enabled Chrome builds, allow the meaning of LOG_DCHECK to be +// determined at run-time. We default it to INFO, to avoid it triggering +// crashes before the run-time has explicitly chosen the behaviour. +logging::LogSeverity LOG_DCHECK = LOG_INFO; +#endif // DCHECK_IS_CONFIGURABLE + +// This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to have +// an object of the correct type on the LHS of the unused part of the ternary +// operator. +std::ostream* g_swallow_stream; + +void SetMinLogLevel(int level) { + g_min_log_level = std::min(LOG_FATAL, level); +} + +int GetMinLogLevel() { + return g_min_log_level; +} + +bool ShouldCreateLogMessage(int severity) { + if (severity < g_min_log_level) + return false; + + // Return true here unless we know ~LogMessage won't do anything. Note that + // ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even + // when g_logging_destination is LOG_NONE. + return severity >= kAlwaysPrintErrorLevel; +} + +// Explicit instantiations for commonly used comparisons. +template std::string* MakeCheckOpString(const int&, + const int&, + const char* names); +template std::string* MakeCheckOpString( + const unsigned long&, + const unsigned long&, + const char* names); +template std::string* MakeCheckOpString( + const unsigned long&, + const unsigned int&, + const char* names); +template std::string* MakeCheckOpString( + const unsigned int&, + const unsigned long&, + const char* names); +template std::string* MakeCheckOpString( + const std::string&, + const std::string&, + const char* name); + +void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p) { + (*os) << "nullptr"; +} + +#if defined(OS_WIN) +LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {} + +LogMessage::SaveLastError::~SaveLastError() { + ::SetLastError(last_error_); +} +#endif // defined(OS_WIN) + +LogMessage::LogMessage(const char* file, int line, LogSeverity severity) + : severity_(severity), file_(file), line_(line) { + Init(file, line); +} + +LogMessage::LogMessage(const char* file, int line, const char* condition) + : severity_(LOG_FATAL), file_(file), line_(line) { + Init(file, line); + stream_ << "Check failed: " << condition << ". "; +} + +LogMessage::LogMessage(const char* file, int line, std::string* result) + : severity_(LOG_FATAL), file_(file), line_(line) { + Init(file, line); + stream_ << "Check failed: " << *result; + delete result; +} + +LogMessage::LogMessage(const char* file, + int line, + LogSeverity severity, + std::string* result) + : severity_(severity), file_(file), line_(line) { + Init(file, line); + stream_ << "Check failed: " << *result; + delete result; +} + +LogMessage::~LogMessage() { + if (severity_ == LOG_FATAL) { + stream_ << std::endl; // Newline to separate from log message. + } + stream_ << std::endl; + std::string str_newline(stream_.str()); + +#if defined(OS_WIN) + OutputDebugStringA(str_newline.c_str()); +#endif + ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr)); + fflush(stderr); + + if (severity_ == LOG_FATAL) { + 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_ << '['; + stream_ << std::this_thread::get_id() << ':'; +#if defined(OS_WIN) + SYSTEMTIME local_time; + GetLocalTime(&local_time); + stream_ << std::setfill('0') << std::setw(2) << local_time.wMonth + << std::setw(2) << local_time.wDay << '/' << std::setw(2) + << local_time.wHour << std::setw(2) << local_time.wMinute + << std::setw(2) << local_time.wSecond << '.' << std::setw(3) + << local_time.wMilliseconds << ':'; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + timeval tv; + gettimeofday(&tv, nullptr); + time_t t = tv.tv_sec; + struct tm local_time; + localtime_r(&t, &local_time); + 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 << '.' << std::setw(6) << tv.tv_usec << ':'; +#else +#error Unsupported platform +#endif + if (severity_ >= 0) + stream_ << log_severity_name(severity_); + else + stream_ << "VERBOSE" << -severity_; + + stream_ << ":" << filename << "(" << line << ")] "; + + message_start_ = stream_.str().length(); +} + +#if defined(OS_WIN) +// This has already been defined in the header, but defining it again as DWORD +// ensures that the type used in the header is equivalent to DWORD. If not, +// the redefinition is a compile error. +typedef DWORD SystemErrorCode; +#endif + +SystemErrorCode GetLastSystemErrorCode() { +#if defined(OS_WIN) + return ::GetLastError(); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + return errno; +#endif +} + +std::string SystemErrorCodeToString(SystemErrorCode error_code) { +#if defined(OS_WIN) + const int kErrorMessageBufferSize = 256; + char msgbuf[kErrorMessageBufferSize]; + DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; + DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf, + arraysize(msgbuf), nullptr); + if (len) { + // Messages returned by system end with line breaks. + return base::CollapseWhitespaceASCII(msgbuf, true) + + base::StringPrintf(" (0x%lX)", error_code); + } + return base::StringPrintf("Error (0x%lX) while retrieving error. (0x%lX)", + GetLastError(), error_code); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) + return base::safe_strerror(error_code) + + base::StringPrintf(" (%d)", error_code); +#endif // defined(OS_WIN) +} + +#if defined(OS_WIN) +Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err) + : err_(err), log_message_(file, line, severity) {} + +Win32ErrorLogMessage::~Win32ErrorLogMessage() { + stream() << ": " << SystemErrorCodeToString(err_); +} +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +ErrnoLogMessage::ErrnoLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err) + : err_(err), log_message_(file, line, severity) {} + +ErrnoLogMessage::~ErrnoLogMessage() { + stream() << ": " << SystemErrorCodeToString(err_); +} +#endif // defined(OS_WIN) + +void RawLog(int level, const char* message) { + if (level >= g_min_log_level && message) { + 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 + +std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) { + return out << (wstr ? base::WideToUTF8(wstr) : std::string()); +} diff --git a/src/3rdparty/gn/base/logging.h b/src/3rdparty/gn/base/logging.h new file mode 100644 index 00000000000..2edad38c4a5 --- /dev/null +++ b/src/3rdparty/gn/base/logging.h @@ -0,0 +1,956 @@ +// 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 + +#include +#include +#include +#include +#include +#include + +#include "base/callback_forward.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/strings/string_piece_forward.h" +#include "base/template_util.h" +#include "util/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(). 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; +// +// We also override the standard 'assert' to use 'DLOG_ASSERT'. +// +// Lastly, there is: +// +// PLOG(ERROR) << "Couldn't do foo"; +// DPLOG(ERROR) << "Couldn't do foo"; +// PLOG_IF(ERROR, cond) << "Couldn't do foo"; +// DPLOG_IF(ERROR, cond) << "Couldn't do foo"; +// PCHECK(condition) << "Couldn't do foo"; +// DPCHECK(condition) << "Couldn't do foo"; +// +// which append the last system error to the message in string form (taken from +// GetLastError() on Windows and errno on POSIX). +// +// The supported severity levels for macros that allow you to specify one +// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. +// +// Very important: logging a message at the FATAL severity level causes +// the program to terminate (after the message is logged). +// +// There is the special severity of DFATAL, which logs FATAL in debug mode, +// ERROR in normal mode. + +namespace logging { + +// 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. +void SetMinLogLevel(int level); + +// Gets the current log level. +int GetMinLogLevel(); + +// Used by LOG_IS_ON to lazy-evaluate stream arguments. +bool ShouldCreateLogMessage(int severity); + +// The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints +// to Clang which control what code paths are statically analyzed, +// and is meant to be used in conjunction with assert & assert-like functions. +// The expression is passed straight through if analysis isn't enabled. +// +// ANALYZER_SKIP_THIS_PATH() suppresses static analysis for the current +// codepath and any other branching codepaths that might follow. +#if defined(__clang_analyzer__) + +inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) { + return false; +} + +inline constexpr bool AnalyzerAssumeTrue(bool arg) { + // AnalyzerNoReturn() is invoked and analysis is terminated if |arg| is + // false. + return arg || AnalyzerNoReturn(); +} + +#define ANALYZER_ASSUME_TRUE(arg) logging::AnalyzerAssumeTrue(!!(arg)) +#define ANALYZER_SKIP_THIS_PATH() \ + static_cast(::logging::AnalyzerNoReturn()) +#define ANALYZER_ALLOW_UNUSED(var) static_cast(var); + +#else // !defined(__clang_analyzer__) + +#define ANALYZER_ASSUME_TRUE(arg) (arg) +#define ANALYZER_SKIP_THIS_PATH() +#define ANALYZER_ALLOW_UNUSED(var) static_cast(var); + +#endif // defined(__clang_analyzer__) + +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 +#if defined(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_EX_DCHECK(ClassName, ...) \ + ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_DCHECK, ##__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) +#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_EX_DCHECK(LogMessage) + +#if defined(OS_WIN) +// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets +// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us +// to keep using this syntax, we define this macro to do the same thing +// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that +// the Windows SDK does for consistency. +#define ERROR 0 +#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \ + COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ##__VA_ARGS__) +#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR +// Needed for LOG_IS_ON(ERROR). +const LogSeverity LOG_0 = LOG_ERROR; +#endif + +// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also, +// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will +// always fire if they fail. +#define LOG_IS_ON(severity) \ + (::logging::ShouldCreateLogMessage(::logging::LOG_##severity)) + +// 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 LOG_ASSERT(condition) \ + LOG_IF(FATAL, !(ANALYZER_ASSUME_TRUE(condition))) \ + << "Assert failed: " #condition ". " + +#if defined(OS_WIN) +#define PLOG_STREAM(severity) \ + COMPACT_GOOGLE_LOG_EX_##severity(Win32ErrorLogMessage, \ + ::logging::GetLastSystemErrorCode()) \ + .stream() +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +#define PLOG_STREAM(severity) \ + COMPACT_GOOGLE_LOG_EX_##severity(ErrnoLogMessage, \ + ::logging::GetLastSystemErrorCode()) \ + .stream() +#endif + +#define PLOG(severity) LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity)) + +#define PLOG_IF(severity, condition) \ + LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition)) + +extern std::ostream* g_swallow_stream; + +// Note that g_swallow_stream is used instead of an arbitrary LOG() stream to +// avoid the creation of an object with a non-trivial destructor (LogMessage). +// On MSVC x86 (checked on 2015 Update 3), this causes a few additional +// pointless instructions to be emitted even at full optimization level, even +// though the : arm of the ternary operator is clearly never executed. Using a +// simpler object to be &'d with Voidify() avoids these extra instructions. +// Using a simpler POD object with a templated operator<< also works to avoid +// these instructions. However, this causes warnings on statically defined +// implementations of operator<<(std::ostream, ...) in some .cc files, because +// they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an +// ostream* also is not suitable, because some compilers warn of undefined +// behavior. +#define EAT_STREAM_PARAMETERS \ + true ? (void)0 \ + : ::logging::LogMessageVoidify() & (*::logging::g_swallow_stream) + +// Captures the result of a CHECK_EQ (for example) and facilitates testing as a +// boolean. +class CheckOpResult { + public: + // |message| must be non-null if and only if the check failed. + CheckOpResult(std::string* message) : message_(message) {} + // Returns true if the check succeeded. + operator bool() const { return !message_; } + // Returns the message. + std::string* message() { return message_; } + + private: + std::string* message_; +}; + +// Crashes in the fastest possible way with no attempt at logging. +// There are different constraints to satisfy here, see http://crbug.com/664209 +// for more context: +// - The trap instructions, and hence the PC value at crash time, have to be +// distinct and not get folded into the same opcode by the compiler. +// On Linux/Android this is tricky because GCC still folds identical +// asm volatile blocks. The workaround is generating distinct opcodes for +// each CHECK using the __COUNTER__ macro. +// - The debug info for the trap instruction has to be attributed to the source +// line that has the CHECK(), to make crash reports actionable. This rules +// out the ability of using a inline function, at least as long as clang +// doesn't support attribute(artificial). +// - Failed CHECKs should produce a signal that is distinguishable from an +// invalid memory access, to improve the actionability of crash reports. +// - The compiler should treat the CHECK as no-return instructions, so that the +// trap code can be efficiently packed in the prologue of the function and +// doesn't interfere with the main execution flow. +// - When debugging, developers shouldn't be able to accidentally step over a +// CHECK. This is achieved by putting opcodes that will cause a non +// continuable exception after the actual trap instruction. +// - Don't cause too much binary bloat. +#if defined(COMPILER_GCC) + +#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL) +// int 3 will generate a SIGTRAP. +#define TRAP_SEQUENCE() \ + asm volatile( \ + "int3; ud2; push %0;" ::"i"(static_cast(__COUNTER__))) + +#elif defined(ARCH_CPU_ARMEL) && !defined(OS_NACL) +// bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running +// as a 32 bit userspace app on arm64. There doesn't seem to be any way to +// cause a SIGTRAP from userspace without using a syscall (which would be a +// problem for sandboxing). +#define TRAP_SEQUENCE() \ + asm volatile("bkpt #0; udf %0;" ::"i"(__COUNTER__ % 256)) + +#elif defined(ARCH_CPU_ARM64) && !defined(OS_NACL) +// This will always generate a SIGTRAP on arm64. +#define TRAP_SEQUENCE() \ + asm volatile("brk #0; hlt %0;" ::"i"(__COUNTER__ % 65536)) + +#else +// Crash report accuracy will not be guaranteed on other architectures, but at +// least this will crash as expected. +#define TRAP_SEQUENCE() __builtin_trap() +#endif // ARCH_CPU_* + +// CHECK() and the trap sequence can be invoked from a constexpr function. +// This could make compilation fail on GCC, as it forbids directly using inline +// asm inside a constexpr function. However, it allows calling a lambda +// expression including the same asm. +// The side effect is that the top of the stacktrace will not point to the +// calling function, but to this anonymous lambda. This is still useful as the +// full name of the lambda will typically include the name of the function that +// calls CHECK() and the debugger will still break at the right line of code. +#if !defined(__clang__) +#define WRAPPED_TRAP_SEQUENCE() \ + do { \ + [] { TRAP_SEQUENCE(); }(); \ + } while (false) +#else +#define WRAPPED_TRAP_SEQUENCE() TRAP_SEQUENCE() +#endif + +#define IMMEDIATE_CRASH() \ + ({ \ + WRAPPED_TRAP_SEQUENCE(); \ + __builtin_unreachable(); \ + }) + +#elif defined(COMPILER_MSVC) + +// Clang is cleverer about coalescing int3s, so we need to add a unique-ish +// instruction following the __debugbreak() to have it emit distinct locations +// for CHECKs rather than collapsing them all together. It would be nice to use +// a short intrinsic to do this (and perhaps have only one implementation for +// both clang and MSVC), however clang-cl currently does not support intrinsics. +// On the flip side, MSVC x64 doesn't support inline asm. So, we have to have +// two implementations. Normally clang-cl's version will be 5 bytes (1 for +// `int3`, 2 for `ud2`, 2 for `push byte imm`, however, TODO(scottmg): +// https://crbug.com/694670 clang-cl doesn't currently support %'ing +// __COUNTER__, so eventually it will emit the dword form of push. +// TODO(scottmg): Reinvestigate a short sequence that will work on both +// compilers once clang supports more intrinsics. See https://crbug.com/693713. +#if defined(__clang__) +#define IMMEDIATE_CRASH() \ + ({ \ + {__asm int 3 __asm ud2 __asm push __COUNTER__}; \ + __builtin_unreachable(); \ + }) +#else +#define IMMEDIATE_CRASH() __debugbreak() +#endif // __clang__ + +#else +#error Port +#endif + +// 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) + +// Make all CHECK functions discard their log strings to reduce code bloat, and +// improve performance, for official release builds. +// +// This is not calling BreakDebugger since this is called frequently, and +// calling an out-of-line function instead of a noreturn inline macro prevents +// compiler optimizations. +#define CHECK(condition) \ + UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_STREAM_PARAMETERS + +// PCHECK includes the system error code, which is useful for determining +// why the condition failed. In official builds, preserve only the error code +// message so that it is available in crash reports. The stringified +// condition and any additional stream parameters are dropped. +#define PCHECK(condition) \ + LAZY_STREAM(PLOG_STREAM(FATAL), UNLIKELY(!(condition))); \ + EAT_STREAM_PARAMETERS + +#define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2)) + +#else // !(OFFICIAL_BUILD && NDEBUG) + +#if defined(_PREFAST_) && defined(OS_WIN) +// Use __analysis_assume to tell the VC++ static analysis engine that +// assert conditions are true, to suppress warnings. The LAZY_STREAM +// parameter doesn't reference 'condition' in /analyze builds because +// this evaluation confuses /analyze. The !! before condition is because +// __analysis_assume gets confused on some conditions: +// http://randomascii.wordpress.com/2011/09/13/analyze-for-visual-studio-the-ugly-part-5/ + +#define CHECK(condition) \ + __analysis_assume(!!(condition)), LAZY_STREAM(LOG_STREAM(FATAL), false) \ + << "Check failed: " #condition ". " + +#define PCHECK(condition) \ + __analysis_assume(!!(condition)), LAZY_STREAM(PLOG_STREAM(FATAL), false) \ + << "Check failed: " #condition ". " + +#else // _PREFAST_ + +// Do as much work as possible out of line to reduce inline code size. +#define CHECK(condition) \ + LAZY_STREAM(::logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \ + !ANALYZER_ASSUME_TRUE(condition)) + +#define PCHECK(condition) \ + LAZY_STREAM(PLOG_STREAM(FATAL), !ANALYZER_ASSUME_TRUE(condition)) \ + << "Check failed: " #condition ". " + +#endif // _PREFAST_ + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use CHECK_EQ et al below. +// The 'switch' is used to prevent the 'else' from being ambiguous when the +// macro is used in an 'if' clause such as: +// if (a == 1) +// CHECK_EQ(2, a); +#define CHECK_OP(name, op, val1, val2) \ + switch (0) \ + case 0: \ + default: \ + if (::logging::CheckOpResult true_if_passed = \ + ::logging::Check##name##Impl((val1), (val2), \ + #val1 " " #op " " #val2)) \ + ; \ + else \ + ::logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()) \ + .stream() + +#endif // !(OFFICIAL_BUILD && NDEBUG) + +// This formats a value for a failing CHECK_XX statement. Ordinarily, +// it uses the definition for operator<<, with a few special cases below. +template +inline typename std::enable_if< + base::internal::SupportsOstreamOperator::value && + !std::is_function::type>::value, + void>::type +MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << v; +} + +// Provide an overload for functions and function pointers. Function pointers +// don't implicitly convert to void* but do implicitly convert to bool, so +// without this function pointers are always printed as 1 or 0. (MSVC isn't +// standards-conforming here and converts function pointers to regular +// pointers, so this is a no-op for MSVC.) +template +inline typename std::enable_if< + std::is_function::type>::value, + void>::type +MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << reinterpret_cast(v); +} + +// We need overloads for enums that don't support operator<<. +// (i.e. scoped enums where no operator<< overload was declared). +template +inline typename std::enable_if< + !base::internal::SupportsOstreamOperator::value && + std::is_enum::value, + void>::type +MakeCheckOpValueString(std::ostream* os, const T& v) { + (*os) << static_cast::type>(v); +} + +// We need an explicit overload for std::nullptr_t. +void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p); + +// 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 +std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) { + std::ostringstream ss; + ss << names << " ("; + MakeCheckOpValueString(&ss, v1); + ss << " vs. "; + MakeCheckOpValueString(&ss, v2); + ss << ")"; + std::string* msg = new std::string(ss.str()); + return msg; +} + +// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated +// in logging.cc. +extern template std::string* MakeCheckOpString(const int&, + const int&, + const char* names); +extern template std::string* MakeCheckOpString( + const unsigned long&, + const unsigned long&, + const char* names); +extern template std::string* MakeCheckOpString( + const unsigned long&, + const unsigned int&, + const char* names); +extern template std::string* MakeCheckOpString( + const unsigned int&, + const unsigned long&, + const char* names); +extern template std::string* MakeCheckOpString( + 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. +// +// The checked condition is wrapped with ANALYZER_ASSUME_TRUE, which under +// static analysis builds, blocks analysis of the current path if the +// condition is false. +#define DEFINE_CHECK_OP_IMPL(name, op) \ + template \ + inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \ + const char* names) { \ + if (ANALYZER_ASSUME_TRUE(v1 op v2)) \ + return NULL; \ + else \ + return ::logging::MakeCheckOpString(v1, v2, names); \ + } \ + inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \ + if (ANALYZER_ASSUME_TRUE(v1 op v2)) \ + return NULL; \ + else \ + return ::logging::MakeCheckOpString(v1, v2, names); \ + } +DEFINE_CHECK_OP_IMPL(EQ, ==) +DEFINE_CHECK_OP_IMPL(NE, !=) +DEFINE_CHECK_OP_IMPL(LE, <=) +DEFINE_CHECK_OP_IMPL(LT, <) +DEFINE_CHECK_OP_IMPL(GE, >=) +DEFINE_CHECK_OP_IMPL(GT, >) +#undef DEFINE_CHECK_OP_IMPL + +#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2) +#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2) +#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2) +#define CHECK_LT(val1, val2) CHECK_OP(LT, <, val1, val2) +#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2) +#define CHECK_GT(val1, val2) CHECK_OP(GT, >, val1, val2) + +#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) +#define DCHECK_IS_ON() 0 +#else +#define DCHECK_IS_ON() 1 +#endif + +// Definitions for DLOG et al. + +#if DCHECK_IS_ON() + +#define DLOG_IS_ON(severity) LOG_IS_ON(severity) +#define DLOG_IF(severity, condition) LOG_IF(severity, condition) +#define DLOG_ASSERT(condition) LOG_ASSERT(condition) +#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition) + +#else // DCHECK_IS_ON() + +// If !DCHECK_IS_ON(), we want to avoid emitting any references to |condition| +// (which may reference a variable defined only if DCHECK_IS_ON()). +// Contrast this with DCHECK et al., which has different behavior. + +#define DLOG_IS_ON(severity) false +#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS +#define DLOG_ASSERT(condition) EAT_STREAM_PARAMETERS +#define DPLOG_IF(severity, condition) EAT_STREAM_PARAMETERS + +#endif // DCHECK_IS_ON() + +#define DLOG(severity) LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity)) + +#define DPLOG(severity) LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity)) + +// Definitions for DCHECK et al. + +#if DCHECK_IS_ON() + +#if DCHECK_IS_CONFIGURABLE +extern LogSeverity LOG_DCHECK; +#else +const LogSeverity LOG_DCHECK = LOG_FATAL; +#endif + +#else // DCHECK_IS_ON() + +// There may be users of LOG_DCHECK that are enabled independently +// of DCHECK_IS_ON(), so default to FATAL logging for those. +const LogSeverity LOG_DCHECK = LOG_FATAL; + +#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. +// +// Note that the definition of the DCHECK macros depends on whether or not +// DCHECK_IS_ON() is true. When DCHECK_IS_ON() is false, the macros use +// EAT_STREAM_PARAMETERS to avoid expressions that would create temporaries. + +#if defined(_PREFAST_) && defined(OS_WIN) +// See comments on the previous use of __analysis_assume. + +#define DCHECK(condition) \ + __analysis_assume(!!(condition)), LAZY_STREAM(LOG_STREAM(DCHECK), false) \ + << "Check failed: " #condition ". " + +#define DPCHECK(condition) \ + __analysis_assume(!!(condition)), LAZY_STREAM(PLOG_STREAM(DCHECK), false) \ + << "Check failed: " #condition ". " + +#else // !(defined(_PREFAST_) && defined(OS_WIN)) + +#if DCHECK_IS_ON() + +#define DCHECK(condition) \ + LAZY_STREAM(LOG_STREAM(DCHECK), !ANALYZER_ASSUME_TRUE(condition)) \ + << "Check failed: " #condition ". " +#define DPCHECK(condition) \ + LAZY_STREAM(PLOG_STREAM(DCHECK), !ANALYZER_ASSUME_TRUE(condition)) \ + << "Check failed: " #condition ". " + +#else // DCHECK_IS_ON() + +#define DCHECK(condition) EAT_STREAM_PARAMETERS << !(condition) +#define DPCHECK(condition) EAT_STREAM_PARAMETERS << !(condition) + +#endif // DCHECK_IS_ON() + +#endif // defined(_PREFAST_) && defined(OS_WIN) + +// Helper macro for binary operators. +// Don't use this macro directly in your code, use DCHECK_EQ et al below. +// The 'switch' is used to prevent the 'else' from being ambiguous when the +// macro is used in an 'if' clause such as: +// if (a == 1) +// DCHECK_EQ(2, a); +#if DCHECK_IS_ON() + +#define DCHECK_OP(name, op, val1, val2) \ + switch (0) \ + case 0: \ + default: \ + if (::logging::CheckOpResult true_if_passed = \ + DCHECK_IS_ON() ? ::logging::Check##name##Impl( \ + (val1), (val2), #val1 " " #op " " #val2) \ + : nullptr) \ + ; \ + else \ + ::logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, \ + true_if_passed.message()) \ + .stream() + +#else // DCHECK_IS_ON() + +// When DCHECKs aren't enabled, DCHECK_OP still needs to reference operator<< +// overloads for |val1| and |val2| to avoid potential compiler warnings about +// unused functions. For the same reason, it also compares |val1| and |val2| +// using |op|. +// +// Note that the contract of DCHECK_EQ, etc is that arguments are only evaluated +// once. Even though |val1| and |val2| appear twice in this version of the macro +// expansion, this is OK, since the expression is never actually evaluated. +#define DCHECK_OP(name, op, val1, val2) \ + EAT_STREAM_PARAMETERS << (::logging::MakeCheckOpValueString( \ + ::logging::g_swallow_stream, val1), \ + ::logging::MakeCheckOpValueString( \ + ::logging::g_swallow_stream, val2), \ + (val1)op(val2)) + +#endif // DCHECK_IS_ON() + +// 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 don't compile correctly if one of the arguments is a pointer +// and the other is NULL. In new code, prefer nullptr instead. To +// work around this for C++98, simply static_cast NULL to the type of the +// desired pointer. + +#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2) +#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2) +#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2) +#define DCHECK_LT(val1, val2) DCHECK_OP(LT, <, val1, val2) +#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2) +#define DCHECK_GT(val1, val2) DCHECK_OP(GT, >, val1, val2) + +#if !DCHECK_IS_ON() && defined(OS_CHROMEOS) +// Implement logging of NOTREACHED() as a dedicated function to get function +// call overhead down to a minimum. +void LogErrorNotReached(const char* file, int line); +#define NOTREACHED() \ + true ? ::logging::LogErrorNotReached(__FILE__, __LINE__) \ + : EAT_STREAM_PARAMETERS +#else +#define NOTREACHED() DCHECK(false) +#endif + +// Redefine the standard assert to use our nice log files +#undef assert +#define assert(x) DLOG_ASSERT(x) + +// This class more or less represents a particular log message. You +// create an instance of LogMessage and then stream stuff to it. +// When you finish streaming to it, ~LogMessage is called and the +// full message gets streamed to the appropriate destination. +// +// You shouldn't actually use LogMessage's constructor to log things, +// though. You should use the LOG() macro (and variants thereof) +// above. +class LogMessage { + public: + // Used for LOG(severity). + LogMessage(const char* file, int line, LogSeverity severity); + + // Used for CHECK(). Implied severity = LOG_FATAL. + LogMessage(const char* file, int line, const char* condition); + + // Used for CHECK_EQ(), etc. Takes ownership of the given string. + // Implied severity = LOG_FATAL. + LogMessage(const char* file, int line, std::string* result); + + // Used for DCHECK_EQ(), etc. Takes ownership of the given string. + LogMessage(const char* file, + int line, + LogSeverity severity, + std::string* result); + + ~LogMessage(); + + std::ostream& stream() { return stream_; } + + LogSeverity severity() { return severity_; } + std::string str() { return stream_.str(); } + + private: + void Init(const char* file, int line); + + LogSeverity severity_; + std::ostringstream stream_; + size_t message_start_; // Offset of the start of the message (past prefix + // info). + // The file and line information passed in to the constructor. + const char* file_; + const int line_; + +#if defined(OS_WIN) + // Stores the current value of GetLastError in the constructor and restores + // it in the destructor by calling SetLastError. + // This is useful since the LogMessage class uses a lot of Win32 calls + // that will lose the value of GLE and the code that called the log function + // will have lost the thread error value when the log call returns. + class SaveLastError { + public: + SaveLastError(); + ~SaveLastError(); + + unsigned long get_error() const { return last_error_; } + + protected: + unsigned long last_error_; + }; + + SaveLastError last_error_; +#endif + + DISALLOW_COPY_AND_ASSIGN(LogMessage); +}; + +// 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() = default; + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) {} +}; + +#if defined(OS_WIN) +typedef unsigned long SystemErrorCode; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +typedef int SystemErrorCode; +#endif + +// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to +// pull in windows.h just for GetLastError() and DWORD. +SystemErrorCode GetLastSystemErrorCode(); +std::string SystemErrorCodeToString(SystemErrorCode error_code); + +#if defined(OS_WIN) +// Appends a formatted system message of the GetLastError() type. +class Win32ErrorLogMessage { + public: + Win32ErrorLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err); + + // Appends the error message before destructing the encapsulated class. + ~Win32ErrorLogMessage(); + + std::ostream& stream() { return log_message_.stream(); } + + private: + SystemErrorCode err_; + LogMessage log_message_; + + DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage); +}; +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +// Appends a formatted system message of the errno type +class ErrnoLogMessage { + public: + ErrnoLogMessage(const char* file, + int line, + LogSeverity severity, + SystemErrorCode err); + + // Appends the error message before destructing the encapsulated class. + ~ErrnoLogMessage(); + + std::ostream& stream() { return log_message_.stream(); } + + private: + SystemErrorCode err_; + LogMessage log_message_; + + DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage); +}; +#endif // OS_WIN + +// Closes the log file explicitly if open. +// NOTE: Since the log file is opened as necessary by the action of logging +// statements, there's no guarantee that it will stay closed +// after this call. +void CloseLogFile(); + +// Async signal safe logging mechanism. +void RawLog(int level, const char* message); + +#define RAW_LOG(level, message) \ + ::logging::RawLog(::logging::LOG_##level, message) + +#define RAW_CHECK(condition) \ + do { \ + if (!(condition)) \ + ::logging::RawLog(::logging::LOG_FATAL, \ + "Check failed: " #condition "\n"); \ + } while (0) + +#if defined(OS_WIN) +// Returns true if logging to file is enabled. +bool IsLoggingToFileEnabled(); + +// Returns the default log file path. +std::wstring GetLogFileFullPath(); +#endif + +} // namespace logging + +// Note that "The behavior of a C++ program is undefined if it adds declarations +// or definitions to namespace std or to a namespace within namespace std unless +// otherwise specified." --C++11[namespace.std] +// +// We've checked that this particular definition has the intended behavior on +// our implementations, but it's prone to breaking in the future, and please +// don't imitate this in your own definitions without checking with some +// standard library experts. +namespace std { +// These functions are provided as a convenience for logging, which is where we +// use streams (it is against Google style to use streams in other places). It +// is designed to allow you to emit non-ASCII Unicode strings to the log file, +// which is normally ASCII. It is relatively slow, so try not to use it for +// common cases. Non-ASCII characters will be converted to UTF-8 by these +// operators. +std::ostream& operator<<(std::ostream& out, const wchar_t* wstr); +inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) { + return out << wstr.c_str(); +} +} // namespace std + +// The NOTIMPLEMENTED() macro annotates codepaths which have not been +// implemented yet. If output spam is a serious concern, +// NOTIMPLEMENTED_LOG_ONCE can be used. + +#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 defined(OS_ANDROID) && defined(OFFICIAL_BUILD) +#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS +#define NOTIMPLEMENTED_LOG_ONCE() EAT_STREAM_PARAMETERS +#else +#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG +#define NOTIMPLEMENTED_LOG_ONCE() \ + 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/src/3rdparty/gn/base/mac/bundle_locations.h b/src/3rdparty/gn/base/mac/bundle_locations.h new file mode 100644 index 00000000000..2bda76e6411 --- /dev/null +++ b/src/3rdparty/gn/base/mac/bundle_locations.h @@ -0,0 +1,65 @@ +// 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_MAC_BUNDLE_LOCATIONS_H_ +#define BASE_MAC_BUNDLE_LOCATIONS_H_ + +#include "base/files/file_path.h" + +#if defined(__OBJC__) +#import +#else // __OBJC__ +class NSBundle; +#endif // __OBJC__ + +namespace base { + +class FilePath; + +namespace mac { + +// This file provides several functions to explicitly request the various +// component bundles of Chrome. Please use these methods rather than calling +// +[NSBundle mainBundle] or CFBundleGetMainBundle(). +// +// Terminology +// - "Outer Bundle" - This is the main bundle for Chrome; it's what +// +[NSBundle mainBundle] returns when Chrome is launched normally. +// +// - "Main Bundle" - This is the bundle from which Chrome was launched. +// This will be the same as the outer bundle except when Chrome is launched +// via an app shortcut, in which case this will return the app shortcut's +// bundle rather than the main Chrome bundle. +// +// - "Framework Bundle" - This is the bundle corresponding to the Chrome +// framework. +// +// Guidelines for use: +// - To access a resource, the Framework bundle should be used. +// - If the choice is between the Outer or Main bundles then please choose +// carefully. Most often the Outer bundle will be the right choice, but for +// cases such as adding an app to the "launch on startup" list, the Main +// bundle is probably the one to use. + +// Methods for retrieving the various bundles. +NSBundle* MainBundle(); +FilePath MainBundlePath(); +NSBundle* OuterBundle(); +FilePath OuterBundlePath(); +NSBundle* FrameworkBundle(); +FilePath FrameworkBundlePath(); + +// Set the bundle that the preceding functions will return, overriding the +// default values. Restore the default by passing in |nil|. +void SetOverrideOuterBundle(NSBundle* bundle); +void SetOverrideFrameworkBundle(NSBundle* bundle); + +// Same as above but accepting a FilePath argument. +void SetOverrideOuterBundlePath(const FilePath& file_path); +void SetOverrideFrameworkBundlePath(const FilePath& file_path); + +} // namespace mac +} // namespace base + +#endif // BASE_MAC_BUNDLE_LOCATIONS_H_ diff --git a/src/3rdparty/gn/base/mac/mac_logging.h b/src/3rdparty/gn/base/mac/mac_logging.h new file mode 100644 index 00000000000..5ef75f38323 --- /dev/null +++ b/src/3rdparty/gn/base/mac/mac_logging.h @@ -0,0 +1,74 @@ +// 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_MAC_MAC_LOGGING_H_ +#define BASE_MAC_MAC_LOGGING_H_ + +#include "base/logging.h" +#include "base/macros.h" +#include "util/build_config.h" + +#if defined(OS_IOS) +#include +#else +#include +#endif + +// Use the OSSTATUS_LOG family to log messages related to errors in Mac OS X +// system routines that report status via an OSStatus or OSErr value. It is +// similar to the PLOG family which operates on errno, but because there is no +// global (or thread-local) OSStatus or OSErr value, the specific error must +// be supplied as an argument to the OSSTATUS_LOG macro. The message logged +// will contain the symbolic constant name corresponding to the status value, +// along with the value itself. +// +// OSErr is just an older 16-bit form of the newer 32-bit OSStatus. Despite +// the name, OSSTATUS_LOG can be used equally well for OSStatus and OSErr. + +namespace logging { + +// Returns a UTF8 description from an OS X Status error. +std::string DescriptionFromOSStatus(OSStatus err); + +class OSStatusLogMessage : public logging::LogMessage { + public: + OSStatusLogMessage(const char* file_path, + int line, + LogSeverity severity, + OSStatus status); + ~OSStatusLogMessage(); + + private: + OSStatus status_; + + DISALLOW_COPY_AND_ASSIGN(OSStatusLogMessage); +}; + +} // namespace logging + +#define OSSTATUS_LOG_STREAM(severity, status) \ + COMPACT_GOOGLE_LOG_EX_##severity(OSStatusLogMessage, status).stream() + +#define OSSTATUS_LOG(severity, status) \ + LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), LOG_IS_ON(severity)) +#define OSSTATUS_LOG_IF(severity, condition, status) \ + LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), \ + LOG_IS_ON(severity) && (condition)) + +#define OSSTATUS_CHECK(condition, status) \ + LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), !(condition)) \ + << "Check failed: " #condition << ". " + +#define OSSTATUS_DLOG(severity, status) \ + LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), DLOG_IS_ON(severity)) +#define OSSTATUS_DLOG_IF(severity, condition, status) \ + LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), \ + DLOG_IS_ON(severity) && (condition)) + +#define OSSTATUS_DCHECK(condition, status) \ + LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \ + DCHECK_IS_ON() && !(condition)) \ + << "Check failed: " #condition << ". " + +#endif // BASE_MAC_MAC_LOGGING_H_ diff --git a/src/3rdparty/gn/base/mac/mac_logging.mm b/src/3rdparty/gn/base/mac/mac_logging.mm new file mode 100644 index 00000000000..f7c30528bc5 --- /dev/null +++ b/src/3rdparty/gn/base/mac/mac_logging.mm @@ -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/mac/mac_logging.h" + +#import + +#include + +#include "util/build_config.h" + +#if !defined(OS_IOS) +#include +#endif + +namespace logging { + +std::string DescriptionFromOSStatus(OSStatus err) { + NSError* error = + [NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil]; + return error.description.UTF8String; +} + +OSStatusLogMessage::OSStatusLogMessage(const char* file_path, + int line, + LogSeverity severity, + OSStatus status) + : LogMessage(file_path, line, severity), status_(status) {} + +OSStatusLogMessage::~OSStatusLogMessage() { +#if defined(OS_IOS) + // TODO(crbug.com/546375): Consider using NSError with NSOSStatusErrorDomain + // to try to get a description of the failure. + stream() << ": " << status_; +#else + stream() << ": " << DescriptionFromOSStatus(status_) << " (" << status_ + << ")"; +#endif +} + +} // namespace logging diff --git a/src/3rdparty/gn/base/mac/scoped_cftyperef.h b/src/3rdparty/gn/base/mac/scoped_cftyperef.h new file mode 100644 index 00000000000..a602fd9cbb2 --- /dev/null +++ b/src/3rdparty/gn/base/mac/scoped_cftyperef.h @@ -0,0 +1,48 @@ +// 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_MAC_SCOPED_CFTYPEREF_H_ +#define BASE_MAC_SCOPED_CFTYPEREF_H_ + +#include + +#include "base/mac/scoped_typeref.h" + +namespace base { + +// ScopedCFTypeRef<> is patterned after std::unique_ptr<>, but maintains +// ownership of a CoreFoundation object: any object that can be represented +// as a CFTypeRef. Style deviations here are solely for compatibility with +// std::unique_ptr<>'s interface, with which everyone is already familiar. +// +// By default, ScopedCFTypeRef<> takes ownership of an object (in the +// constructor or in reset()) by taking over the caller's existing ownership +// claim. The caller must own the object it gives to ScopedCFTypeRef<>, and +// relinquishes an ownership claim to that object. ScopedCFTypeRef<> does not +// call CFRetain(). This behavior is parameterized by the |OwnershipPolicy| +// enum. If the value |RETAIN| is passed (in the constructor or in reset()), +// then ScopedCFTypeRef<> will call CFRetain() on the object, and the initial +// ownership is not changed. + +namespace internal { + +template +struct ScopedCFTypeRefTraits { + static CFT InvalidValue() { return nullptr; } + static CFT Retain(CFT object) { + CFRetain(object); + return object; + } + static void Release(CFT object) { CFRelease(object); } +}; + +} // namespace internal + +template +using ScopedCFTypeRef = + ScopedTypeRef>; + +} // namespace base + +#endif // BASE_MAC_SCOPED_CFTYPEREF_H_ diff --git a/src/3rdparty/gn/base/mac/scoped_typeref.h b/src/3rdparty/gn/base/mac/scoped_typeref.h new file mode 100644 index 00000000000..659ee3426b0 --- /dev/null +++ b/src/3rdparty/gn/base/mac/scoped_typeref.h @@ -0,0 +1,138 @@ +// 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_MAC_SCOPED_TYPEREF_H_ +#define BASE_MAC_SCOPED_TYPEREF_H_ + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/memory/scoped_policy.h" + +namespace base { + +// ScopedTypeRef<> is patterned after std::unique_ptr<>, but maintains ownership +// of a reference to any type that is maintained by Retain and Release methods. +// +// The Traits structure must provide the Retain and Release methods for type T. +// A default ScopedTypeRefTraits is used but not defined, and should be defined +// for each type to use this interface. For example, an appropriate definition +// of ScopedTypeRefTraits for CGLContextObj would be: +// +// template<> +// struct ScopedTypeRefTraits { +// static CGLContextObj InvalidValue() { return nullptr; } +// static CGLContextObj Retain(CGLContextObj object) { +// CGLContextRetain(object); +// return object; +// } +// static void Release(CGLContextObj object) { CGLContextRelease(object); } +// }; +// +// For the many types that have pass-by-pointer create functions, the function +// InitializeInto() is provided to allow direct initialization and assumption +// of ownership of the object. For example, continuing to use the above +// CGLContextObj specialization: +// +// base::ScopedTypeRef context; +// CGLCreateContext(pixel_format, share_group, context.InitializeInto()); +// +// For initialization with an existing object, the caller may specify whether +// the ScopedTypeRef<> being initialized is assuming the caller's existing +// ownership of the object (and should not call Retain in initialization) or if +// it should not assume this ownership and must create its own (by calling +// Retain in initialization). This behavior is based on the |policy| parameter, +// with |ASSUME| for the former and |RETAIN| for the latter. The default policy +// is to |ASSUME|. + +template +struct ScopedTypeRefTraits; + +template > +class ScopedTypeRef { + public: + typedef T element_type; + + explicit constexpr ScopedTypeRef( + __unsafe_unretained T object = Traits::InvalidValue(), + base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME) + : object_(object) { + if (object_ && policy == base::scoped_policy::RETAIN) + object_ = Traits::Retain(object_); + } + + ScopedTypeRef(const ScopedTypeRef& that) : object_(that.object_) { + if (object_) + object_ = Traits::Retain(object_); + } + + // This allows passing an object to a function that takes its superclass. + template + explicit ScopedTypeRef(const ScopedTypeRef& that_as_subclass) + : object_(that_as_subclass.get()) { + if (object_) + object_ = Traits::Retain(object_); + } + + ScopedTypeRef(ScopedTypeRef&& that) : object_(that.object_) { + that.object_ = Traits::InvalidValue(); + } + + ~ScopedTypeRef() { + if (object_) + Traits::Release(object_); + } + + ScopedTypeRef& operator=(const ScopedTypeRef& that) { + reset(that.get(), base::scoped_policy::RETAIN); + return *this; + } + + // This is to be used only to take ownership of objects that are created + // by pass-by-pointer create functions. To enforce this, require that the + // object be reset to NULL before this may be used. + T* InitializeInto() WARN_UNUSED_RESULT { + DCHECK(!object_); + return &object_; + } + + void reset(__unsafe_unretained T object = Traits::InvalidValue(), + base::scoped_policy::OwnershipPolicy policy = + base::scoped_policy::ASSUME) { + if (object && policy == base::scoped_policy::RETAIN) + object = Traits::Retain(object); + if (object_) + Traits::Release(object_); + object_ = object; + } + + bool operator==(__unsafe_unretained T that) const { return object_ == that; } + + bool operator!=(__unsafe_unretained T that) const { return object_ != that; } + + operator T() const __attribute((ns_returns_not_retained)) { return object_; } + + T get() const __attribute((ns_returns_not_retained)) { return object_; } + + void swap(ScopedTypeRef& that) { + __unsafe_unretained T temp = that.object_; + that.object_ = object_; + object_ = temp; + } + + // ScopedTypeRef<>::release() is like std::unique_ptr<>::release. It is NOT + // a wrapper for Release(). To force a ScopedTypeRef<> object to call + // Release(), use ScopedTypeRef<>::reset(). + T release() __attribute((ns_returns_not_retained)) WARN_UNUSED_RESULT { + __unsafe_unretained T temp = object_; + object_ = Traits::InvalidValue(); + return temp; + } + + private: + __unsafe_unretained T object_; +}; + +} // namespace base + +#endif // BASE_MAC_SCOPED_TYPEREF_H_ diff --git a/src/3rdparty/gn/base/macros.h b/src/3rdparty/gn/base/macros.h new file mode 100644 index 00000000000..321f65bc513 --- /dev/null +++ b/src/3rdparty/gn/base/macros.h @@ -0,0 +1,94 @@ +// 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 // For size_t. + +// Distinguish mips32. +#if defined(__mips__) && (_MIPS_SIM == _ABIO32) && !defined(__mips32__) +#define __mips32__ +#endif + +// Distinguish mips64. +#if defined(__mips__) && (_MIPS_SIM == _ABI64) && !defined(__mips64__) +#define __mips64__ +#endif + +// 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) TypeName& operator=(const TypeName&) = delete + +// Put this in the declarations for a class to be uncopyable and unassignable. +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + DISALLOW_COPY(TypeName); \ + DISALLOW_ASSIGN(TypeName) + +// A macro to disallow all the implicit constructors, namely the +// default constructor, copy constructor and operator= functions. +// This is especially useful for classes containing only static methods. +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName() = delete; \ + DISALLOW_COPY_AND_ASSIGN(TypeName) + +// The arraysize(arr) macro returns the # of elements in an array arr. The +// expression is a compile-time constant, and therefore can be used in defining +// new arrays, for example. If you use arraysize on a pointer by mistake, you +// will get a compile-time error. For the technical details, refer to +// http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx. + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +// +// DEPRECATED, please use base::size(array) instead. +// TODO(https://crbug.com/837308): Replace existing arraysize usages. +template +char (&ArraySizeHelper(T (&array)[N]))[N]; +#define arraysize(array) (sizeof(ArraySizeHelper(array))) + +// Used to explicitly mark the return value of a function as unused. If you are +// really sure you don't want to do anything with the return value of a function +// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example: +// +// std::unique_ptr my_var = ...; +// if (TakeOwnership(my_var.get()) == SUCCESS) +// ignore_result(my_var.release()); +// +template +inline void ignore_result(const T&) {} + +namespace base { + +// 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. This is +// thread-safe. +// +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DEPRECATED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// Please don't use this macro. Use a function-local static of type +// base::NoDestructor instead: +// +// Factory& Factory::GetInstance() { +// static base::NoDestructor instance; +// return *instance; +// } +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \ + static type& name = *new type arguments + +// Workaround for MSVC, which expands __VA_ARGS__ as one macro argument. To +// work around this bug, wrap the entire expression in this macro... +#define CR_EXPAND_ARG(arg) arg + +} // namespace base + +#endif // BASE_MACROS_H_ diff --git a/src/3rdparty/gn/base/md5.cc b/src/3rdparty/gn/base/md5.cc new file mode 100644 index 00000000000..c66f7b220c1 --- /dev/null +++ b/src/3rdparty/gn/base/md5.cc @@ -0,0 +1,299 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// The original file was copied from sqlite, and was in the public domain. + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include "base/md5.h" + +#include + +namespace { + +struct Context { + uint32_t buf[4]; + uint32_t bits[2]; + uint8_t in[64]; +}; + +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(uint8_t* buf, unsigned longs) { + do { + uint32_t temp = + static_cast(static_cast(buf[3]) << 8 | buf[2]) + << 16 | + (static_cast(buf[1]) << 8 | buf[0]); + *reinterpret_cast(buf) = temp; + buf += 4; + } while (--longs); +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32_t buf[4], const uint32_t in[16]) { + uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +} // namespace + +namespace base { + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(MD5Context* context) { + struct Context* ctx = reinterpret_cast(context); + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(MD5Context* context, const StringPiece& data) { + struct Context* ctx = reinterpret_cast(context); + const uint8_t* buf = reinterpret_cast(data.data()); + size_t len = data.size(); + + /* Update bitcount */ + + uint32_t t = ctx->bits[0]; + if ((ctx->bits[0] = t + (static_cast(len) << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += static_cast(len >> 29); + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + uint8_t* p = static_cast(ctx->in + t); + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, reinterpret_cast(ctx->in)); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, reinterpret_cast(ctx->in)); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(MD5Digest* digest, MD5Context* context) { + struct Context* ctx = reinterpret_cast(context); + unsigned count; + uint8_t* p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, reinterpret_cast(ctx->in)); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + memcpy(&ctx->in[14 * sizeof(ctx->bits[0])], &ctx->bits[0], + sizeof(ctx->bits[0])); + memcpy(&ctx->in[15 * sizeof(ctx->bits[1])], &ctx->bits[1], + sizeof(ctx->bits[1])); + + MD5Transform(ctx->buf, reinterpret_cast(ctx->in)); + byteReverse(reinterpret_cast(ctx->buf), 4); + memcpy(digest->a, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +void MD5IntermediateFinal(MD5Digest* digest, const MD5Context* context) { + /* MD5Final mutates the MD5Context*. Make a copy for generating the + intermediate value. */ + MD5Context context_copy; + memcpy(&context_copy, context, sizeof(context_copy)); + MD5Final(digest, &context_copy); +} + +std::string MD5DigestToBase16(const MD5Digest& digest) { + static char const zEncode[] = "0123456789abcdef"; + + std::string ret; + ret.resize(32); + + for (int i = 0, j = 0; i < 16; i++, j += 2) { + uint8_t a = digest.a[i]; + ret[j] = zEncode[(a >> 4) & 0xf]; + ret[j + 1] = zEncode[a & 0xf]; + } + return ret; +} + +void MD5Sum(const void* data, size_t length, MD5Digest* digest) { + MD5Context ctx; + MD5Init(&ctx); + MD5Update(&ctx, StringPiece(reinterpret_cast(data), length)); + MD5Final(digest, &ctx); +} + +std::string MD5String(const StringPiece& str) { + MD5Digest digest; + MD5Sum(str.data(), str.length(), &digest); + return MD5DigestToBase16(digest); +} + +} // namespace base diff --git a/src/3rdparty/gn/base/md5.h b/src/3rdparty/gn/base/md5.h new file mode 100644 index 00000000000..16a0a6f90d9 --- /dev/null +++ b/src/3rdparty/gn/base/md5.h @@ -0,0 +1,76 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_MD5_H_ +#define BASE_MD5_H_ + +#include +#include + +#include "base/strings/string_piece.h" + +namespace base { + +// MD5 stands for Message Digest algorithm 5. +// MD5 is a robust hash function, designed for cyptography, but often used +// for file checksums. The code is complex and slow, but has few +// collisions. +// See Also: +// http://en.wikipedia.org/wiki/MD5 + +// These functions perform MD5 operations. The simplest call is MD5Sum() to +// generate the MD5 sum of the given data. +// +// You can also compute the MD5 sum of data incrementally by making multiple +// calls to MD5Update(): +// MD5Context ctx; // intermediate MD5 data: do not use +// MD5Init(&ctx); +// MD5Update(&ctx, data1, length1); +// MD5Update(&ctx, data2, length2); +// ... +// +// MD5Digest digest; // the result of the computation +// MD5Final(&digest, &ctx); +// +// You can call MD5DigestToBase16() to generate a string of the digest. + +// The output of an MD5 operation. +struct MD5Digest { + uint8_t a[16]; +}; + +// Used for storing intermediate data during an MD5 computation. Callers +// should not access the data. +typedef char MD5Context[88]; + +// Initializes the given MD5 context structure for subsequent calls to +// MD5Update(). +void MD5Init(MD5Context* context); + +// For the given buffer of |data| as a StringPiece, updates the given MD5 +// context with the sum of the data. You can call this any number of times +// during the computation, except that MD5Init() must have been called first. +void MD5Update(MD5Context* context, const StringPiece& data); + +// Finalizes the MD5 operation and fills the buffer with the digest. +void MD5Final(MD5Digest* digest, MD5Context* context); + +// MD5IntermediateFinal() generates a digest without finalizing the MD5 +// operation. Can be used to generate digests for the input seen thus far, +// without affecting the digest generated for the entire input. +void MD5IntermediateFinal(MD5Digest* digest, const MD5Context* context); + +// Converts a digest into human-readable hexadecimal. +std::string MD5DigestToBase16(const MD5Digest& digest); + +// Computes the MD5 sum of the given data buffer with the given length. +// The given 'digest' structure will be filled with the result data. +void MD5Sum(const void* data, size_t length, MD5Digest* digest); + +// Returns the MD5 (in hexadecimal) of a string. +std::string MD5String(const StringPiece& str); + +} // namespace base + +#endif // BASE_MD5_H_ diff --git a/src/3rdparty/gn/base/memory/free_deleter.h b/src/3rdparty/gn/base/memory/free_deleter.h new file mode 100644 index 00000000000..e12795c7a88 --- /dev/null +++ b/src/3rdparty/gn/base/memory/free_deleter.h @@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_MEMORY_FREE_DELETER_H_ +#define BASE_MEMORY_FREE_DELETER_H_ + +#include + +namespace base { + +// Function object which invokes 'free' on its parameter, which must be +// a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr: +// +// std::unique_ptr foo_ptr( +// static_cast(malloc(sizeof(int)))); +struct FreeDeleter { + inline void operator()(void* ptr) const { free(ptr); } +}; + +} // namespace base + +#endif // BASE_MEMORY_FREE_DELETER_H_ diff --git a/src/3rdparty/gn/base/memory/ptr_util.h b/src/3rdparty/gn/base/memory/ptr_util.h new file mode 100644 index 00000000000..42f4f49eebd --- /dev/null +++ b/src/3rdparty/gn/base/memory/ptr_util.h @@ -0,0 +1,23 @@ +// Copyright 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. + +#ifndef BASE_MEMORY_PTR_UTIL_H_ +#define BASE_MEMORY_PTR_UTIL_H_ + +#include +#include + +namespace base { + +// Helper to transfer ownership of a raw pointer to a std::unique_ptr. +// Note that std::unique_ptr has very different semantics from +// std::unique_ptr: do not use this helper for array allocations. +template +std::unique_ptr WrapUnique(T* ptr) { + return std::unique_ptr(ptr); +} + +} // namespace base + +#endif // BASE_MEMORY_PTR_UTIL_H_ diff --git a/src/3rdparty/gn/base/memory/raw_scoped_refptr_mismatch_checker.h b/src/3rdparty/gn/base/memory/raw_scoped_refptr_mismatch_checker.h new file mode 100644 index 00000000000..ab8b2abcbb9 --- /dev/null +++ b/src/3rdparty/gn/base/memory/raw_scoped_refptr_mismatch_checker.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. + +#ifndef BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ +#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ + +#include + +#include "base/template_util.h" + +// It is dangerous to post a task with a T* argument where T is a subtype of +// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the +// object may already have been deleted since it was not held with a +// scoped_refptr. Example: http://crbug.com/27191 +// The following set of traits are designed to generate a compile error +// whenever this antipattern is attempted. + +namespace base { + +// This is a base internal implementation file used by task.h and callback.h. +// Not for public consumption, so we wrap it in namespace internal. +namespace internal { + +template +struct IsRefCountedType : std::false_type {}; + +template +struct IsRefCountedType()->AddRef()), + decltype(std::declval()->Release())>> + : std::true_type {}; + +template +struct NeedsScopedRefptrButGetsRawPtr { + static_assert(!std::is_reference::value, + "NeedsScopedRefptrButGetsRawPtr requires non-reference type."); + + enum { + // Human readable translation: you needed to be a scoped_refptr if you are a + // raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase) + // type. + value = std::is_pointer::value && + IsRefCountedType>::value + }; +}; + +} // namespace internal + +} // namespace base + +#endif // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_ diff --git a/src/3rdparty/gn/base/memory/ref_counted.cc b/src/3rdparty/gn/base/memory/ref_counted.cc new file mode 100644 index 00000000000..79ab8535a5e --- /dev/null +++ b/src/3rdparty/gn/base/memory/ref_counted.cc @@ -0,0 +1,35 @@ +// 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_.IsOne(); +} + +#if defined(ARCH_CPU_64_BIT) +void RefCountedBase::AddRefImpl() const { + // Check if |ref_count_| overflow only on 64 bit archs since the number of + // objects may exceed 2^32. + // To avoid the binary size bloat, use non-inline function here. + CHECK(++ref_count_ > 0); +} +#endif + +#if !defined(ARCH_CPU_X86_FAMILY) +bool RefCountedThreadSafeBase::Release() const { + return ReleaseImpl(); +} +void RefCountedThreadSafeBase::AddRef() const { + AddRefImpl(); +} +#endif + +} // namespace subtle + +} // namespace base diff --git a/src/3rdparty/gn/base/memory/ref_counted.h b/src/3rdparty/gn/base/memory/ref_counted.h new file mode 100644 index 00000000000..8ebdcd68b5b --- /dev/null +++ b/src/3rdparty/gn/base/memory/ref_counted.h @@ -0,0 +1,317 @@ +// 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 + +#include + +#include "base/atomic_ref_count.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "util/build_config.h" + +namespace base { +namespace subtle { + +class RefCountedBase { + public: + bool HasOneRef() const { return ref_count_ == 1; } + + protected: + explicit RefCountedBase(StartRefCountFromZeroTag) {} + + explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {} + + ~RefCountedBase() {} + + void AddRef() const { AddRefImpl(); } + + // Returns true if the object should self-delete. + bool Release() const { + --ref_count_; + + // TODO(maruel): Add back once it doesn't assert 500 times/sec. + // Current thread books the critical section "AddRelease" + // without release it. + // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); + + return ref_count_ == 0; + } + + // Returns true if it is safe to read or write the object, from a thread + // safety standpoint. Should be DCHECK'd from the methods of RefCounted + // classes if there is a danger of objects being shared across threads. + // + // This produces fewer false positives than adding a separate SequenceChecker + // into the subclass, because it automatically detaches from the sequence when + // the reference count is 1 (and never fails if there is only one reference). + // + // This means unlike a separate SequenceChecker, it will permit a singly + // referenced object to be passed between threads (not holding a reference on + // the sending thread), but will trap if the sending thread holds onto a + // reference, or if the object is accessed from multiple threads + // simultaneously. + bool IsOnValidSequence() const { return true; } + + private: + template + friend scoped_refptr base::AdoptRef(U*); + + void Adopted() const {} + +#if defined(ARCH_CPU_64_BIT) + void AddRefImpl() const; +#else + void AddRefImpl() const { ++ref_count_; } +#endif + + mutable uint32_t ref_count_ = 0; + + DISALLOW_COPY_AND_ASSIGN(RefCountedBase); +}; + +class RefCountedThreadSafeBase { + public: + bool HasOneRef() const; + + protected: + explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} + explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag) + : ref_count_(1) {} + + ~RefCountedThreadSafeBase() = default; + +// Release and AddRef are suitable for inlining on X86 because they generate +// very small code sequences. On other platforms (ARM), it causes a size +// regression and is probably not worth it. +#if defined(ARCH_CPU_X86_FAMILY) + // Returns true if the object should self-delete. + bool Release() const { return ReleaseImpl(); } + void AddRef() const { AddRefImpl(); } +#else + // Returns true if the object should self-delete. + bool Release() const; + void AddRef() const; +#endif + + private: + template + friend scoped_refptr base::AdoptRef(U*); + + void Adopted() const {} + + ALWAYS_INLINE void AddRefImpl() const { ref_count_.Increment(); } + + ALWAYS_INLINE bool ReleaseImpl() const { + if (!ref_count_.Decrement()) { + return true; + } + return false; + } + + mutable AtomicRefCount ref_count_{0}; + + DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); +}; + +} // namespace subtle + +// ScopedAllowCrossThreadRefCountAccess disables the check documented on +// RefCounted below for rare pre-existing use cases where thread-safety was +// guaranteed through other means (e.g. explicit sequencing of calls across +// execution sequences when bouncing between threads in order). New callers +// should refrain from using this (callsites handling thread-safety through +// locks should use RefCountedThreadSafe per the overhead of its atomics being +// negligible compared to locks anyways and callsites doing explicit sequencing +// should properly std::move() the ref to avoid hitting this check). +// TODO(tzik): Cleanup existing use cases and remove +// ScopedAllowCrossThreadRefCountAccess. +class ScopedAllowCrossThreadRefCountAccess final { + public: + ScopedAllowCrossThreadRefCountAccess() {} + ~ScopedAllowCrossThreadRefCountAccess() {} +}; + +// +// A base class for reference counted classes. Otherwise, known as a cheap +// knock-off of WebKit's RefCounted class. To use this, just extend your +// class from it like so: +// +// class MyFoo : public base::RefCounted { +// ... +// private: +// friend class base::RefCounted; +// ~MyFoo(); +// }; +// +// You should always make your destructor non-public, to avoid any code deleting +// the object accidently while there are references to it. +// +// +// The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs +// to trap unsafe cross thread usage. A subclass instance of RefCounted can be +// passed to another execution sequence only when its ref count is 1. If the ref +// count is more than 1, the RefCounted class verifies the ref updates are made +// on the same execution sequence as the previous ones. The subclass can also +// manually call IsOnValidSequence to trap other non-thread-safe accesses; see +// the documentation for that method. +// +// +// The reference count starts from zero by default, and we intended to migrate +// to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to +// the ref counted class to opt-in. +// +// If an object has start-from-one ref count, the first scoped_refptr need to be +// created by base::AdoptRef() or base::MakeRefCounted(). We can use +// base::MakeRefCounted() to create create both type of ref counted object. +// +// The motivations to use start-from-one ref count are: +// - Start-from-one ref count doesn't need the ref count increment for the +// first reference. +// - It can detect an invalid object acquisition for a being-deleted object +// that has zero ref count. That tends to happen on custom deleter that +// delays the deletion. +// TODO(tzik): Implement invalid acquisition detection. +// - Behavior parity to Blink's WTF::RefCounted, whose count starts from one. +// And start-from-one ref count is a step to merge WTF::RefCounted into +// base::RefCounted. +// +#define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \ + static constexpr ::base::subtle::StartRefCountFromOneTag \ + kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag + +template +class RefCounted; + +template +struct DefaultRefCountedTraits { + static void Destruct(const T* x) { + RefCounted::DeleteInternal(x); + } +}; + +template > +class RefCounted : public subtle::RefCountedBase { + public: + static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = + subtle::kStartRefCountFromZeroTag; + + RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {} + + void AddRef() const { subtle::RefCountedBase::AddRef(); } + + void Release() const { + if (subtle::RefCountedBase::Release()) { + // Prune the code paths which the static analyzer may take to simulate + // object destruction. Use-after-free errors aren't possible given the + // lifetime guarantees of the refcounting system. + ANALYZER_SKIP_THIS_PATH(); + + Traits::Destruct(static_cast(this)); + } + } + + protected: + ~RefCounted() = default; + + private: + friend struct DefaultRefCountedTraits; + template + static void DeleteInternal(const U* x) { + delete x; + } + + DISALLOW_COPY_AND_ASSIGN(RefCounted); +}; + +// Forward declaration. +template +class RefCountedThreadSafe; + +// Default traits for RefCountedThreadSafe. Deletes the object when its ref +// count reaches 0. Overload to delete it on a different thread etc. +template +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::DeleteInternal( + x); + } +}; + +// +// A thread-safe variant of RefCounted +// +// class MyFoo : public base::RefCountedThreadSafe { +// ... +// }; +// +// 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(); +// +// We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe +// too. See the comment above the RefCounted definition for details. +template > +class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { + public: + static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = + subtle::kStartRefCountFromZeroTag; + + explicit RefCountedThreadSafe() + : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} + + void AddRef() const { subtle::RefCountedThreadSafeBase::AddRef(); } + + void Release() const { + if (subtle::RefCountedThreadSafeBase::Release()) { + ANALYZER_SKIP_THIS_PATH(); + Traits::Destruct(static_cast(this)); + } + } + + protected: + ~RefCountedThreadSafe() = default; + + private: + friend struct DefaultRefCountedThreadSafeTraits; + template + static void DeleteInternal(const U* 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 +class RefCountedData + : public base::RefCountedThreadSafe> { + public: + RefCountedData() : data() {} + RefCountedData(const T& in_value) : data(in_value) {} + RefCountedData(T&& in_value) : data(std::move(in_value)) {} + + T data; + + private: + friend class base::RefCountedThreadSafe>; + ~RefCountedData() = default; +}; + +} // namespace base + +#endif // BASE_MEMORY_REF_COUNTED_H_ diff --git a/src/3rdparty/gn/base/memory/scoped_policy.h b/src/3rdparty/gn/base/memory/scoped_policy.h new file mode 100644 index 00000000000..5dbf2048d64 --- /dev/null +++ b/src/3rdparty/gn/base/memory/scoped_policy.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_MEMORY_SCOPED_POLICY_H_ +#define BASE_MEMORY_SCOPED_POLICY_H_ + +namespace base { +namespace scoped_policy { + +// Defines the ownership policy for a scoped object. +enum OwnershipPolicy { + // The scoped object takes ownership of an object by taking over an existing + // ownership claim. + ASSUME, + + // The scoped object will retain the the object and any initial ownership is + // not changed. + RETAIN +}; + +} // namespace scoped_policy +} // namespace base + +#endif // BASE_MEMORY_SCOPED_POLICY_H_ diff --git a/src/3rdparty/gn/base/memory/scoped_refptr.h b/src/3rdparty/gn/base/memory/scoped_refptr.h new file mode 100644 index 00000000000..a2576170bf9 --- /dev/null +++ b/src/3rdparty/gn/base/memory/scoped_refptr.h @@ -0,0 +1,333 @@ +// Copyright 2017 The Chromium 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_SCOPED_REFPTR_H_ +#define BASE_MEMORY_SCOPED_REFPTR_H_ + +#include + +#include +#include +#include + +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/macros.h" + +template +class scoped_refptr; + +namespace base { + +template +class RefCounted; +template +class RefCountedThreadSafe; + +template +scoped_refptr AdoptRef(T* t); + +namespace subtle { + +enum AdoptRefTag { kAdoptRefTag }; +enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag }; +enum StartRefCountFromOneTag { kStartRefCountFromOneTag }; + +template +constexpr bool IsRefCountPreferenceOverridden(const T*, + const RefCounted*) { + return !std::is_same, + std::decay_t>::value; +} + +template +constexpr bool IsRefCountPreferenceOverridden( + const T*, + const RefCountedThreadSafe*) { + return !std::is_same, + std::decay_t>::value; +} + +constexpr bool IsRefCountPreferenceOverridden(...) { + return false; +} + +} // namespace subtle + +// Creates a scoped_refptr from a raw pointer without incrementing the reference +// count. Use this only for a newly created object whose reference count starts +// from 1 instead of 0. +template +scoped_refptr AdoptRef(T* obj) { + using Tag = std::decay_t; + static_assert(std::is_same::value, + "Use AdoptRef only for the reference count starts from one."); + + DCHECK(obj); + DCHECK(obj->HasOneRef()); + obj->Adopted(); + return scoped_refptr(obj, subtle::kAdoptRefTag); +} + +namespace subtle { + +template +scoped_refptr AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) { + return scoped_refptr(obj); +} + +template +scoped_refptr AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) { + return AdoptRef(obj); +} + +} // namespace subtle + +// Constructs an instance of T, which is a ref counted type, and wraps the +// object into a scoped_refptr. +template +scoped_refptr MakeRefCounted(Args&&... args) { + T* obj = new T(std::forward(args)...); + return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference); +} + +// Takes an instance of T, which is a ref counted type, and wraps the object +// into a scoped_refptr. +template +scoped_refptr WrapRefCounted(T* t) { + return scoped_refptr(t); +} + +} // 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 { +// ... +// private: +// friend class RefCounted; // Allow destruction by RefCounted<>. +// ~MyFoo(); // Destructor must be private/protected. +// }; +// +// void some_function() { +// scoped_refptr foo = MakeRefCounted(); +// foo->Method(param); +// // |foo| is released when this function returns +// } +// +// void some_other_function() { +// scoped_refptr foo = MakeRefCounted(); +// ... +// foo = nullptr; // explicitly releases |foo| +// ... +// if (foo) +// foo->Method(param); +// } +// +// The above examples show how scoped_refptr acts like a pointer to T. +// Given two scoped_refptr classes, it is also possible to exchange +// references between the two objects, like so: +// +// { +// scoped_refptr a = MakeRefCounted(); +// scoped_refptr b; +// +// b.swap(a); +// // now, |b| references the MyFoo object, and |a| references nullptr. +// } +// +// To make both |a| and |b| in the above example reference the same MyFoo +// object, simply use the assignment operator: +// +// { +// scoped_refptr a = MakeRefCounted(); +// scoped_refptr b; +// +// b = a; +// // now, |a| and |b| each own a reference to the same MyFoo object. +// } +// +// Also see Chromium's ownership and calling conventions: +// https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions +// Specifically: +// If the function (at least sometimes) takes a ref on a refcounted object, +// declare the param as scoped_refptr. The caller can decide whether it +// wishes to transfer ownership (by calling std::move(t) when passing t) or +// retain its ref (by simply passing t directly). +// In other words, use scoped_refptr like you would a std::unique_ptr except +// in the odd case where it's required to hold on to a ref while handing one +// to another component (if a component merely needs to use t on the stack +// without keeping a ref: pass t as a raw T*). +template +class scoped_refptr { + public: + typedef T element_type; + + constexpr scoped_refptr() = default; + + // Constructs from raw pointer. constexpr if |p| is null. + constexpr scoped_refptr(T* p) : ptr_(p) { + if (ptr_) + AddRef(ptr_); + } + + // Copy constructor. This is required in addition to the copy conversion + // constructor below. + scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {} + + // Copy conversion constructor. + template ::value>::type> + scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {} + + // Move constructor. This is required in addition to the move conversion + // constructor below. + scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; } + + // Move conversion constructor. + template ::value>::type> + scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { + r.ptr_ = nullptr; + } + + ~scoped_refptr() { + static_assert(!base::subtle::IsRefCountPreferenceOverridden( + static_cast(nullptr), static_cast(nullptr)), + "It's unsafe to override the ref count preference." + " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE" + " from subclasses."); + if (ptr_) + Release(ptr_); + } + + T* get() const { return ptr_; } + + T& operator*() const { + DCHECK(ptr_); + return *ptr_; + } + + T* operator->() const { + DCHECK(ptr_); + return ptr_; + } + + scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); } + + // Unified assignment operator. + scoped_refptr& operator=(scoped_refptr r) noexcept { + swap(r); + return *this; + } + + void swap(scoped_refptr& r) noexcept { std::swap(ptr_, r.ptr_); } + + explicit operator bool() const { return ptr_ != nullptr; } + + template + bool operator==(const scoped_refptr& rhs) const { + return ptr_ == rhs.get(); + } + + template + bool operator!=(const scoped_refptr& rhs) const { + return !operator==(rhs); + } + + template + bool operator<(const scoped_refptr& rhs) const { + return ptr_ < rhs.get(); + } + + protected: + T* ptr_ = nullptr; + + private: + template + friend scoped_refptr base::AdoptRef(U*); + + scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {} + + // Friend required for move constructors that set r.ptr_ to null. + template + friend class scoped_refptr; + + // Non-inline helpers to allow: + // class Opaque; + // extern template class scoped_refptr; + // Otherwise the compiler will complain that Opaque is an incomplete type. + static void AddRef(T* ptr); + static void Release(T* ptr); +}; + +// static +template +void scoped_refptr::AddRef(T* ptr) { + ptr->AddRef(); +} + +// static +template +void scoped_refptr::Release(T* ptr) { + ptr->Release(); +} + +template +bool operator==(const scoped_refptr& lhs, const U* rhs) { + return lhs.get() == rhs; +} + +template +bool operator==(const T* lhs, const scoped_refptr& rhs) { + return lhs == rhs.get(); +} + +template +bool operator==(const scoped_refptr& lhs, std::nullptr_t null) { + return !static_cast(lhs); +} + +template +bool operator==(std::nullptr_t null, const scoped_refptr& rhs) { + return !static_cast(rhs); +} + +template +bool operator!=(const scoped_refptr& lhs, const U* rhs) { + return !operator==(lhs, rhs); +} + +template +bool operator!=(const T* lhs, const scoped_refptr& rhs) { + return !operator==(lhs, rhs); +} + +template +bool operator!=(const scoped_refptr& lhs, std::nullptr_t null) { + return !operator==(lhs, null); +} + +template +bool operator!=(std::nullptr_t null, const scoped_refptr& rhs) { + return !operator==(null, rhs); +} + +template +std::ostream& operator<<(std::ostream& out, const scoped_refptr& p) { + return out << p.get(); +} + +template +void swap(scoped_refptr& lhs, scoped_refptr& rhs) noexcept { + lhs.swap(rhs); +} + +#endif // BASE_MEMORY_SCOPED_REFPTR_H_ diff --git a/src/3rdparty/gn/base/memory/weak_ptr.cc b/src/3rdparty/gn/base/memory/weak_ptr.cc new file mode 100644 index 00000000000..4abeb7f84ef --- /dev/null +++ b/src/3rdparty/gn/base/memory/weak_ptr.cc @@ -0,0 +1,75 @@ +// 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() = default; + +WeakReference::WeakReference() = default; + +WeakReference::WeakReference(const scoped_refptr& flag) : flag_(flag) {} + +WeakReference::~WeakReference() = default; + +WeakReference::WeakReference(WeakReference&& other) = default; + +WeakReference::WeakReference(const WeakReference& other) = default; + +bool WeakReference::is_valid() const { + return flag_ && flag_->IsValid(); +} + +WeakReferenceOwner::WeakReferenceOwner() = default; + +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_); +} + +void WeakReferenceOwner::Invalidate() { + if (flag_) { + flag_->Invalidate(); + flag_ = nullptr; + } +} + +WeakPtrBase::WeakPtrBase() : ptr_(0) {} + +WeakPtrBase::~WeakPtrBase() = default; + +WeakPtrBase::WeakPtrBase(const WeakReference& ref, uintptr_t ptr) + : ref_(ref), ptr_(ptr) { + DCHECK(ptr_); +} + +WeakPtrFactoryBase::WeakPtrFactoryBase(uintptr_t ptr) : ptr_(ptr) { + DCHECK(ptr_); +} + +WeakPtrFactoryBase::~WeakPtrFactoryBase() { + ptr_ = 0; +} + +} // namespace internal +} // namespace base diff --git a/src/3rdparty/gn/base/memory/weak_ptr.h b/src/3rdparty/gn/base/memory/weak_ptr.h new file mode 100644 index 00000000000..3b2a0af6fb9 --- /dev/null +++ b/src/3rdparty/gn/base/memory/weak_ptr.h @@ -0,0 +1,378 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Weak pointers are pointers to an object that do not affect its lifetime, +// and which may be invalidated (i.e. reset to nullptr) by the object, or its +// owner, at any time, most commonly when the object is about to be deleted. + +// Weak pointers are useful when an object needs to be accessed safely by one +// or more objects other than its owner, and those callers can cope with the +// object vanishing and e.g. tasks posted to it being silently dropped. +// Reference-counting such an object would complicate the ownership graph and +// make it harder to reason about the object's lifetime. + +// EXAMPLE: +// +// class Controller { +// public: +// Controller() : weak_factory_(this) {} +// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); } +// void WorkComplete(const Result& result) { ... } +// private: +// // Member variables should appear before the WeakPtrFactory, to ensure +// // that any WeakPtrs to Controller are invalidated before its members +// // variable's destructors are executed, rendering them invalid. +// WeakPtrFactory weak_factory_; +// }; +// +// class Worker { +// public: +// static void StartNew(const WeakPtr& controller) { +// Worker* worker = new Worker(controller); +// // Kick off asynchronous processing... +// } +// private: +// Worker(const WeakPtr& controller) +// : controller_(controller) {} +// void DidCompleteAsynchronousProcessing(const Result& result) { +// if (controller_) +// controller_->WorkComplete(result); +// } +// WeakPtr controller_; +// }; +// +// With this implementation a caller may use SpawnWorker() to dispatch multiple +// Workers and subsequently delete the Controller, without waiting for all +// Workers to have completed. + +// ------------------------- IMPORTANT: Thread-safety ------------------------- + +// Weak pointers may be passed safely between threads, but must always be +// dereferenced and invalidated on the same SequencedTaskRunner otherwise +// checking the pointer would be racey. +// +// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory +// is dereferenced, the factory and its WeakPtrs become bound to the calling +// thread or current SequencedWorkerPool token, and cannot be dereferenced or +// invalidated on any other task runner. Bound WeakPtrs can still be handed +// off to other task runners, e.g. to use to post tasks back to object on the +// bound sequence. +// +// If all WeakPtr objects are destroyed or invalidated then the factory is +// unbound from the SequencedTaskRunner/Thread. The WeakPtrFactory may then be +// destroyed, or new WeakPtr objects may be used, from a different sequence. +// +// Thus, at least one WeakPtr object must exist and have been dereferenced on +// the correct thread to enforce that other WeakPtr objects will enforce they +// are used on the desired thread. + +#ifndef BASE_MEMORY_WEAK_PTR_H_ +#define BASE_MEMORY_WEAK_PTR_H_ + +#include +#include + +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" + +namespace base { + +template +class SupportsWeakPtr; +template +class WeakPtr; + +namespace internal { +// These classes are part of the WeakPtr implementation. +// DO NOT USE THESE CLASSES DIRECTLY YOURSELF. + +class WeakReference { + public: + // Although Flag is bound to a specific SequencedTaskRunner, it may be + // deleted from another via base::WeakPtr::~WeakPtr(). + class Flag : public RefCountedThreadSafe { + public: + Flag(); + + void Invalidate(); + bool IsValid() const; + + private: + friend class base::RefCountedThreadSafe; + + ~Flag(); + + bool is_valid_; + }; + + WeakReference(); + explicit WeakReference(const scoped_refptr& flag); + ~WeakReference(); + + WeakReference(WeakReference&& other); + WeakReference(const WeakReference& other); + WeakReference& operator=(WeakReference&& other) = default; + WeakReference& operator=(const WeakReference& other) = default; + + bool is_valid() const; + + private: + scoped_refptr flag_; +}; + +class WeakReferenceOwner { + public: + WeakReferenceOwner(); + ~WeakReferenceOwner(); + + WeakReference GetRef() const; + + bool HasRefs() const { return flag_ && !flag_->HasOneRef(); } + + void Invalidate(); + + private: + mutable scoped_refptr flag_; +}; + +// This class simplifies the implementation of WeakPtr's type conversion +// constructor by avoiding the need for a public accessor for ref_. A +// WeakPtr cannot access the private members of WeakPtr, so this +// base class gives us a way to access ref_ in a protected fashion. +class WeakPtrBase { + public: + WeakPtrBase(); + ~WeakPtrBase(); + + WeakPtrBase(const WeakPtrBase& other) = default; + WeakPtrBase(WeakPtrBase&& other) = default; + WeakPtrBase& operator=(const WeakPtrBase& other) = default; + WeakPtrBase& operator=(WeakPtrBase&& other) = default; + + void reset() { + ref_ = internal::WeakReference(); + ptr_ = 0; + } + + protected: + WeakPtrBase(const WeakReference& ref, uintptr_t ptr); + + WeakReference ref_; + + // This pointer is only valid when ref_.is_valid() is true. Otherwise, its + // value is undefined (as opposed to nullptr). + uintptr_t ptr_; +}; + +// 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 to WeakPtr. This + // conversion will only compile if there is exists a Base which inherits + // from SupportsWeakPtr. See base::AsWeakPtr() below for a helper + // function that makes calling this easier. + // + // Precondition: t != nullptr + template + static WeakPtr StaticAsWeakPtr(Derived* t) { + static_assert( + std::is_base_of::value, + "AsWeakPtr argument must inherit from SupportsWeakPtr"); + return AsWeakPtrImpl(t); + } + + private: + // This template function uses type inference to find a Base of Derived + // which is an instance of SupportsWeakPtr. We can then safely + // static_cast the Base* to a Derived*. + template + static WeakPtr AsWeakPtrImpl(SupportsWeakPtr* t) { + WeakPtr ptr = t->AsWeakPtr(); + return WeakPtr( + ptr.ref_, static_cast(reinterpret_cast(ptr.ptr_))); + } +}; + +} // namespace internal + +template +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; +// if (foo) +// foo->method(); +// +template +class WeakPtr : public internal::WeakPtrBase { + public: + WeakPtr() = default; + + WeakPtr(std::nullptr_t) {} + + // Allow conversion from U to T provided U "is a" T. Note that this + // is separate from the (implicit) copy and move constructors. + template + WeakPtr(const WeakPtr& other) : WeakPtrBase(other) { + // Need to cast from U* to T* to do pointer adjustment in case of multiple + // inheritance. This also enforces the "U is a T" rule. + T* t = reinterpret_cast(other.ptr_); + ptr_ = reinterpret_cast(t); + } + template + WeakPtr(WeakPtr&& other) : WeakPtrBase(std::move(other)) { + // Need to cast from U* to T* to do pointer adjustment in case of multiple + // inheritance. This also enforces the "U is a T" rule. + T* t = reinterpret_cast(other.ptr_); + ptr_ = reinterpret_cast(t); + } + + T* get() const { + return ref_.is_valid() ? reinterpret_cast(ptr_) : nullptr; + } + + T& operator*() const { + DCHECK(get() != nullptr); + return *get(); + } + T* operator->() const { + DCHECK(get() != nullptr); + return get(); + } + + // Allow conditionals to test validity, e.g. if (weak_ptr) {...}; + explicit operator bool() const { return get() != nullptr; } + + private: + friend class internal::SupportsWeakPtrBase; + template + friend class WeakPtr; + friend class SupportsWeakPtr; + friend class WeakPtrFactory; + + WeakPtr(const internal::WeakReference& ref, T* ptr) + : WeakPtrBase(ref, reinterpret_cast(ptr)) {} +}; + +// Allow callers to compare WeakPtrs against nullptr to test validity. +template +bool operator!=(const WeakPtr& weak_ptr, std::nullptr_t) { + return !(weak_ptr == nullptr); +} +template +bool operator!=(std::nullptr_t, const WeakPtr& weak_ptr) { + return weak_ptr != nullptr; +} +template +bool operator==(const WeakPtr& weak_ptr, std::nullptr_t) { + return weak_ptr.get() == nullptr; +} +template +bool operator==(std::nullptr_t, const WeakPtr& weak_ptr) { + return weak_ptr == nullptr; +} + +namespace internal { +class WeakPtrFactoryBase { + protected: + WeakPtrFactoryBase(uintptr_t ptr); + ~WeakPtrFactoryBase(); + internal::WeakReferenceOwner weak_reference_owner_; + uintptr_t ptr_; +}; +} // namespace internal + +// 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 that is used to pass around a weak reference to a bool. +template +class WeakPtrFactory : public internal::WeakPtrFactoryBase { + public: + explicit WeakPtrFactory(T* ptr) + : WeakPtrFactoryBase(reinterpret_cast(ptr)) {} + + ~WeakPtrFactory() = default; + + WeakPtr GetWeakPtr() { + return WeakPtr(weak_reference_owner_.GetRef(), + reinterpret_cast(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: + 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 SupportsWeakPtr : public internal::SupportsWeakPtrBase { + public: + SupportsWeakPtr() = default; + + WeakPtr AsWeakPtr() { + return WeakPtr(weak_reference_owner_.GetRef(), static_cast(this)); + } + + protected: + ~SupportsWeakPtr() = default; + + private: + internal::WeakReferenceOwner weak_reference_owner_; + DISALLOW_COPY_AND_ASSIGN(SupportsWeakPtr); +}; + +// Helper function that uses type deduction to safely return a WeakPtr +// when Derived doesn't directly extend SupportsWeakPtr, instead it +// extends a Base that extends SupportsWeakPtr. +// +// EXAMPLE: +// class Base : public base::SupportsWeakPtr {}; +// class Derived : public Base {}; +// +// Derived derived; +// base::WeakPtr ptr = base::AsWeakPtr(&derived); +// +// Note that the following doesn't work (invalid type conversion) since +// Derived::AsWeakPtr() is WeakPtr SupportsWeakPtr::AsWeakPtr(), +// and there's no way to safely cast WeakPtr to WeakPtr at +// the caller. +// +// base::WeakPtr ptr = derived.AsWeakPtr(); // Fails. + +template +WeakPtr AsWeakPtr(Derived* t) { + return internal::SupportsWeakPtrBase::StaticAsWeakPtr(t); +} + +} // namespace base + +#endif // BASE_MEMORY_WEAK_PTR_H_ diff --git a/src/3rdparty/gn/base/numerics/checked_math.h b/src/3rdparty/gn/base/numerics/checked_math.h new file mode 100644 index 00000000000..433860c58ba --- /dev/null +++ b/src/3rdparty/gn/base/numerics/checked_math.h @@ -0,0 +1,393 @@ +// Copyright 2017 The Chromium 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_CHECKED_MATH_H_ +#define BASE_NUMERICS_CHECKED_MATH_H_ + +#include + +#include +#include + +#include "base/numerics/checked_math_impl.h" + +namespace base { +namespace internal { + +template +class CheckedNumeric { + static_assert(std::is_arithmetic::value, + "CheckedNumeric: T must be a numeric type."); + + public: + using type = T; + + constexpr CheckedNumeric() = default; + + // Copy constructor. + template + constexpr CheckedNumeric(const CheckedNumeric& rhs) + : state_(rhs.state_.value(), rhs.IsValid()) {} + + template + friend class CheckedNumeric; + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to CheckedNumerics to make them easier to use. + template + constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit) + : state_(value) { + static_assert(std::is_arithmetic::value, "Argument must be numeric."); + } + + // This is not an explicit constructor because we want a seamless conversion + // from StrictNumeric types. + template + constexpr CheckedNumeric( + StrictNumeric value) // NOLINT(runtime/explicit) + : state_(static_cast(value)) {} + + // IsValid() - The public API to test if a CheckedNumeric is currently valid. + // A range checked destination type can be supplied using the Dst template + // parameter. + template + constexpr bool IsValid() const { + return state_.is_valid() && + IsValueInRangeForNumericType(state_.value()); + } + + // AssignIfValid(Dst) - Assigns the underlying value if it is currently valid + // and is within the range supported by the destination type. Returns true if + // successful and false otherwise. + template +#if defined(__clang__) || defined(__GNUC__) + __attribute__((warn_unused_result)) +#elif defined(_MSC_VER) + _Check_return_ +#endif + constexpr bool + AssignIfValid(Dst* result) const { + return BASE_NUMERICS_LIKELY(IsValid()) + ? ((*result = static_cast(state_.value())), true) + : false; + } + + // ValueOrDie() - The primary accessor for the underlying value. If the + // current state is not valid it will CHECK and crash. + // A range checked destination type can be supplied using the Dst template + // parameter, which will trigger a CHECK if the value is not in bounds for + // the destination. + // The CHECK behavior can be overridden by supplying a handler as a + // template parameter, for test code, etc. However, the handler cannot access + // the underlying value, and it is not available through other means. + template + constexpr StrictNumeric ValueOrDie() const { + return BASE_NUMERICS_LIKELY(IsValid()) + ? static_cast(state_.value()) + : CheckHandler::template HandleFailure(); + } + + // 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. + // A range checked destination type can be supplied using the Dst template + // parameter. WARNING: This function may fail to compile or CHECK at runtime + // if the supplied default_value is not within range of the destination type. + template + constexpr StrictNumeric ValueOrDefault(const Src default_value) const { + return BASE_NUMERICS_LIKELY(IsValid()) + ? static_cast(state_.value()) + : checked_cast(default_value); + } + + // Returns a checked numeric of the specified type, cast from the current + // CheckedNumeric. If the current state is invalid or the destination cannot + // represent the result then the returned CheckedNumeric will be invalid. + template + constexpr CheckedNumeric::type> Cast() const { + return *this; + } + + // This friend method is available solely for providing more detailed logging + // in the the tests. Do not implement it in production code, because the + // underlying values may change at any time. + template + friend U GetNumericValueForTest(const CheckedNumeric& src); + + // Prototypes for the supported arithmetic operator overloads. + template + constexpr CheckedNumeric& operator+=(const Src rhs); + template + constexpr CheckedNumeric& operator-=(const Src rhs); + template + constexpr CheckedNumeric& operator*=(const Src rhs); + template + constexpr CheckedNumeric& operator/=(const Src rhs); + template + constexpr CheckedNumeric& operator%=(const Src rhs); + template + constexpr CheckedNumeric& operator<<=(const Src rhs); + template + constexpr CheckedNumeric& operator>>=(const Src rhs); + template + constexpr CheckedNumeric& operator&=(const Src rhs); + template + constexpr CheckedNumeric& operator|=(const Src rhs); + template + constexpr CheckedNumeric& operator^=(const Src rhs); + + constexpr CheckedNumeric operator-() const { + // The negation of two's complement int min is int min, so we simply + // check for that in the constexpr case. + // We use an optimized code path for a known run-time variable. + return MustTreatAsConstexpr(state_.value()) || !std::is_signed::value || + std::is_floating_point::value + ? CheckedNumeric( + NegateWrapper(state_.value()), + IsValid() && (!std::is_signed::value || + std::is_floating_point::value || + NegateWrapper(state_.value()) != + std::numeric_limits::lowest())) + : FastRuntimeNegate(); + } + + constexpr CheckedNumeric operator~() const { + return CheckedNumeric( + InvertWrapper(state_.value()), IsValid()); + } + + constexpr CheckedNumeric Abs() const { + return !IsValueNegative(state_.value()) ? *this : -*this; + } + + template + constexpr CheckedNumeric::type> Max( + const U rhs) const { + using R = typename UnderlyingType::type; + using result_type = typename MathWrapper::type; + // TODO(jschuh): This can be converted to the MathOp version and remain + // constexpr once we have C++14 support. + return CheckedNumeric( + static_cast( + IsGreater::Test(state_.value(), Wrapper::value(rhs)) + ? state_.value() + : Wrapper::value(rhs)), + state_.is_valid() && Wrapper::is_valid(rhs)); + } + + template + constexpr CheckedNumeric::type> Min( + const U rhs) const { + using R = typename UnderlyingType::type; + using result_type = typename MathWrapper::type; + // TODO(jschuh): This can be converted to the MathOp version and remain + // constexpr once we have C++14 support. + return CheckedNumeric( + static_cast( + IsLess::Test(state_.value(), Wrapper::value(rhs)) + ? state_.value() + : Wrapper::value(rhs)), + state_.is_valid() && Wrapper::is_valid(rhs)); + } + + // This function is available only for integral types. It returns an unsigned + // integer of the same width as the source type, containing the absolute value + // of the source, and properly handling signed min. + constexpr CheckedNumeric::type> + UnsignedAbs() const { + return CheckedNumeric::type>( + SafeUnsignedAbs(state_.value()), state_.is_valid()); + } + + constexpr CheckedNumeric& operator++() { + *this += 1; + return *this; + } + + constexpr CheckedNumeric operator++(int) { + CheckedNumeric value = *this; + *this += 1; + return value; + } + + constexpr CheckedNumeric& operator--() { + *this -= 1; + return *this; + } + + constexpr CheckedNumeric operator--(int) { + CheckedNumeric value = *this; + *this -= 1; + return value; + } + + // These perform the actual math operations on the CheckedNumerics. + // Binary arithmetic operations. + template