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",
|
"//base/util:base_util_unittests",
|
||||||
"//chrome/installer",
|
"//chrome/installer",
|
||||||
"//chrome/updater",
|
"//chrome/updater",
|
||||||
|
"//codelabs",
|
||||||
"//components:components_unittests",
|
"//components:components_unittests",
|
||||||
"//components/gwp_asan:gwp_asan_unittests",
|
"//components/gwp_asan:gwp_asan_unittests",
|
||||||
"//net:net_unittests",
|
"//net:net_unittests",
|
||||||
|
@@ -68,6 +68,8 @@ _TEST_CODE_EXCLUDED_PATHS = (
|
|||||||
r'ios[\\/].*_app_interface\.mm$',
|
r'ios[\\/].*_app_interface\.mm$',
|
||||||
# Views Examples code
|
# Views Examples code
|
||||||
r'ui[\\/]views[\\/]examples[\\/].*',
|
r'ui[\\/]views[\\/]examples[\\/].*',
|
||||||
|
# Chromium Codelab
|
||||||
|
r'codelabs[\\/]*'
|
||||||
)
|
)
|
||||||
|
|
||||||
_THIRD_PARTY_EXCEPT_BLINK = 'third_party/(?!blink/)'
|
_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