Update the Chromium Codelab
- New top-level //codelabs directory - Update exercises 0-4 to compile - Add mojo exercise Previous codelab is here: https://www.chromium.org/developers/cpp-in-chromium-101-codelab Bug: N/A Change-Id: I2218160fa9efc8017dce809db8546604ade7e5d8 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2414488 Reviewed-by: Victor Costan <pwnall@chromium.org> Reviewed-by: Dirk Pranke <dpranke@google.com> Reviewed-by: Scott Violet <sky@chromium.org> Reviewed-by: Marijn Kruisselbrink <mek@chromium.org> Reviewed-by: danakj <danakj@chromium.org> Reviewed-by: enne <enne@chromium.org> Commit-Queue: Austin Sullivan <asully@chromium.org> Cr-Commit-Position: refs/heads/master@{#814678}
This commit is contained in:

committed by
Commit Bot

parent
4b418527ec
commit
33da70ab00
1
BUILD.gn
1
BUILD.gn
@ -73,6 +73,7 @@ group("gn_all") {
|
||||
"//base/util:base_util_unittests",
|
||||
"//chrome/installer",
|
||||
"//chrome/updater",
|
||||
"//codelabs",
|
||||
"//components:components_unittests",
|
||||
"//components/gwp_asan:gwp_asan_unittests",
|
||||
"//net:net_unittests",
|
||||
|
@ -68,6 +68,8 @@ _TEST_CODE_EXCLUDED_PATHS = (
|
||||
r'ios[\\/].*_app_interface\.mm$',
|
||||
# Views Examples code
|
||||
r'ui[\\/]views[\\/]examples[\\/].*',
|
||||
# Chromium Codelab
|
||||
r'codelabs[\\/]*'
|
||||
)
|
||||
|
||||
_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
|
||||
|
54
codelabs/BUILD.gn
Normal file
54
codelabs/BUILD.gn
Normal file
@ -0,0 +1,54 @@
|
||||
# Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
group("codelabs") {
|
||||
testonly = true
|
||||
deps = [
|
||||
":codelab_factor",
|
||||
":codelab_fibonacci",
|
||||
":codelab_hello_world",
|
||||
":codelab_mojo",
|
||||
":codelab_sleep",
|
||||
]
|
||||
}
|
||||
|
||||
executable("codelab_hello_world") {
|
||||
sources = [ "cpp101/hello_world.cc" ]
|
||||
deps = [ "//base" ]
|
||||
}
|
||||
|
||||
executable("codelab_fibonacci") {
|
||||
sources = [ "cpp101/fibonacci.cc" ]
|
||||
deps = [ "//base" ]
|
||||
}
|
||||
|
||||
executable("codelab_sleep") {
|
||||
testonly = true
|
||||
sources = [ "cpp101/sleep.cc" ]
|
||||
deps = [
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
]
|
||||
}
|
||||
|
||||
executable("codelab_factor") {
|
||||
testonly = true
|
||||
sources = [ "cpp101/factor.cc" ]
|
||||
deps = [
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
]
|
||||
}
|
||||
|
||||
executable("codelab_mojo") {
|
||||
testonly = true
|
||||
sources = [ "cpp101/mojo.cc" ]
|
||||
deps = [
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
"//codelabs/cpp101/services/math/",
|
||||
"//mojo/core/embedder",
|
||||
"//mojo/public/cpp/base",
|
||||
]
|
||||
}
|
4
codelabs/DEPS
Normal file
4
codelabs/DEPS
Normal file
@ -0,0 +1,4 @@
|
||||
include_rules = [
|
||||
"+mojo/core/embedder",
|
||||
"+mojo/public/cpp/bindings",
|
||||
]
|
1
codelabs/OWNERS
Normal file
1
codelabs/OWNERS
Normal file
@ -0,0 +1 @@
|
||||
*
|
13
codelabs/README.md
Normal file
13
codelabs/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Chromium Codelab
|
||||
|
||||
See the `cpp101/` directory for the Chromium C++ codelab,
|
||||
including example solutions.
|
||||
|
||||
## Motivation
|
||||
|
||||
The goal of this codelab is to introduce new Chromium developers to both the
|
||||
important design patterns and the style of code they can expect to become
|
||||
familiar with.
|
||||
|
||||
The code in this directory is for documentation purposes only. It is compiled
|
||||
via the top level BUILD.gn's `gn_all` target to make sure it is kept up to date.
|
282
codelabs/cpp101/codelab.md
Normal file
282
codelabs/cpp101/codelab.md
Normal file
@ -0,0 +1,282 @@
|
||||
# C++ in Chromium 101 - Codelab
|
||||
|
||||
This tutorial will guide you through the creation of various example C++
|
||||
applications, highlighting important Chromium C++ concepts.
|
||||
This tutorial assumes robust knowledge of C++ (the language) but does not
|
||||
assume you know how to write an application specific to Chromium's style and
|
||||
architecture. This tutorial does assume that you know how to check files out
|
||||
of Chromium's repository.
|
||||
|
||||
As always, consider the following resources as of primary importance:
|
||||
|
||||
- [Coding Style](https://chromium.googlesource.com/chromium/src/+/master/styleguide/styleguide.md)
|
||||
- [Callback<> and Bind()](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md)
|
||||
- [Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md)
|
||||
- [Intro to Mojo & Services](https://chromium.googlesource.com/chromium/src.git/+/master/docs/mojo_and_services.md)
|
||||
- [Important Abstractions and Data Structures](https://sites.google.com/a/chromium.org/dev/developers/coding-style/important-abstractions-and-data-structures) (badly needs updating)
|
||||
|
||||
This tutorial does not assume you have read any of the above,
|
||||
though you should feel free to peruse them when necessary.
|
||||
This tutorial will cover information across all of those guides.
|
||||
|
||||
Exercise solutions are available in the `codelabs/cpp101/` directory of the
|
||||
Chromium source code. Build all of the example solutions with
|
||||
`autoninja -C out/Default codelabs`. You are encouraged to create a new
|
||||
`base/cpp101/` directory locally if you want to try implementing these
|
||||
exercises yourself.
|
||||
|
||||
### Exercise 0: "Hello World!"
|
||||
|
||||
This exercise demonstrates the use of the [ninja](https://ninja-build.org/)
|
||||
build system to build a simple C++ binary and demonstrates how typical C++
|
||||
builds are organized within Chromium.
|
||||
|
||||
Create a new target in `base/BUILD.gn` for a new executable
|
||||
named `codelab_hello_world`. Then write the classic "Hello, world!" program in
|
||||
C++. You should be able to build it with
|
||||
`autoninja -C out/Default codelab_hello_world` and execute it directly by
|
||||
finding the binary within `out/Default`.
|
||||
|
||||
Sample execution:
|
||||
```shell
|
||||
$ cd /path/to/chromium/src
|
||||
$ gclient runhooks
|
||||
$ autoninja -C out/Default codelab_hello_world
|
||||
$ out/Default/codelab_hello_world
|
||||
Hello, world!
|
||||
[0923/185218.645640:INFO:hello_world.cc(27)] Hello, world!
|
||||
```
|
||||
|
||||
### More information
|
||||
|
||||
[Git Tips](https://chromium.googlesource.com/chromium/src.git/+/master/docs/git_tips.md)
|
||||
and [Git Cookbook](https://chromium.googlesource.com/chromium/src.git/+/master/docs/git_cookbook.md)
|
||||
|
||||
[Life of a Chromium Developer](https://docs.google.com/a/google.com/presentation/d/1abnqM9j6zFodPHA38JG1061rG2iGj_GABxEDgZsdbJg/)
|
||||
|
||||
## Part 1: Using command-line arguments
|
||||
|
||||
We will augment our `codelab_hello_world` binary to parse command-line flags and
|
||||
use those values to print messages to the user.
|
||||
|
||||
Command-line arguments within Chromium are processed by the
|
||||
`CommandLine::Init()` function, which takes command line flags from the
|
||||
[argc and argv](https://crasseux.com/books/ctutorial/argc-and-argv.html)
|
||||
(argument count & vector) variables of the main() method. A typical invocation
|
||||
of `CommandLine::Init()` looks like the following:
|
||||
```cpp
|
||||
int main(int argc, char** argv) {
|
||||
CommandLine::Init(argc, argv);
|
||||
// Main program execution ...
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
Flags are not explicitly defined in Chromium. Instead, we
|
||||
use `GetSwitchValueASCII()` and friends to retrieve values passed in.
|
||||
|
||||
### Important include files
|
||||
|
||||
```cpp
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
```
|
||||
|
||||
### Exercise 1: Using command-line arguments
|
||||
|
||||
Change `codelab_hello_world` to take a `--greeting` and a `--name` switch.
|
||||
The greeting, if not specified, should default to "Hello",
|
||||
and the name, if not specified, should default to "World".
|
||||
|
||||
## Part 2: Callbacks and Bind
|
||||
|
||||
C++, unlike other languages such as Python, Javascript, or Lisp, has only
|
||||
rudimentary support for [callbacks](https://en.wikipedia.org/wiki/Callbacks)
|
||||
and no support for
|
||||
[partial application](https://en.wikipedia.org/wiki/Partial_application).
|
||||
However, Chromium has the `base::OnceCallback<Sig>` and
|
||||
`base::RepeatingCallback<Sig>`class, whose instances can be freely passed
|
||||
around, returned, and generally be treated as first-class values.
|
||||
base::OnceCallback<Sig> is the move-only, single-call variant,
|
||||
and base::RepeatingCallback<Sig> is the copyable, multiple-call variant.
|
||||
|
||||
The `Sig` template parameter is a function signature type:
|
||||
```cpp
|
||||
// The type of a callback that:
|
||||
// - Can run only once.
|
||||
// - Is move-only and non-copyable.
|
||||
// - Takes no arguments and does not return anything.
|
||||
// base::OnceClosure is an alias of this type.
|
||||
base::OnceCallback<void()>
|
||||
|
||||
// The type of a callback that:
|
||||
// - Can run more than once.
|
||||
// - Is copyable.
|
||||
// - Takes no arguments and does not return anything.
|
||||
// base::RepeatingClosure is an alias of this type.
|
||||
base::RepeatingCallback<void()>
|
||||
|
||||
// The types of a callback that takes two arguments (a string and a double)
|
||||
// and returns an int.
|
||||
base::OnceCallback<int(std::string, double)>
|
||||
base::RepeatingCallback<int(std::string, double)>
|
||||
```
|
||||
Callbacks are executed by invoking the `Run()` member function.
|
||||
base::OnceCallback<Sig> needs to be rvalue to run.
|
||||
```cpp
|
||||
void MyFunction1(base::OnceCallback<int(std::string, double)> my_callback) {
|
||||
// OnceCallback
|
||||
int result1 = std::move(my_callback).Run("my string 1", 1.0);
|
||||
|
||||
// After running a OnceCallback, it's consumed and nulled out.
|
||||
DCHECK(!my_callback);
|
||||
...
|
||||
}
|
||||
|
||||
void MyFunction2(base::RepeatingCallback<int(std::string, double)> my_callback) {
|
||||
int result1 = my_callback.Run("my string 1", 1.0);
|
||||
// Run() can be called as many times as you wish for RepeatingCallback.
|
||||
int result2 = my_callback.Run("my string 2", 2);
|
||||
...
|
||||
```
|
||||
Callbacks are constructed using the `base::BindOnce()` or `base::BindRepeating()` function,
|
||||
which handles partial application:
|
||||
```cpp
|
||||
// Declare a function.
|
||||
void MyFunction(int32 a, double b);
|
||||
|
||||
base::OnceCallback<void(double)> my_callback1 = base::BindOnce(&MyFunction, 10);
|
||||
base::RepeatingCallback<void(double)> my_callback2 = base::BindRepeating(&MyFunction, 10);
|
||||
|
||||
// Equivalent to:
|
||||
//
|
||||
// MyFunction(10, 3.5);
|
||||
//
|
||||
std::move(my_callback1).Run(3.5);
|
||||
my_callback2.Run(3.5);
|
||||
```
|
||||
`base::BindOnce()` and `base::BindRepeating()` can do a lot more, including
|
||||
binding class member functions and binding additional arguments to an
|
||||
existing `base::OnceCallback` or `base::RepeatingCallback`. See
|
||||
[docs/callback.md](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md)
|
||||
for details.
|
||||
|
||||
### Important Include Files
|
||||
|
||||
```cpp
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
```
|
||||
|
||||
### More Information
|
||||
|
||||
[Callback<> and Bind()](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md)
|
||||
|
||||
### Exercise 2: Fibonacci closures
|
||||
|
||||
Implement a function that returns a callback that takes no arguments and returns
|
||||
successive Fibonacci numbers. That is, a function that can be used like this:
|
||||
```cpp
|
||||
base::RepeatingCallback<int()> fibonacci_closure = MakeFibonacciClosure();
|
||||
LOG(INFO) << fibonacci_closure.Run(); // Prints "1"
|
||||
LOG(INFO) << fibonacci_closure.Run(); // Prints "1"
|
||||
LOG(INFO) << fibonacci_closure.Run(); // Prints "2"
|
||||
...
|
||||
```
|
||||
Each returned Fibonacci callback should be independent;
|
||||
running one callback shouldn't affect the result of running another callback.
|
||||
Write a `fibonacci` executable that takes an integer argument `n`
|
||||
and uses your function to print out the first `n` Fibonacci numbers.
|
||||
|
||||
(This exercise was inspired by
|
||||
[this Go exercise: Function closures](https://tour.golang.org/moretypes/25).)
|
||||
|
||||
## Part 3: Threads and task runners
|
||||
|
||||
Chromium has a number of abstractions for sequencing and threading.
|
||||
[Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md)
|
||||
is a must-read and go-to reference for anything related to tasks, thread pools,
|
||||
task runners, and more.
|
||||
|
||||
Sequenced execution (on virtual threads) is strongly preferred to
|
||||
single-threaded execution (on physical threads). Chromium's abstraction for
|
||||
asynchronously running posted tasks is `base::TaskRunner`. Task runners allow
|
||||
you to write code that posts tasks without depending on what exactly will run
|
||||
those tasks.
|
||||
|
||||
`base::SequencedTaskRunner` (which extends `base::TaskRunner`) is a commonly
|
||||
used abstraction which handles running tasks (which are instances
|
||||
of `base::Closure`) in sequential order. These tasks are not guaranteed to run
|
||||
on the same thread. The preferred way of posting to the current (virtual) thread
|
||||
is `base::SequencedTaskRunnerHandle::Get()`.
|
||||
|
||||
A task that can run on any thread and doesn’t have ordering or mutual exclusion
|
||||
requirements with other tasks should be posted using one of the
|
||||
`base::ThreadPool::PostTask()` functions.
|
||||
|
||||
There are a number of ways to post tasks to a thread pool or task runner.
|
||||
|
||||
- `PostTask()`
|
||||
- `PostDelayedTask()` if you want to add a delay.
|
||||
- `PostTaskAndReply()` lets you post a task which will post a task back to your
|
||||
current thread when its done.
|
||||
- `PostTaskAndReplyWithResult()` to automatically pass the return value of the
|
||||
first call as argument to the second call.
|
||||
|
||||
Normally you wouldn't have to worry about setting up a threading environment and
|
||||
keeping it running, since that is automatically done by Chromium's thread
|
||||
classes. However, since the main thread doesn't automatically start off with
|
||||
`TaskEnvironment`, there's a bit of extra setup involved. This setup code is
|
||||
available in the exercise solution files.
|
||||
|
||||
### Important header files
|
||||
```cpp
|
||||
#include "base/threading/sequenced_task_runner_handle.h"
|
||||
#include "base/time/time.h"
|
||||
```
|
||||
|
||||
### Exercise 3a: Sleep
|
||||
|
||||
Implement the Unix command-line utility `sleep` using only
|
||||
a `base::SequencedTaskRunnerHandle` (i.e., without using the `sleep` function
|
||||
or `base::PlatformThread::Sleep`).
|
||||
|
||||
### Exercise 3b: Integer factorization
|
||||
|
||||
Take the given (slow) function to find a non-trivial factor of a given integer:
|
||||
```cpp
|
||||
bool FindNonTrivialFactor(int n, int* factor) {
|
||||
// Really naive algorithm.
|
||||
for (int i = n-1; i >= 2; --i) {
|
||||
if (n % i == 0) {
|
||||
*factor = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
```
|
||||
Write a command-line utility `factor` that takes a number, posts a task to the
|
||||
background using `FindNonTrivialFactor`, and prints a status update every second
|
||||
as long as the factoring task is executing.
|
||||
|
||||
### More information
|
||||
|
||||
[Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md)
|
||||
|
||||
## Part 4: Mojo
|
||||
|
||||
Mojo is Chromium's abstraction of IPC. Mojo allows for developers to easily
|
||||
connect interface clients and implementations across arbitrary intra- and
|
||||
inter-process boundaries. See the
|
||||
[Intro to Mojo and Services](https://chromium.googlesource.com/chromium/src.git/+/master/docs/mojo_and_services.md)
|
||||
guide to get started.
|
||||
|
||||
### Exercise 4: Building a simple out-of-process service
|
||||
|
||||
See the [building a simple out-of-process service](https://chromium.googlesource.com/chromium/src.git/+/master/docs/mojo_and_services.md#example_building-a-simple-out_of_process-service)
|
||||
tutorial on using Mojo to define, hook up, and launch an out-of-process service.
|
||||
|
||||
### More Information
|
||||
|
||||
[Mojo C++ Bindings API Docs](https://chromium.googlesource.com/chromium/src.git/+/master/mojo/public/cpp/bindings/README.md)
|
||||
[Mojo Docs](https://chromium.googlesource.com/chromium/src.git/+/master/mojo/README.md)
|
94
codelabs/cpp101/factor.cc
Normal file
94
codelabs/cpp101/factor.cc
Normal file
@ -0,0 +1,94 @@
|
||||
// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/optional.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/test/test_timeouts.h"
|
||||
#include "base/threading/sequenced_task_runner_handle.h"
|
||||
#include "base/time/time.h"
|
||||
|
||||
namespace {
|
||||
|
||||
base::Optional<int> FindNonTrivialFactor(int n) {
|
||||
// Really naive algorithm.
|
||||
for (int i = 2; i < n; ++i) {
|
||||
if (n % i == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return base::nullopt;
|
||||
}
|
||||
|
||||
void FindNonTrivialFactorHelper(int n, base::Optional<int>* result) {
|
||||
*result = FindNonTrivialFactor(n);
|
||||
}
|
||||
|
||||
void PrintStatusUpdate(base::TimeTicks start_time) {
|
||||
double num_seconds = (base::TimeTicks::Now() - start_time).InSecondsF();
|
||||
LOG(INFO) << "Waited for " << num_seconds << " seconds...\n";
|
||||
}
|
||||
|
||||
void PrintStatusUpdateRepeatedly(base::TimeTicks start_time,
|
||||
base::TimeDelta print_interval) {
|
||||
PrintStatusUpdate(start_time);
|
||||
base::ThreadPool::PostDelayedTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&PrintStatusUpdateRepeatedly, start_time, print_interval),
|
||||
print_interval);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
base::AtExitManager exit_manager;
|
||||
base::CommandLine::Init(argc, argv);
|
||||
TestTimeouts::Initialize();
|
||||
base::test::TaskEnvironment task_environment{
|
||||
base::test::TaskEnvironment::TimeSource::SYSTEM_TIME};
|
||||
|
||||
if (argc <= 1) {
|
||||
LOG(INFO) << argv[0] << ": missing operand\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
if (!base::StringToInt(argv[1], &n) || n < 2) {
|
||||
LOG(INFO) << argv[0] << ": invalid n '" << argv[1] << "'";
|
||||
return -1;
|
||||
}
|
||||
|
||||
base::RunLoop run_loop;
|
||||
|
||||
base::Optional<int> result;
|
||||
// Notice that we're posting the long-running factoring operation to
|
||||
// |base::ThreadPool| to avoid blocking the main thread
|
||||
//
|
||||
// |run_loop.QuitClosure()| will be called once the factoring task completes.
|
||||
base::ThreadPool::PostTaskAndReply(
|
||||
FROM_HERE, base::BindOnce(&FindNonTrivialFactorHelper, n, &result),
|
||||
run_loop.QuitClosure());
|
||||
|
||||
base::ThreadPool::PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&PrintStatusUpdateRepeatedly, base::TimeTicks::Now(),
|
||||
base::TimeDelta::FromSeconds(1)));
|
||||
|
||||
run_loop.Run();
|
||||
|
||||
if (result.has_value()) {
|
||||
LOG(INFO) << "found non-trivial factor " << result.value() << " for " << n;
|
||||
DCHECK_EQ(n % result.value(), 0);
|
||||
} else {
|
||||
LOG(INFO) << n << " is prime";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
60
codelabs/cpp101/fibonacci.cc
Normal file
60
codelabs/cpp101/fibonacci.cc
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct FibonacciState {
|
||||
FibonacciState() = default;
|
||||
|
||||
int i{0}, j{1};
|
||||
};
|
||||
|
||||
int ComputeNextFibonacciNumber(FibonacciState* state) {
|
||||
int next = state->i + state->j;
|
||||
state->i = state->j;
|
||||
state->j = next;
|
||||
return state->i;
|
||||
}
|
||||
|
||||
base::RepeatingCallback<int()> MakeFibonacciClosure() {
|
||||
auto state = std::make_unique<FibonacciState>();
|
||||
return base::BindRepeating(&ComputeNextFibonacciNumber,
|
||||
base::Owned(std::move(state)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc <= 1) {
|
||||
LOG(INFO) << argv[0] << ": missing operand";
|
||||
return -1;
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
if (!base::StringToInt(argv[1], &n) || n < 0) {
|
||||
LOG(INFO) << argv[0] << ": invalid n '" << argv[1] << "'";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// |fibonacci_closure1| and |fibonacci_closure2| are independent. Though they
|
||||
// are bound to the same method, they each have their own |FibonacciState|.
|
||||
// Running one closure does not affect the other.
|
||||
base::RepeatingCallback<int()> fibonacci_closure1 = MakeFibonacciClosure();
|
||||
base::RepeatingCallback<int()> fibonacci_closure2 = MakeFibonacciClosure();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
// Run both closures and confirm the values match.
|
||||
int fibonacci_i = fibonacci_closure1.Run();
|
||||
int fibonacci_i_backup = fibonacci_closure2.Run();
|
||||
DCHECK_EQ(fibonacci_i, fibonacci_i_backup);
|
||||
|
||||
LOG(INFO) << "F_" << i << " = " << fibonacci_i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
28
codelabs/cpp101/hello_world.cc
Normal file
28
codelabs/cpp101/hello_world.cc
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2020 The Chromium 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 <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
CHECK(base::CommandLine::Init(argc, argv));
|
||||
|
||||
const base::CommandLine& command_line =
|
||||
*base::CommandLine::ForCurrentProcess();
|
||||
|
||||
std::string greeting = command_line.GetSwitchValueASCII("greeting");
|
||||
if (greeting.empty())
|
||||
greeting = "Hello";
|
||||
|
||||
std::string name = command_line.GetSwitchValueASCII("name");
|
||||
if (name.empty())
|
||||
name = "world";
|
||||
|
||||
CHECK_GT(printf("%s, %s!\n", greeting.c_str(), name.c_str()), 0);
|
||||
LOG(INFO) << greeting << ", " << name << "!";
|
||||
}
|
62
codelabs/cpp101/mojo.cc
Normal file
62
codelabs/cpp101/mojo.cc
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/location.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/test/test_timeouts.h"
|
||||
#include "codelabs/cpp101/services/math/math_service.h"
|
||||
#include "mojo/core/embedder/embedder.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
base::AtExitManager exit_manager;
|
||||
base::CommandLine::Init(argc, argv);
|
||||
TestTimeouts::Initialize();
|
||||
base::test::TaskEnvironment task_environment{
|
||||
base::test::TaskEnvironment::TimeSource::SYSTEM_TIME};
|
||||
mojo::core::Init();
|
||||
|
||||
if (argc <= 2) {
|
||||
LOG(INFO) << argv[0] << ": missing operand";
|
||||
return -1;
|
||||
}
|
||||
|
||||
int divisor = 0;
|
||||
if (!base::StringToInt(argv[1], &divisor)) {
|
||||
LOG(INFO) << argv[0] << ": invalid divisor '" << argv[1] << "'";
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dividend = 0;
|
||||
if (!base::StringToInt(argv[2], ÷nd) || dividend == 0) {
|
||||
LOG(INFO) << argv[0] << ": invalid divisor '" << argv[2] << "'";
|
||||
return -1;
|
||||
}
|
||||
|
||||
base::RunLoop run_loop;
|
||||
|
||||
mojo::Remote<math::mojom::MathService> math_service;
|
||||
math::MathService math_service_impl(
|
||||
math_service.BindNewPipeAndPassReceiver());
|
||||
|
||||
math_service->Divide(divisor, dividend,
|
||||
base::BindOnce(
|
||||
[](base::OnceClosure quit, int32_t quotient) {
|
||||
LOG(INFO) << "Quotient: " << quotient;
|
||||
std::move(quit).Run();
|
||||
},
|
||||
run_loop.QuitClosure()));
|
||||
|
||||
run_loop.Run();
|
||||
|
||||
return 0;
|
||||
}
|
15
codelabs/cpp101/services/math/BUILD.gn
Normal file
15
codelabs/cpp101/services/math/BUILD.gn
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
source_set("math") {
|
||||
sources = [
|
||||
"math_service.cc",
|
||||
"math_service.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"public/mojom",
|
||||
"//base",
|
||||
]
|
||||
}
|
21
codelabs/cpp101/services/math/math_service.cc
Normal file
21
codelabs/cpp101/services/math/math_service.cc
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2020 The Chromium 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 "math_service.h"
|
||||
|
||||
namespace math {
|
||||
|
||||
MathService::MathService(mojo::PendingReceiver<mojom::MathService> receiver)
|
||||
: receiver_(this, std::move(receiver)) {}
|
||||
|
||||
MathService::~MathService() = default;
|
||||
|
||||
void MathService::Divide(int32_t dividend,
|
||||
int32_t divisor,
|
||||
DivideCallback callback) {
|
||||
// Respond with the quotient!
|
||||
std::move(callback).Run(dividend / divisor);
|
||||
}
|
||||
|
||||
} // namespace math
|
32
codelabs/cpp101/services/math/math_service.h
Normal file
32
codelabs/cpp101/services/math/math_service.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2020 The Chromium 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 CODELABS_CPP101_SERVICES_MATH_MATH_SERVICE_H_
|
||||
#define CODELABS_CPP101_SERVICES_MATH_MATH_SERVICE_H_
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "codelabs/cpp101/services/math/public/mojom/math_service.mojom.h"
|
||||
#include "mojo/public/cpp/bindings/receiver.h"
|
||||
|
||||
namespace math {
|
||||
|
||||
class MathService : public mojom::MathService {
|
||||
public:
|
||||
explicit MathService(mojo::PendingReceiver<mojom::MathService> receiver);
|
||||
~MathService() override;
|
||||
MathService(const MathService&) = delete;
|
||||
MathService& operator=(const MathService&) = delete;
|
||||
|
||||
private:
|
||||
// mojom::MathService:
|
||||
void Divide(int32_t dividend,
|
||||
int32_t divisor,
|
||||
DivideCallback callback) override;
|
||||
|
||||
mojo::Receiver<mojom::MathService> receiver_;
|
||||
};
|
||||
|
||||
} // namespace math
|
||||
|
||||
#endif // CODELABS_CPP101_SERVICES_MATH_MATH_SERVICE_H_
|
9
codelabs/cpp101/services/math/public/mojom/BUILD.gn
Normal file
9
codelabs/cpp101/services/math/public/mojom/BUILD.gn
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//mojo/public/tools/bindings/mojom.gni")
|
||||
|
||||
mojom("mojom") {
|
||||
sources = [ "math_service.mojom" ]
|
||||
}
|
2
codelabs/cpp101/services/math/public/mojom/OWNERS
Normal file
2
codelabs/cpp101/services/math/public/mojom/OWNERS
Normal file
@ -0,0 +1,2 @@
|
||||
per-file *.mojom=set noparent
|
||||
per-file *.mojom=file://ipc/SECURITY_OWNERS
|
@ -0,0 +1,9 @@
|
||||
// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
module math.mojom;
|
||||
|
||||
interface MathService {
|
||||
Divide(int32 dividend, int32 divisor) => (int32 quotient);
|
||||
};
|
50
codelabs/cpp101/sleep.cc
Normal file
50
codelabs/cpp101/sleep.cc
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/test/test_timeouts.h"
|
||||
#include "base/threading/sequenced_task_runner_handle.h"
|
||||
#include "base/time/time.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
base::AtExitManager exit_manager;
|
||||
base::CommandLine::Init(argc, argv);
|
||||
TestTimeouts::Initialize();
|
||||
base::test::TaskEnvironment task_environment{
|
||||
base::test::TaskEnvironment::TimeSource::SYSTEM_TIME};
|
||||
|
||||
if (argc <= 1) {
|
||||
LOG(INFO) << argv[0] << ": missing operand";
|
||||
return -1;
|
||||
}
|
||||
|
||||
int duration_seconds = 0;
|
||||
if (!base::StringToInt(argv[1], &duration_seconds) || duration_seconds < 0) {
|
||||
LOG(INFO) << ": invalid time interval '" << argv[1] << "'";
|
||||
return -1;
|
||||
}
|
||||
|
||||
base::RunLoop run_loop;
|
||||
base::TimeDelta duration = base::TimeDelta::FromSeconds(duration_seconds);
|
||||
|
||||
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
|
||||
FROM_HERE, base::BindOnce(run_loop.QuitClosure()), duration);
|
||||
|
||||
// Tasks are run asynchronously, so this will print before the task runs.
|
||||
LOG(INFO) << "Going to sleep for " << duration_seconds << " seconds...";
|
||||
|
||||
// Runs all the tasks that have been posted to the |SequencedTaskRunner|.
|
||||
run_loop.Run();
|
||||
|
||||
// This will NOT complete until |run_loop.QuitClosure()| runs.
|
||||
LOG(INFO) << "I'm awake!";
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user