react-native-windows 0.81.35 → 0.81.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +48 -2
- package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +40 -13
- package/Microsoft.ReactNative/TurboModulesProvider.cpp +30 -13
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/Scripts/creaternwlib.cmd +2 -2
- package/external/fast-float/.syncignore +0 -1
- package/external/fast-float/README.md +545 -0
- package/external/fmt/.syncignore +0 -2
- package/external/fmt/README.md +484 -0
- package/external/fmt/doc/ChangeLog-old.md +3290 -0
- package/external/fmt/doc/api.md +650 -0
- package/external/fmt/doc/fmt.css +61 -0
- package/external/fmt/doc/fmt.js +4 -0
- package/external/fmt/doc/get-started.md +222 -0
- package/external/fmt/doc/index.md +151 -0
- package/external/fmt/doc/perf.svg +1 -0
- package/external/fmt/doc/python-license.txt +290 -0
- package/external/fmt/doc/syntax.md +887 -0
- package/external/folly/.syncignore +2 -3
- package/external/folly/README.md +263 -0
- package/external/folly/folly/docs/AtomicHashMap.md +134 -0
- package/external/folly/folly/docs/Benchmark.md +310 -0
- package/external/folly/folly/docs/Conv.md +291 -0
- package/external/folly/folly/docs/Dynamic.md +220 -0
- package/external/folly/folly/docs/DynamicConverter.md +71 -0
- package/external/folly/folly/docs/Executors.md +63 -0
- package/external/folly/folly/docs/FBString.md +46 -0
- package/external/folly/folly/docs/FBVector.md +200 -0
- package/external/folly/folly/docs/Fbvector--graphical_solutions.png +0 -0
- package/external/folly/folly/docs/Format.md +177 -0
- package/external/folly/folly/docs/Function.md +92 -0
- package/external/folly/folly/docs/Futures.md +263 -0
- package/external/folly/folly/docs/GroupVarint.md +46 -0
- package/external/folly/folly/docs/Histogram.md +104 -0
- package/external/folly/folly/docs/MapUtils.md +80 -0
- package/external/folly/folly/docs/Overview.md +263 -0
- package/external/folly/folly/docs/PackedSyncPtr.md +77 -0
- package/external/folly/folly/docs/Poly.md +500 -0
- package/external/folly/folly/docs/ProducerConsumerQueue.md +82 -0
- package/external/folly/folly/docs/Rcu.md +218 -0
- package/external/folly/folly/docs/SmallLocks.md +24 -0
- package/external/folly/folly/docs/Synchronized.md +793 -0
- package/external/folly/folly/docs/ThreadCachedInt.md +98 -0
- package/external/folly/folly/docs/ThreadLocal.md +105 -0
- package/external/folly/folly/docs/Traits.md +161 -0
- package/external/folly/folly/docs/small_vector.md +64 -0
- package/external/folly/folly/docs/style.css +23 -0
- package/external/folly/static/logo.svg +1 -0
- package/package.json +2 -2
- package/templates/cpp-lib/example/metro.config.js +31 -6
- package/Scripts/Warm-RnwFeedCache.ps1 +0 -413
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
`folly/Format.h`
|
|
2
|
+
----------------
|
|
3
|
+
|
|
4
|
+
`folly/Format.h` provides a fast, powerful, type-safe, flexible facility
|
|
5
|
+
for formatting text, using a specification language similar to Python's
|
|
6
|
+
[str.format](http://docs.python.org/library/string.html#formatstrings).
|
|
7
|
+
By default, it can format strings, numbers (integral and floating point),
|
|
8
|
+
and dynamically-typed `folly::dynamic` objects, and can extract values from
|
|
9
|
+
random-access containers and string-keyed maps. In many cases, `format` is
|
|
10
|
+
faster than `sprintf` as well as being fully type-safe.
|
|
11
|
+
|
|
12
|
+
### Overview
|
|
13
|
+
***
|
|
14
|
+
|
|
15
|
+
Here are some code samples to get started:
|
|
16
|
+
|
|
17
|
+
``` Cpp
|
|
18
|
+
using folly::format;
|
|
19
|
+
using folly::sformat;
|
|
20
|
+
|
|
21
|
+
// Objects produced by format() can be streamed without creating
|
|
22
|
+
// an intermediary string; {} yields the next argument using default
|
|
23
|
+
// formatting.
|
|
24
|
+
std::cout << format("The answers are {} and {}", 23, 42);
|
|
25
|
+
// => "The answers are 23 and 42"
|
|
26
|
+
|
|
27
|
+
// If you just want the string, though, you're covered.
|
|
28
|
+
std::string result = sformat("The answers are {} and {}", 23, 42);
|
|
29
|
+
// => "The answers are 23 and 42"
|
|
30
|
+
|
|
31
|
+
// To insert a literal '{' or '}', just double it.
|
|
32
|
+
std::cout << format("{} {{}} {{{}}}", 23, 42);
|
|
33
|
+
// => "23 {} {42}"
|
|
34
|
+
|
|
35
|
+
// Arguments can be referenced out of order, even multiple times
|
|
36
|
+
std::cout << format("The answers are {1}, {0}, and {1} again", 23, 42);
|
|
37
|
+
// => "The answers are 42, 23, and 42 again"
|
|
38
|
+
|
|
39
|
+
// It's perfectly fine to not reference all arguments
|
|
40
|
+
std::cout << format("The only answer is {1}", 23, 42);
|
|
41
|
+
// => "The only answer is 42"
|
|
42
|
+
|
|
43
|
+
// Values can be extracted from indexable containers
|
|
44
|
+
// (random-access sequences and integral-keyed maps), and also from
|
|
45
|
+
// string-keyed maps
|
|
46
|
+
std::vector<int> v {23, 42};
|
|
47
|
+
std::map<std::string, std::string> m { {"what", "answer"} };
|
|
48
|
+
std::cout << format("The only {1[what]} is {0[1]}", v, m);
|
|
49
|
+
// => "The only answer is 42"
|
|
50
|
+
|
|
51
|
+
// format works with pairs and tuples
|
|
52
|
+
std::tuple<int, std::string, int> t {42, "hello", 23};
|
|
53
|
+
std::cout << format("{0} {2} {1}", t);
|
|
54
|
+
// => "42 23 hello"
|
|
55
|
+
|
|
56
|
+
// Format supports width, alignment, arbitrary fill, and various
|
|
57
|
+
// format specifiers, with meanings similar to printf
|
|
58
|
+
// "X<10": fill with 'X', left-align ('<'), width 10
|
|
59
|
+
std::cout << format("{:X<10} {}", "hello", "world");
|
|
60
|
+
// => "helloXXXXX world"
|
|
61
|
+
|
|
62
|
+
// Field width may be a runtime value rather than part of the format string
|
|
63
|
+
int x = 6;
|
|
64
|
+
std::cout << format("{:-^*}", x, "hi");
|
|
65
|
+
// => "--hi--"
|
|
66
|
+
|
|
67
|
+
// Explicit arguments work with dynamic field width, as long as indexes are
|
|
68
|
+
// given for both the value and the field width.
|
|
69
|
+
std::cout << format("{2:+^*0}",
|
|
70
|
+
9, "unused", 456); // => "+++456+++"
|
|
71
|
+
|
|
72
|
+
// Format supports printf-style format specifiers
|
|
73
|
+
std::cout << format("{0:05d} decimal = {0:04x} hex", 42);
|
|
74
|
+
// => "00042 decimal = 002a hex"
|
|
75
|
+
|
|
76
|
+
// Formatter objects may be written to a string using folly::to or
|
|
77
|
+
// folly::toAppend (see folly/Conv.h), or by calling their appendTo(),
|
|
78
|
+
// and str() methods
|
|
79
|
+
std::string s = format("The only answer is {}", 42).str();
|
|
80
|
+
std::cout << s;
|
|
81
|
+
// => "The only answer is 42"
|
|
82
|
+
|
|
83
|
+
// Decimal precision usage
|
|
84
|
+
std::cout << format("Only 2 decimals is {:.2f}", 23.34134534535);
|
|
85
|
+
// => "Only 2 decimals is 23.34"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
### Format string syntax
|
|
90
|
+
***
|
|
91
|
+
|
|
92
|
+
Format string (`format`):
|
|
93
|
+
`"{" [arg_index] ["[" key "]"] [":" format_spec] "}"`
|
|
94
|
+
|
|
95
|
+
- `arg_index`: index of argument to format; default = next argument. Note
|
|
96
|
+
that a format string may have either default argument indexes or
|
|
97
|
+
non-default argument indexes, but not both (to avoid confusion).
|
|
98
|
+
- `key`: if the argument is a container (C-style array or pointer,
|
|
99
|
+
`std::array`, vector, deque, map), you may use this
|
|
100
|
+
to select the element to format; works with random-access sequences and
|
|
101
|
+
integer- and string-keyed maps. Multiple level keys work as well, with
|
|
102
|
+
components separated with "."; for example, given
|
|
103
|
+
`map<string, map<string, string>> m`, `{[foo.bar]}` selects
|
|
104
|
+
`m["foo"]["bar"]`.
|
|
105
|
+
- `format_spec`: format specification, see below
|
|
106
|
+
|
|
107
|
+
Format specification:
|
|
108
|
+
`[[fill] align] [sign] ["#"] ["0"] [width] [","] ["." precision] ["."] [type]`
|
|
109
|
+
|
|
110
|
+
- `fill` (may only be specified if `align` is also specified): pad with this
|
|
111
|
+
character ('` `' (space) or '`0`' (zero) might be useful; space is default)
|
|
112
|
+
- `align`: one of '`<`', '`>`', '`=`', '`^`':
|
|
113
|
+
- '`<`': left-align (default for most objects)
|
|
114
|
+
- '`>`': right-align (default for numbers)
|
|
115
|
+
- '`=`': pad after sign, but before significant digits; used to print
|
|
116
|
+
`-0000120`; only valid for numbers
|
|
117
|
+
- '`^`': center
|
|
118
|
+
- `sign`: one of '`+`', '`-`', ' ' (space) (only valid for numbers)
|
|
119
|
+
- '`+`': output '`+`' if positive or zero, '`-`' if negative
|
|
120
|
+
- '`-`': output '`-`' if negative, nothing otherwise (default)
|
|
121
|
+
- '` `' (space): output '` `' (space) if positive or zero, '`-`' if negative
|
|
122
|
+
- '`#`': output base prefix (`0` for octal, `0b` or `0B` for binary, `0x` or
|
|
123
|
+
`0X` for hexadecimal; only valid for integers)
|
|
124
|
+
- '`0`': 0-pad after sign, same as specifying "`0=`" as the `fill` and
|
|
125
|
+
`align` parameters (only valid for numbers)
|
|
126
|
+
- `width`: minimum field width. May be '`*`' to indicate that the field width
|
|
127
|
+
is given by an argument. Defaults to the next argument (preceding the value
|
|
128
|
+
to be formatted) but an explicit argument index may be given following the
|
|
129
|
+
'`*`'.
|
|
130
|
+
- '`,`' (comma): output comma as thousands' separator (only valid for integers,
|
|
131
|
+
and only for decimal output)
|
|
132
|
+
- `precision` (not allowed for integers):
|
|
133
|
+
- for floating point values, number of digits after decimal point ('`f`' or
|
|
134
|
+
'`F`' presentation) or number of significant digits ('`g`' or '`G`')
|
|
135
|
+
- for others, maximum field size (truncate subsequent characters)
|
|
136
|
+
- '`.`' (when used after precision or in lieu of precison): Forces a trailing
|
|
137
|
+
decimal point to make it clear this is a floating point value.
|
|
138
|
+
- `type`: presentation format, see below
|
|
139
|
+
|
|
140
|
+
Presentation formats:
|
|
141
|
+
|
|
142
|
+
- Strings (`folly::StringPiece`, `std::string`, `folly::fbstring`,
|
|
143
|
+
`const char*`):
|
|
144
|
+
- '`s`' (default)
|
|
145
|
+
- Integers:
|
|
146
|
+
- '`b`': output in binary (base 2) ("`0b`" prefix if '`#`' specified)
|
|
147
|
+
- '`B`': output in binary (base 2) ("`0B`" prefix if '`#`' specified)
|
|
148
|
+
- '`c`': output as a character (cast to `char`)
|
|
149
|
+
- '`d`': output in decimal (base 10) (default)
|
|
150
|
+
- '`o`': output in octal (base 8)
|
|
151
|
+
- '`O`': output in octal (base 8) (same as '`o`')
|
|
152
|
+
- '`x`': output in hexadecimal (base 16) (lower-case digits above 9)
|
|
153
|
+
- '`X`': output in hexadecimal (base 16) (upper-case digits above 9)
|
|
154
|
+
- '`n`': locale-aware output (currently same as '`d`')
|
|
155
|
+
- `bool`:
|
|
156
|
+
- default: output "`true`" or "`false`" as strings
|
|
157
|
+
- integer presentations allowed as well
|
|
158
|
+
- `char`:
|
|
159
|
+
- same as other integers, but default is '`c`' instead of '`d`'
|
|
160
|
+
- Floating point (`float`, `double`; `long double` is not implemented):
|
|
161
|
+
- '`e`': scientific notation using '`e`' as exponent character
|
|
162
|
+
- '`E`': scientific notation using '`E`' as exponent character
|
|
163
|
+
- '`f`': fixed point
|
|
164
|
+
- '`F`': fixed point (same as '`f`')
|
|
165
|
+
- '`g`': general; use either '`f`' or '`e`' depending on magnitude (default)
|
|
166
|
+
- '`G`': general; use either '`f`' or '`E`' depending on magnitude
|
|
167
|
+
- '`n`': locale-aware version of '`g`' (currently same as '`g`')
|
|
168
|
+
- '`%`': percentage: multiply by 100 then display as '`f`'
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
### Extension
|
|
172
|
+
***
|
|
173
|
+
|
|
174
|
+
You can extend `format` for your own class by providing a specialization for
|
|
175
|
+
`folly::FormatValue`. See `folly/Format.h` and `folly/FormatArg.h` for
|
|
176
|
+
details, and the existing specialization for `folly::dynamic` in
|
|
177
|
+
`folly/dynamic-inl.h` for an implementation example.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
`folly/Function.h`
|
|
2
|
+
------------------
|
|
3
|
+
|
|
4
|
+
`folly::Function` is a polymorphic function wrapper that is not copyable and does not require the wrapped function to be copy constructible. It is similar to `std::function`, but different with respect to some interesting features.
|
|
5
|
+
|
|
6
|
+
There are some limitations in `std::function` that `folly::Function` tries to avoid. `std::function` is copy-constructible and requires that the callable that it wraps is copy-constructible as well, which is a constraint that is often inconvenient. In most cases when using a `std::function` you don't make use of its copy-constructibility, so you might sometimes feel like you get back very little in return for a noticeable restriction.
|
|
7
|
+
|
|
8
|
+
This restriction becomes apparent when trying to use a lambda capturing a `unique_ptr` (or any non-copyable type) as a callback for a folly::Future.
|
|
9
|
+
``` Cpp
|
|
10
|
+
std::unique_ptr<Foo> foo_ptr = new Foo;
|
|
11
|
+
|
|
12
|
+
some_future.then(
|
|
13
|
+
[foo_ptr = std::move(foo_ptr)] mutable
|
|
14
|
+
(int x)
|
|
15
|
+
{ foo_ptr->setX(x); }
|
|
16
|
+
);
|
|
17
|
+
```
|
|
18
|
+
This piece of code did not compile before `folly::Future` started using `folly::Function` instead of `std::function` to store the callback. Because the lambda captures something non-copyable (the `unique_ptr`), it is not copyable itself. And `std::function` can only store copyable callables.
|
|
19
|
+
|
|
20
|
+
The implementation of folly::Future did not make use of the copy-constructibility of `std::function` at any point. There was no benefit from the fact that the `std::function` is copy-constructible, but the fact that it can only wrap copy-constructible callables posed a restriction.
|
|
21
|
+
|
|
22
|
+
A workaround was available: `folly::MoveWrapper`, which wraps an object that may be non-copyable and implements copy operations by moving the embedded object. Using a `folly::MoveWrapper`, you can capture non-copyable objects in a lambda, and the lambda itself is still copyable and may be wrapped in a `std::function`. It is a pragmatic solution for the above problem, but you have to be a little careful. The problem is that you can’t use a `MoveWrapper` anywhere where copy operations are assumed to behave like actual copy operations. Also, a `folly::MoveWrapper<std::unique_ptr<T>>` essentially behaves like `auto_ptr<T>`. Ask yourself whether you’d want to use lots of `auto_ptr`s in your codebase. And the original question still persists: we very often don’t benefit from copy-constructibility of `std::function`, so why do we have to live with this restriction? I.e. why do we have to use `MoveWrapper`?
|
|
23
|
+
|
|
24
|
+
`folly::Function` is an actual solution to this problem, as it can wrap non-copyable callables, at the cost of not being copy-constructible, which more often than not is not a relevant restriction. `folly::Future` now uses `folly::Function` to store callbacks, so the good news is: the code example from the top of this note is becoming a perfectly valid way to use future callbacks. The code compiles and behaves as you would expect.
|
|
25
|
+
|
|
26
|
+
Here are more details about `folly::Function`: much like `std::function`, it wraps an arbitrary object that can be invoked like a given function type. E.g. a `folly::Function<int(std::string, double)>` can wrap any callable object that returns an `int` (or something that is convertible to an `int`) when invoked with a `std::string` and a `double` argument. The function type is a template parameter of `folly::Function`, but the specific type of the callable is not.
|
|
27
|
+
|
|
28
|
+
Other than copyability, there is one more significant difference between `std::function` and `folly::Function`, and it concerns const-correctness. `std::function` does not enforce const-correctness: it allows you to store mutable callables (i.e. callables that may change their inner state when executed, such as a mutable lambda) and call them in a const context (i.e. when you only have access to a const reference to the `std::function` object). For example:
|
|
29
|
+
``` Cpp
|
|
30
|
+
class FooBar {
|
|
31
|
+
public:
|
|
32
|
+
void call_func() const {
|
|
33
|
+
func_();
|
|
34
|
+
}
|
|
35
|
+
private:
|
|
36
|
+
std::function<void()> func_;
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
The `call_func` member function is declared const. However, when it calls `func_()`, it may change the inner state of `func_`, and thereby the inner state of the `FooBar` object. Inside the `FooBar` class, `func_` is like a non-const method that is callable from const methods.
|
|
40
|
+
|
|
41
|
+
Some people consider `std::function` in the standard broken with respect to this. (Paper N4348 explains this problem in more detail.) It also lists possible ways to fix the problem. `folly::Function`, however, goes a different way: you have to declare whether you want to store a const function, in which case you can invoke any reference (const or non-const) of the `folly::Function`, or a non-const (mutable) function, in which case you need a non-const reference to the `folly::Function` to be able to invoke it. In the above example, let’s say that `func_` stores a const function, which makes it okay that it gets invoked from `call_func` (a const method). Instead of `std::function`, you could use `folly::Function<void() const>` for the `func_` member.
|
|
42
|
+
|
|
43
|
+
Const-ness is part of a function type. To illustrate:
|
|
44
|
+
``` Cpp
|
|
45
|
+
class Foo {
|
|
46
|
+
public:
|
|
47
|
+
int operator()() { return 1; }
|
|
48
|
+
int operator()(char const*) { return 2; }
|
|
49
|
+
int operator()(int) { return 3; }
|
|
50
|
+
int operator()(int) const { return 4; }
|
|
51
|
+
int operator()(int, int) const { return 5; }
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
You can overload methods multiple times using different argument signatures. Const-ness is part of that signature, so even for the same set of argument types you can overload a const and a non-const version. It’s not even particularly unusual to do that. Take for instance the `begin()` method of STL container types: `begin()` returns an `iterator`, `begin() const` returns a `const_iterator`. `folly::Function` allows you to select a specific overload easily:
|
|
55
|
+
``` Cpp
|
|
56
|
+
folly::Function<int()> uf1 = Foo();
|
|
57
|
+
// uf1() returns 1
|
|
58
|
+
folly::Function<int(char const*)> uf2 = Foo();
|
|
59
|
+
// uf2() returns 2
|
|
60
|
+
folly::Function<int(int)> uf3 = Foo();
|
|
61
|
+
// uf3() returns 3
|
|
62
|
+
folly::Function<int(int) const> uf4 = Foo();
|
|
63
|
+
// uf4() returns 4
|
|
64
|
+
folly::Function<int(int, int) const> uf5 = Foo();
|
|
65
|
+
// uf5() returns 5
|
|
66
|
+
```
|
|
67
|
+
If `cfoo` is a const-reference to a `Foo` object, `cfoo(int)` returns 4. If `foo` is a non-const reference to a `Foo` object, `foo(int)` returns 3. Normal const-to-non-const conversion behavior applies: if you call `foo(int, int)` it will return 5: a non-const reference will invoke the const method if no non-const method is defined. Which leads to the following behavior:
|
|
68
|
+
``` Cpp
|
|
69
|
+
folly::Function<int(int, int)> uf5nc = Foo();
|
|
70
|
+
// uf5nc() returns 5
|
|
71
|
+
```
|
|
72
|
+
If you are wondering if the introduction of const function types means that you have to change lots of normal function types to const function types if you want to use `folly::Function`: not really, or at least not as much as you might think. There are only two reasons to use a `folly::Function` with a const function type:
|
|
73
|
+
* a callable object defines both const and non-const `operator()` and you explicitly want to select the const one
|
|
74
|
+
* you need to invoke a `folly::Function` from a const context (i.e. you only have a const reference to the `folly::Function`)
|
|
75
|
+
|
|
76
|
+
In practice, you will not need the const variant very often. Adding const to a function type adds a restriction for the callable: it must not change its inner state when invoked. If you don’t care whether it does or not, don’t worry about const!
|
|
77
|
+
|
|
78
|
+
A `folly::Function<R(Args...) const>` can be converted into a `folly::Function<R(Args...)>`: either way the stored callable will not change its inner state when invoked. The former type expresses and guarantees that, the latter does not. When you get rid of the const, the selected function stays the same:
|
|
79
|
+
``` Cpp
|
|
80
|
+
folly::Function<int(int)> uf4nc = std::move(uf4);
|
|
81
|
+
// uf4nc() returns 4, not 3!
|
|
82
|
+
```
|
|
83
|
+
If you want to go the other way, you are talking about a (potentially dangerous) const cast: a callable that may or may not change its inner state is declared as one that guarantees not to do that. Proceed at your own risk! This conversion does not happen implicitly, though:
|
|
84
|
+
``` Cpp
|
|
85
|
+
folly::Function<int() const> uf1c = folly::constCastFunction(std::move(uf1));
|
|
86
|
+
// uf1c() returns 1
|
|
87
|
+
```
|
|
88
|
+
Admittedly, seeing const function types as template parameters is unfamiliar. As far as I am aware it happens nowhere in the standard library. But it is the most consistent way to deal with the issue of const-correctness here. Const qualifiers are part of a function type, as a matter of fact. If you require a const-qualified function to be wrapped in a `folly::Function`, just declare it as that! More often than not you will find that you do not need the const qualifier. While writing the `folly::Function` implementation, a good set of unit tests had existed before the const function types got introduced. Not a single one of those unit tests had to be changed: they all compiled and passed after the introduction of const function types. Obviously new ones were added to test the const-correctness. But in your day-to-day use of `folly::Function` you won’t have to worry about const very often.
|
|
89
|
+
|
|
90
|
+
Memory usage
|
|
91
|
+
============
|
|
92
|
+
Like most implementations of `std::function`, `folly::Function` stores small callable objects in-line and larger callable objects will be stored on the heap. `folly::Function` returns the size of the allocation it has made from its `heapAllocatedMemory()` member function; naturally it will return `0` when the callable is stored in-line.
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Futures
|
|
2
|
+
|
|
3
|
+
### Futures is a framework for expressing asynchronous code in C++ using the Promise/Future pattern.
|
|
4
|
+
|
|
5
|
+
# Overview
|
|
6
|
+
|
|
7
|
+
Folly Futures is an async C++ framework inspired by [Twitter's Futures](https://twitter.github.io/finagle/guide/Futures.html) implementation in Scala (see also [Future.scala](https://github.com/twitter/util/blob/master/util-core/src/main/scala/com/twitter/util/Future.scala), [Promise.scala](https://github.com/twitter/util/blob/master/util-core/src/main/scala/com/twitter/util/Promise.scala), and friends), and loosely builds upon the existing but anemic Futures code found in the C++11 standard ([std::future](https://en.cppreference.com/w/cpp/thread/future)) and [boost::future](https://www.boost.org/doc/libs/1_53_0/doc/html/thread/synchronization.html#thread.synchronization.futures) (especially >= 1.53.0). Although inspired by the C++11 std::future interface, it is not a drop-in replacement because some ideas don't translate well enough to maintain API compatibility.
|
|
8
|
+
|
|
9
|
+
The primary difference from std::future is that you can attach callbacks to Futures (with `thenValue` or `thenTry`), under the control of an executor to manage where work runs, which enables sequential and parallel composition of Futures for cleaner asynchronous code.
|
|
10
|
+
|
|
11
|
+
# Brief Synopsis
|
|
12
|
+
|
|
13
|
+
```cpp
|
|
14
|
+
#include <folly/futures/Future.h>
|
|
15
|
+
#include <folly/executors/ThreadedExecutor.h>
|
|
16
|
+
using namespace folly;
|
|
17
|
+
using namespace std;
|
|
18
|
+
|
|
19
|
+
void foo(int x) {
|
|
20
|
+
// do something with x
|
|
21
|
+
cout << "foo(" << x << ")" << endl;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ...
|
|
25
|
+
folly::ThreadedExecutor executor;
|
|
26
|
+
cout << "making Promise" << endl;
|
|
27
|
+
Promise<int> p;
|
|
28
|
+
Future<int> f = p.getSemiFuture().via(&executor);
|
|
29
|
+
auto f2 = move(f).thenValue(foo);
|
|
30
|
+
cout << "Future chain made" << endl;
|
|
31
|
+
|
|
32
|
+
// ... now perhaps in another event callback
|
|
33
|
+
|
|
34
|
+
cout << "fulfilling Promise" << endl;
|
|
35
|
+
p.setValue(42);
|
|
36
|
+
move(f2).get();
|
|
37
|
+
cout << "Promise fulfilled" << endl;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This would print:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
making Promise
|
|
44
|
+
Future chain made
|
|
45
|
+
fulfilling Promise
|
|
46
|
+
foo(42)
|
|
47
|
+
Promise fulfilled
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Blog Post
|
|
51
|
+
|
|
52
|
+
In addition to this document, there is [a blog post on code.facebook.com (June
|
|
53
|
+
2015)](https://code.facebook.com/posts/1661982097368498/futures-for-c-11-at-facebook/).
|
|
54
|
+
|
|
55
|
+
# Brief guide
|
|
56
|
+
This brief guide covers the basics. For a more in-depth coverage skip to the appropriate section.
|
|
57
|
+
|
|
58
|
+
Let's begin with an example using an imaginary simplified Memcache client interface:
|
|
59
|
+
|
|
60
|
+
```cpp
|
|
61
|
+
using std::string;
|
|
62
|
+
class MemcacheClient {
|
|
63
|
+
public:
|
|
64
|
+
struct GetReply {
|
|
65
|
+
enum class Result {
|
|
66
|
+
FOUND,
|
|
67
|
+
NOT_FOUND,
|
|
68
|
+
SERVER_ERROR,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
Result result;
|
|
72
|
+
// The value when result is FOUND,
|
|
73
|
+
// The error message when result is SERVER_ERROR or CLIENT_ERROR
|
|
74
|
+
// undefined otherwise
|
|
75
|
+
string value;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
GetReply get(string key);
|
|
79
|
+
};
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
This API is synchronous, i.e. when you call `get()` you have to wait for the result. This is very simple, but unfortunately it is also very easy to write very slow code using synchronous APIs.
|
|
83
|
+
|
|
84
|
+
Now, consider this traditional asynchronous signature for the same operation:
|
|
85
|
+
|
|
86
|
+
```cpp
|
|
87
|
+
int async_get(string key, std::function<void(GetReply)> callback);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
When you call `async_get()`, your asynchronous operation begins and when it finishes your callback will be called with the result. Very performant code can be written with an API like this, but for nontrivial applications the code devolves into a special kind of spaghetti code affectionately referred to as "callback hell".
|
|
91
|
+
|
|
92
|
+
The Future-based API looks like this:
|
|
93
|
+
|
|
94
|
+
```cpp
|
|
95
|
+
SemiFuture<GetReply> future_get(string key);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
A `SemiFuture<GetReply>` or `Future<GetReply>` is a placeholder for the `GetReply` that we will eventually get. For most of the descriptive text below, Future can refer to either `folly::SemiFuture` or `folly::Future` as the former is a safe subset of the latter. A Future usually starts life out "unfulfilled", or incomplete, i.e.:
|
|
99
|
+
|
|
100
|
+
```cpp
|
|
101
|
+
fut.isReady() == false
|
|
102
|
+
fut.value() // will throw an exception because the Future is not ready
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
At some point in the future, the `Future` will have been fulfilled, and we can access its value.
|
|
106
|
+
|
|
107
|
+
```cpp
|
|
108
|
+
fut.isReady() == true
|
|
109
|
+
GetReply& reply = fut.value();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Futures support exceptions. If the asynchronous producer fails with an exception, your Future may represent an exception instead of a value. In that case:
|
|
113
|
+
|
|
114
|
+
```cpp
|
|
115
|
+
fut.isReady() == true
|
|
116
|
+
fut.value() // will rethrow the exception
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Just what is exceptional depends on the API. In our example we have chosen not to raise exceptions for `SERVER_ERROR`, but represent this explicitly in the `GetReply` object. On the other hand, an astute Memcache veteran would notice that we left `CLIENT_ERROR` out of `GetReply::Result`, and perhaps a `CLIENT_ERROR` would have been raised as an exception, because `CLIENT_ERROR` means there's a bug in the library and this would be truly exceptional. These decisions are judgement calls by the API designer. The important thing is that exceptional conditions (including and especially spurious exceptions that nobody expects) get captured and can be handled higher up the "stack".
|
|
120
|
+
|
|
121
|
+
So far we have described a way to initiate an asynchronous operation via an API that returns a Future, and then sometime later after it is fulfilled, we get its value. This is slightly more useful than a synchronous API, but it's not yet ideal. There are two more very important pieces to the puzzle.
|
|
122
|
+
|
|
123
|
+
First, we can aggregate Futures, to define a new Future that completes after some or all of the aggregated Futures complete. Consider two examples: fetching a batch of requests and waiting for all of them, and fetching a group of requests and waiting for only one of them.
|
|
124
|
+
|
|
125
|
+
```cpp
|
|
126
|
+
MemcacheClient mc;
|
|
127
|
+
|
|
128
|
+
vector<SemiFuture<GetReply>> futs;
|
|
129
|
+
for (auto& key : keys) {
|
|
130
|
+
futs.push_back(mc.future_get(key));
|
|
131
|
+
}
|
|
132
|
+
auto all = collectAll(futs.begin(), futs.end());
|
|
133
|
+
|
|
134
|
+
vector<SemiFuture<GetReply>> futs;
|
|
135
|
+
for (auto& key : keys) {
|
|
136
|
+
futs.push_back(mc.future_get(key));
|
|
137
|
+
}
|
|
138
|
+
auto any = collectAny(futs.begin(), futs.end());
|
|
139
|
+
|
|
140
|
+
vector<SemiFuture<GetReply>> futs;
|
|
141
|
+
for (auto& key : keys) {
|
|
142
|
+
futs.push_back(mc.future_get(key));
|
|
143
|
+
}
|
|
144
|
+
auto anyv = collectAnyWithoutException(futs.begin(), futs.end());
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`all` and `any` are Futures (for the exact type and usage see the header files). They will be complete when all/one of futs are complete, respectively. (There is also `collectN()` for when you need some, and `collectAnyWithoutException` when you need one value if some value would be available.)
|
|
148
|
+
|
|
149
|
+
Second, we can associate a Future with an executor. An executor specifies where work will run, and we detail this more later. In summary, given an executor we can convert a `SemiFuture` to a `Future` with an executor, or a `Future` on one executor to a `Future` on another executor.
|
|
150
|
+
|
|
151
|
+
For example:
|
|
152
|
+
|
|
153
|
+
```cpp
|
|
154
|
+
folly::ThreadedExecutor executor;
|
|
155
|
+
SemiFuture<GetReply> semiFut = mc.future_get("foo");
|
|
156
|
+
Future<GetReply> fut1 = std::move(semiFut).via(&executor);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Once an executor is attached, a `Future` allows continuations to be attached and chained together monadically. An example will clarify:
|
|
160
|
+
|
|
161
|
+
```cpp
|
|
162
|
+
SemiFuture<GetReply> semiFut = mc.future_get("foo");
|
|
163
|
+
Future<GetReply> fut1 = std::move(semiFut).via(&executor);
|
|
164
|
+
|
|
165
|
+
Future<string> fut2 = std::move(fut1).thenValue(
|
|
166
|
+
[](GetReply reply) {
|
|
167
|
+
if (reply.result == MemcacheClient::GetReply::Result::FOUND)
|
|
168
|
+
return reply.value;
|
|
169
|
+
throw SomeException("No value");
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
Future<Unit> fut3 = std::move(fut2)
|
|
173
|
+
.thenValue([](string str) {
|
|
174
|
+
cout << str << endl;
|
|
175
|
+
})
|
|
176
|
+
.thenTry([](folly::Try<string> strTry) {
|
|
177
|
+
cout << strTry.value() << endl;
|
|
178
|
+
})
|
|
179
|
+
.thenError(folly::tag_t<std::exception>{}, [](std::exception const& e) {
|
|
180
|
+
cerr << e.what() << endl;
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
That example is a little contrived but the idea is that you can transform a result from one type to another, potentially in a chain, and unhandled errors propagate. Of course, the intermediate variables are optional.
|
|
185
|
+
|
|
186
|
+
Using `.thenValue` or `.thenTry` to add callbacks is idiomatic. It brings all the code into one place, which avoids callback hell. `.thenValue` appends a continuation that takes `T&&` for some `Future<T>` and an error bypasses the callback and is passed to the next, `thenTry` takes a callback taking `folly::Try<T>` which encapsulates both value and exception. `thenError(tag_t<ExceptionType>{},...` will bypass a value and only run if there is an exception, the `ExceptionType` template parameter to the tag type allows filtering by exception type; `tag_t<ExceptionType>{}` is optional and if no tag is passed passed the function will be parameterized with a `folly::exception_wrapper`. For C++17 there is a global inline variable and `folly::tag<ExceptionType>` may be passed directly without explicit construction.
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
Up to this point we have skirted around the matter of waiting for Futures. You may never need to wait for a Future, because your code is event-driven and all follow-up action happens in a then-block. But if want to have a batch workflow, where you initiate a batch of asynchronous operations and then wait for them all to finish at a synchronization point, then you will want to wait for a Future. Futures have a blocking method called `wait()` that does exactly that and optionally takes a timeout.
|
|
191
|
+
|
|
192
|
+
Futures are partially threadsafe. A Promise or Future can migrate between threads as long as there's a full memory barrier of some sort. `Future::thenValue` and `Promise::setValue` (and all variants that boil down to those two calls) can be called from different threads. **But**, be warned that you might be surprised about which thread your callback executes on. Let's consider an example, where we take a future straight from a promise, without going via the safer SemiFuture, and where we therefore have a `Future` that does not carry an executor. This is in general something to avoid.
|
|
193
|
+
|
|
194
|
+
```cpp
|
|
195
|
+
// Thread A
|
|
196
|
+
Promise<Unit> p;
|
|
197
|
+
auto f = p.getFuture();
|
|
198
|
+
|
|
199
|
+
// Thread B
|
|
200
|
+
std::move(f).thenValue(x).thenValue(y).thenTry(z);
|
|
201
|
+
|
|
202
|
+
// Thread A
|
|
203
|
+
p.setValue();
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
This is legal and technically threadsafe. However, it is important to realize that you do not know in which thread `x`, `y`, and/or `z` will execute. Maybe they will execute in Thread A when `p.setValue()` is called. Or, maybe they will execute in Thread B when `f.thenValue` is called. Or, maybe `x` will execute in Thread A, but `y` and/or `z` will execute in Thread B. There's a race between `setValue` and `then`—whichever runs last will execute the callback. The only guarantee is that one of them will run the callback.
|
|
207
|
+
|
|
208
|
+
For safety, `.via` should be preferred. We can chain `.via` operations to give very strong control over where callbacks run:
|
|
209
|
+
|
|
210
|
+
```cpp
|
|
211
|
+
std::move(aFuture)
|
|
212
|
+
.thenValue(x)
|
|
213
|
+
.via(e1).thenValue(y1).thenValue(y2)
|
|
214
|
+
.via(e2).thenValue(z);
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`x` will execute in the context of the executor associated with `aFuture`. `y1` and `y2` will execute in the context of `e1`, and `z` will execute in the context of `e2`. If after `z` you want to get back to the original context, you need to get there with a call to `via` passing the original executor.
|
|
218
|
+
|
|
219
|
+
# You make me Promises, Promises
|
|
220
|
+
|
|
221
|
+
If you are wrapping an asynchronous operation, or providing an asynchronous API to users, then you will want to make `Promise`s. Every Future has a corresponding Promise (except Futures that spring into existence already completed, with `makeFuture()`). Promises are simple: you make one, you extract the Future, and you fulfill it with a value or an exception. Example:
|
|
222
|
+
|
|
223
|
+
```cpp
|
|
224
|
+
Promise<int> p;
|
|
225
|
+
SemiFuture<int> f = p.getSemiFuture();
|
|
226
|
+
|
|
227
|
+
f.isReady() == false
|
|
228
|
+
|
|
229
|
+
p.setValue(42);
|
|
230
|
+
|
|
231
|
+
f.isReady() == true
|
|
232
|
+
f.value() == 42
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
and an exception example:
|
|
236
|
+
|
|
237
|
+
```cpp
|
|
238
|
+
Promise<int> p;
|
|
239
|
+
SemiFuture<int> f = p.getSemiFuture();
|
|
240
|
+
|
|
241
|
+
f.isReady() == false
|
|
242
|
+
|
|
243
|
+
p.setException(std::runtime_error("Fail"));
|
|
244
|
+
|
|
245
|
+
f.isReady() == true
|
|
246
|
+
f.value() // throws the exception
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
It's good practice to use setWith which takes a function and automatically captures exceptions, e.g.
|
|
250
|
+
|
|
251
|
+
```cpp
|
|
252
|
+
Promise<int> p;
|
|
253
|
+
p.setWith([]{
|
|
254
|
+
try {
|
|
255
|
+
// do stuff that may throw
|
|
256
|
+
return 42;
|
|
257
|
+
} catch (MySpecialException const& e) {
|
|
258
|
+
// handle it
|
|
259
|
+
return 7;
|
|
260
|
+
}
|
|
261
|
+
// Any exceptions that we didn't catch, will be caught for us
|
|
262
|
+
});
|
|
263
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
`folly/GroupVarint.h`
|
|
2
|
+
---------------------
|
|
3
|
+
|
|
4
|
+
`folly/GroupVarint.h` is an implementation of variable-length encoding for 32-
|
|
5
|
+
and 64-bit integers using the Group Varint encoding scheme as described in
|
|
6
|
+
Jeff Dean's [WSDM 2009 talk][wsdm] and in [Information Retrieval: Implementing
|
|
7
|
+
and Evaluating Search Engines][irbook].
|
|
8
|
+
|
|
9
|
+
[wsdm]: http://research.google.com/people/jeff/WSDM09-keynote.pdf
|
|
10
|
+
[irbook]: http://www.ir.uwaterloo.ca/book/addenda-06-index-compression.html
|
|
11
|
+
|
|
12
|
+
Briefly, a group of four 32-bit integers is encoded as a sequence of variable
|
|
13
|
+
length, between 5 and 17 bytes; the first byte encodes the length (in bytes)
|
|
14
|
+
of each integer in the group. A group of five 64-bit integers is encoded as a
|
|
15
|
+
sequence of variable length, between 7 and 42 bytes; the first two bytes
|
|
16
|
+
encode the length (in bytes) of each integer in the group.
|
|
17
|
+
|
|
18
|
+
`GroupVarint.h` defines a few classes:
|
|
19
|
+
|
|
20
|
+
* `GroupVarint<T>`, where `T` is `uint32_t` or `uint64_t`:
|
|
21
|
+
|
|
22
|
+
Basic encoding / decoding interface, mainly aimed at encoding / decoding
|
|
23
|
+
one group at a time.
|
|
24
|
+
|
|
25
|
+
* `GroupVarintEncoder<T, Output>`, where `T` is `uint32_t` or `uint64_t`,
|
|
26
|
+
and `Output` is a functor that accepts `StringPiece` objects as arguments:
|
|
27
|
+
|
|
28
|
+
Streaming encoder: add values one at a time, and they will be
|
|
29
|
+
flushed to the output one group at a time. Handles the case where
|
|
30
|
+
the last group is incomplete (the number of integers to encode isn't
|
|
31
|
+
a multiple of the group size)
|
|
32
|
+
|
|
33
|
+
* `GroupVarintDecoder<T>`, where `T` is `uint32_t` or `uint64_t`:
|
|
34
|
+
|
|
35
|
+
Streaming decoder: extract values one at a time. Handles the case where
|
|
36
|
+
the last group is incomplete.
|
|
37
|
+
|
|
38
|
+
The 32-bit implementation is significantly faster than the 64-bit
|
|
39
|
+
implementation; on platforms supporting the SSSE3 instruction set, we
|
|
40
|
+
use the PSHUFB instruction to speed up lookup, as described in [SIMD-Based
|
|
41
|
+
Decoding of Posting Lists][cikmpaper] (CIKM 2011).
|
|
42
|
+
|
|
43
|
+
[cikmpaper]: http://www.stepanovpapers.com/CIKM_2011.pdf
|
|
44
|
+
|
|
45
|
+
For more details, see the header file `folly/GroupVarint.h` and the
|
|
46
|
+
associated test file `folly/test/GroupVarintTest.cpp`.
|