Commit 0e32d9f4 authored by Nikita Mikhaylov's avatar Nikita Mikhaylov Committed by Facebook GitHub Bot

Added highlighting to code snippets in docs. (#1364)

Summary:
It was very hard to read without any code highligting.
Pull Request resolved: https://github.com/facebook/folly/pull/1364

Reviewed By: Orvid

Differential Revision: D21921822

Pulled By: yfeldblum

fbshipit-source-id: aa1bc39a5d38b055fe4370ccd4ac0b7d5e0273d4
parent c4fa5482
...@@ -12,7 +12,7 @@ format. ...@@ -12,7 +12,7 @@ format.
Simply pass a dynamic into a templated convertTo: Simply pass a dynamic into a templated convertTo:
``` ```cpp
dynamic d = { { 1, 2, 3 }, { 4, 5 } }; // a vector of vector of int dynamic d = { { 1, 2, 3 }, { 4, 5 } }; // a vector of vector of int
auto vvi = convertTo<fbvector<fbvector<int>>>(d); auto vvi = convertTo<fbvector<fbvector<int>>>(d);
``` ```
......
...@@ -10,14 +10,14 @@ dramatic, and occasionally spectacular. ...@@ -10,14 +10,14 @@ dramatic, and occasionally spectacular.
### Sample ### Sample
*** ***
```cpp
folly::fbvector<int> numbers({0, 1, 2, 3}); folly::fbvector<int> numbers({0, 1, 2, 3});
numbers.reserve(10); numbers.reserve(10);
for (int i = 4; i < 10; i++) { for (int i = 4; i < 10; i++) {
numbers.push_back(i * 2); numbers.push_back(i * 2);
} }
assert(numbers[6] == 12); assert(numbers[6] == 12);
```
### Motivation ### Motivation
*** ***
...@@ -148,7 +148,7 @@ times. A bloody mess, that's what it was." ...@@ -148,7 +148,7 @@ times. A bloody mess, that's what it was."
Only a tiny minority of objects are genuinely non-relocatable: Only a tiny minority of objects are genuinely non-relocatable:
* Objects that use internal pointers, e.g.: * Objects that use internal pointers, e.g.:
```cpp
class Ew { class Ew {
char buffer[1024]; char buffer[1024];
char * pointerInsideBuffer; char * pointerInsideBuffer;
...@@ -156,7 +156,7 @@ Only a tiny minority of objects are genuinely non-relocatable: ...@@ -156,7 +156,7 @@ Only a tiny minority of objects are genuinely non-relocatable:
Ew() : pointerInsideBuffer(buffer) {} Ew() : pointerInsideBuffer(buffer) {}
... ...
} }
```
* Objects that need to update "observers" that store pointers to them. * Objects that need to update "observers" that store pointers to them.
The first class of designs can always be redone at small or no The first class of designs can always be redone at small or no
...@@ -180,12 +180,12 @@ trait `folly::IsRelocatable` defined in `"folly/Traits.h"`. By default, ...@@ -180,12 +180,12 @@ trait `folly::IsRelocatable` defined in `"folly/Traits.h"`. By default,
`folly::IsRelocatable::value` conservatively yields false. If `folly::IsRelocatable::value` conservatively yields false. If
you know that your type `Widget` is in fact relocatable, go right you know that your type `Widget` is in fact relocatable, go right
after `Widget`'s definition and write this: after `Widget`'s definition and write this:
```cpp
// at global namespace level // at global namespace level
namespace folly { namespace folly {
struct IsRelocatable<Widget> : boost::true_type {}; struct IsRelocatable<Widget> : boost::true_type {};
} }
```
If you don't do this, `fbvector<Widget>` will fail to compile If you don't do this, `fbvector<Widget>` will fail to compile
with a `static_assert`. with a `static_assert`.
......
...@@ -10,7 +10,7 @@ The primary difference from std::future is that you can attach callbacks to Futu ...@@ -10,7 +10,7 @@ The primary difference from std::future is that you can attach callbacks to Futu
# Brief Synopsis # Brief Synopsis
``` ```cpp
#include <folly/futures/Future.h> #include <folly/futures/Future.h>
#include <folly/executors/ThreadedExecutor.h> #include <folly/executors/ThreadedExecutor.h>
using namespace folly; using namespace folly;
...@@ -39,13 +39,11 @@ void foo(int x) { ...@@ -39,13 +39,11 @@ void foo(int x) {
This would print: This would print:
```
making Promise making Promise
Future chain made Future chain made
fulfilling Promise fulfilling Promise
foo(42) foo(42)
Promise fulfilled Promise fulfilled
```
## Blog Post ## Blog Post
...@@ -57,7 +55,7 @@ This brief guide covers the basics. For a more in-depth coverage skip to the app ...@@ -57,7 +55,7 @@ This brief guide covers the basics. For a more in-depth coverage skip to the app
Let's begin with an example using an imaginary simplified Memcache client interface: Let's begin with an example using an imaginary simplified Memcache client interface:
``` ```cpp
using std::string; using std::string;
class MemcacheClient { class MemcacheClient {
public: public:
...@@ -83,7 +81,7 @@ This API is synchronous, i.e. when you call `get()` you have to wait for the res ...@@ -83,7 +81,7 @@ This API is synchronous, i.e. when you call `get()` you have to wait for the res
Now, consider this traditional asynchronous signature for the same operation: Now, consider this traditional asynchronous signature for the same operation:
``` ```cpp
int async_get(string key, std::function<void(GetReply)> callback); int async_get(string key, std::function<void(GetReply)> callback);
``` ```
...@@ -91,27 +89,27 @@ When you call `async_get()`, your asynchronous operation begins and when it fini ...@@ -91,27 +89,27 @@ When you call `async_get()`, your asynchronous operation begins and when it fini
The Future-based API looks like this: The Future-based API looks like this:
``` ```cpp
SemiFuture<GetReply> future_get(string key); SemiFuture<GetReply> future_get(string key);
``` ```
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.: 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.:
``` ```cpp
fut.isReady() == false fut.isReady() == false
fut.value() // will throw an exception because the Future is not ready fut.value() // will throw an exception because the Future is not ready
``` ```
At some point in the future, the `Future` will have been fulfilled, and we can access its value. At some point in the future, the `Future` will have been fulfilled, and we can access its value.
``` ```cpp
fut.isReady() == true fut.isReady() == true
GetReply& reply = fut.value(); GetReply& reply = fut.value();
``` ```
Futures support exceptions. If the asynchronous producer fails with an exception, your Future may represent an exception instead of a value. In that case: Futures support exceptions. If the asynchronous producer fails with an exception, your Future may represent an exception instead of a value. In that case:
``` ```cpp
fut.isReady() == true fut.isReady() == true
fut.value() // will rethrow the exception fut.value() // will rethrow the exception
``` ```
...@@ -122,7 +120,7 @@ So far we have described a way to initiate an asynchronous operation via an API ...@@ -122,7 +120,7 @@ So far we have described a way to initiate an asynchronous operation via an API
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. 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.
``` ```cpp
MemcacheClient mc; MemcacheClient mc;
vector<SemiFuture<GetReply>> futs; vector<SemiFuture<GetReply>> futs;
...@@ -144,7 +142,7 @@ Second, we can associate a Future with an executor. An executor specifies where ...@@ -144,7 +142,7 @@ Second, we can associate a Future with an executor. An executor specifies where
For example: For example:
``` ```cpp
folly::ThreadedExecutor executor; folly::ThreadedExecutor executor;
SemiFuture<GetReply> semiFut = mc.future_get("foo"); SemiFuture<GetReply> semiFut = mc.future_get("foo");
Future<GetReply> fut1 = std::move(semiFut).via(&executor); Future<GetReply> fut1 = std::move(semiFut).via(&executor);
...@@ -152,7 +150,7 @@ Future<GetReply> fut1 = std::move(semiFut).via(&executor); ...@@ -152,7 +150,7 @@ Future<GetReply> fut1 = std::move(semiFut).via(&executor);
Once an executor is attached, a `Future` allows continuations to be attached and chained together monadically. An example will clarify: Once an executor is attached, a `Future` allows continuations to be attached and chained together monadically. An example will clarify:
``` ```cpp
SemiFuture<GetReply> semiFut = mc.future_get("foo"); SemiFuture<GetReply> semiFut = mc.future_get("foo");
Future<GetReply> fut1 = std::move(semiFut).via(&executor); Future<GetReply> fut1 = std::move(semiFut).via(&executor);
...@@ -185,7 +183,7 @@ Up to this point we have skirted around the matter of waiting for Futures. You m ...@@ -185,7 +183,7 @@ Up to this point we have skirted around the matter of waiting for Futures. You m
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. 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.
``` ```cpp
// Thread A // Thread A
Promise<Unit> p; Promise<Unit> p;
auto f = p.getFuture(); auto f = p.getFuture();
...@@ -201,7 +199,7 @@ This is legal and technically threadsafe. However, it is important to realize th ...@@ -201,7 +199,7 @@ This is legal and technically threadsafe. However, it is important to realize th
For safety, `.via` should be preferred. We can chain `.via` operations to give very strong control over where callbacks run: For safety, `.via` should be preferred. We can chain `.via` operations to give very strong control over where callbacks run:
``` ```cpp
std::move(aFuture) std::move(aFuture)
.thenValue(x) .thenValue(x)
.via(e1).thenValue(y1).thenValue(y2) .via(e1).thenValue(y1).thenValue(y2)
...@@ -210,7 +208,7 @@ std::move(aFuture) ...@@ -210,7 +208,7 @@ std::move(aFuture)
`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. Another way to express this is using an overload of `then` that takes an Executor: `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. Another way to express this is using an overload of `then` that takes an Executor:
``` ```cpp
std::move(aFuture) std::move(aFuture)
.thenValue(x) .thenValue(x)
.thenValue(e1, y1, y2) .thenValue(e1, y1, y2)
...@@ -221,7 +219,7 @@ Either way, there is no ambiguity about which executor will run `y1`, `y2`, or ` ...@@ -221,7 +219,7 @@ Either way, there is no ambiguity about which executor will run `y1`, `y2`, or `
You can still have a race after `via` if you break it into multiple statements, e.g. in this counterexample: You can still have a race after `via` if you break it into multiple statements, e.g. in this counterexample:
``` ```cpp
f2 = std::move(f).via(e1).thenValue(y1).thenValue(y2); // nothing racy here f2 = std::move(f).via(e1).thenValue(y1).thenValue(y2); // nothing racy here
std::move(f2).thenValue(y3); // racy std::move(f2).thenValue(y3); // racy
``` ```
...@@ -230,7 +228,7 @@ std::move(f2).thenValue(y3); // racy ...@@ -230,7 +228,7 @@ std::move(f2).thenValue(y3); // racy
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: 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:
``` ```cpp
Promise<int> p; Promise<int> p;
SemiFuture<int> f = p.getSemiFuture(); SemiFuture<int> f = p.getSemiFuture();
...@@ -244,7 +242,7 @@ f.value() == 42 ...@@ -244,7 +242,7 @@ f.value() == 42
and an exception example: and an exception example:
``` ```cpp
Promise<int> p; Promise<int> p;
SemiFuture<int> f = p.getSemiFuture(); SemiFuture<int> f = p.getSemiFuture();
...@@ -258,7 +256,7 @@ f.value() // throws the exception ...@@ -258,7 +256,7 @@ f.value() // throws the exception
It's good practice to use setWith which takes a function and automatically captures exceptions, e.g. It's good practice to use setWith which takes a function and automatically captures exceptions, e.g.
``` ```cpp
Promise<int> p; Promise<int> p;
p.setWith([]{ p.setWith([]{
try { try {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment