Commit c067ea95 authored by Dominik Charousset's avatar Dominik Charousset

Change license to BSD and adopt new coding style

parent adf89af5
---
AccessModifierOffset: -1
AlignEscapedNewlinesLeft: false
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackParameters: true
BreakBeforeBinaryOperators: false
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: false
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
IndentCaseLabels: true
IndentFunctionDeclarationAfterType: false
IndentWidth: 2
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PointerBindsToType: true
SpaceBeforeAssignmentOperators: true
SpaceAfterControlStatementKeyword: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
Standard: Cpp11
UseTab: Never
BreakConstructorInitializersBeforeComma: false
...
This files specifies the coding style for CAF source files.
The style is based on the
[Google C++ Style Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml).
# Example for the Impatient
#### `libcaf_example/caf/example/my_class.hpp`
```cpp
#ifndef CAF_EXAMPLE_MY_CLASS_HPP
#define CAF_EXAMPLE_MY_CLASS_HPP
#include <string>
namespace caf {
namespace example {
class my_class {
public:
/**
* @brief Constructs `my_class`.
*
* The class is only being used as style guide example.
*/
my_class();
/**
* @brief Destructs `my_class`.
*/
~my_class();
/**
* @brief Gets the name of this instance.
* Some more brief description.
*
* Long description goes here.
*/
inline const std::string& name() const {
return m_name;
}
/**
* @brief Sets the name of this instance.
*/
inline void name(std::string new_name) {
m_name = std::move(new_name);
}
/**
* @brief Prints the name to `STDIN`.
*/
void print_name() const;
/**
* @brief Does something. Maybe.
*/
void do_something();
private:
std::string m_name;
};
} // namespace example
} // namespace caf
#endif // CAF_EXAMPLE_MY_CLASS_HPP
```
#### `libcaf_example/src/my_class.cpp`
```cpp
#include "caf/example/my_class.hpp"
#include <iostream>
namespace caf {
namespace example {
namespace {
constexpr const char default_name[] = "my object";
} // namespace <anonymous>
my_class::my_class() : m_name(default_name) {
// nop
}
my_class::~my_class() {
// nop
}
void my_class::print_name() const {
std::cout << name() << std::endl;
}
void my_class::do_something() {
if (name() == default_name) {
std::cout << "You didn't gave me a proper name, so I "
<< "refuse to do something."
<< std::endl;
} else {
std::cout << "You gave me the name " << name()
<< "... Do you really think I'm willing to do something "
"for you after insulting me like that?"
<< std::endl;
}
}
} // namespace example
} // namespace caf
```
# General rules
- Use 2 spaces per indentation level.
- The maximum number of characters per line is 80.
- Never use tabs.
- Vertical whitespaces separate functions and are not used inside functions:
use comments to document logical blocks.
- Header filenames end in `.hpp`, implementation files end in `.cpp`.
- Member variables use the prefix `m_`.
- Thread-local variables use the prefix `t_`.
- Never declare more than one variable per line.
- `*` and `&` bind to the *type*.
- Class names, constants, and function names are all-lowercase with underscores.
- Template parameter names use CamelCase.
- Namespaces do not increase the indentation level.
- Access modifiers, e.g. `public`, are indented one space.
- Use the order `public`, `protected`, and then `private`.
- Always use `auto` to declare a variable unless you cannot initialize it
immediately or if you actually want a type conversion. In the latter case,
provide a comment why this conversion is necessary.
- Never use unwrapped, manual resource management such as `new` and `delete`.
- Do not use `typedef`. The syntax provided by `using` is much cleaner.
- Use `typename` only when referring to dependent names.
- Keywords are always followed by a whitespace: `if (...)`, `template <...>`,
`while (...)`, etc.
- Always use `{}` for bodies of control structures such as `if` or `while`,
even for bodies consiting only of a single statement.
- Opening braces belong to the same line:
```cpp
if (my_condition) {
my_fun();
} else {
my_other_fun();
}
```
- Use standard order for readability: C standard libraries, C++ standard
libraries, other libraries, (your) CAF headers:
```cpp
#include <sys/types.h>
#include <vector>
#include "some/other/library.hpp"
#include "caf/example/myclass.hpp"
```
# Headers
- Each `.cpp` file has an associated `.hpp` file.
Exceptions to this rule are unit tests and `main.cpp` files.
- Each class has its own pair of header and implementation
files and the relative path is derived from its full name.
For example, the header file for `caf::example::my_class` of `libcaf_example`
is located at `libcaf_example/caf/example/my_class.hpp`.
Source files simply belong to the `src` folder of the component, e.g.,
`libcaf_example/src/my_class.cpp`.
- All header files should use `#define` guards to prevent multiple inclusion.
The symbol name is `<RELATIVE>_<PATH>_<TO>_<FILE>_HPP`.
- Do not `#include` when a forward declaration suffices.
- Each library component must provide a `fwd.hpp` header providing forward
declartations for all types used in the user API.
- Each library component must provide an `all.hpp` header including
all headers for the user API and the main page for the documentation.
- Use `inline` for small functions (rule of thumb: 10 lines or less).
## Template Metaprogramming
Despite its power, template metaprogramming came to the language pretty
much by accident. Templates were never meant to be used for compile-time
algorithms and type transformations. This is why C++ punishes metaprogramming
with an insane amount of syntax noise. In CAF, we make excessive use of
templates. To keep the code readable despite all the syntax noise, we have some
extra rules for formatting metaprogramming code.
- Brake `using name = ...` statements always directly after `=` if it
does not fit in one line.
- Consider the *semantics* of a metaprogramming function. For example,
`std::conditional` is an if-then-else construct. Hence, place the if-clause
on its own line and do the same for the two cases.
- Use one level of indentation per "open" template and place the closing `>`,
`>::type` or `>::value` on its own line. For example:
```cpp
using optional_result_type =
typename std::conditional<
std::is_same<result_type, void>::value,
bool,
optional<result_type>
>::type;
// think of it as the following (not valid C++):
auto optional_result_type =
conditional {
if (result_type == void)
then (bool)
else (optional<result_type>)
};
```
- Note that this is not necessary when simply defining a type alias.
When dealing with "ordinary" templates, indenting based on the position of
the opening `<` is ok too, e.g.:
```cpp
using response_handle_type = response_handle<Subtype, message,
ResponseHandleTag>;
```
# Miscellaneous
## Rvalue references
- Use rvalue references whenever it makes sense.
- Write move constructors and assignment operators if possible.
## Casting
- Never use C-style casts.
## Preprocessor Macros
- Use macros if and only if you can't get the same result by using inline
functions or proper constants.
- Macro names use the form `CAF_<COMPONENT>_<NAME>`.
Boost Software License - Version 1.0 - August 17th, 2003 Copyright (c) 2011-2014, Dominik Charousset
All rights reserved.
Permission is hereby granted, free of charge, to any person or organization Redistribution and use in source and binary forms, with or without
obtaining a copy of the software and accompanying documentation covered by modification, are permitted provided that the following conditions are met:
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including * Redistributions of source code must retain the above copyright
the above license grant, this restriction and the following disclaimer, notice, this list of conditions and the following disclaimer.
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * Redistributions in binary form must reproduce the above copyright
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, notice, this list of conditions and the following disclaimer in the
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT documentation and/or other materials provided with the distribution.
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, * Neither the name of the copyright holder nor the names of its
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER contributors may be used to endorse or promote products derived from
DEALINGS IN THE SOFTWARE. this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
/******************************************************************************\ /******************************************************************************\
* This example illustrates how to use aout. * * This example illustrates how to use aout. *
\******************************************************************************/ \ ******************************************************************************/
#include <chrono> #include <chrono>
#include <cstdlib> #include <cstdlib>
...@@ -11,22 +11,22 @@ using namespace caf; ...@@ -11,22 +11,22 @@ using namespace caf;
using std::endl; using std::endl;
int main() { int main() {
std::srand(static_cast<unsigned>(std::time(0))); std::srand(static_cast<unsigned>(std::time(0)));
for (int i = 1; i <= 50; ++i) { for (int i = 1; i <= 50; ++i) {
spawn<blocking_api>([i](blocking_actor* self) { spawn<blocking_api>([i](blocking_actor* self) {
aout(self) << "Hi there! This is actor nr. " aout(self) << "Hi there! This is actor nr. "
<< i << "!" << endl; << i << "!" << endl;
std::chrono::milliseconds tout{std::rand() % 1000}; std::chrono::milliseconds tout{std::rand() % 1000};
self->delayed_send(self, tout, atom("done")); self->delayed_send(self, tout, atom("done"));
self->receive(others() >> [i, self] { self->receive(others() >> [i, self] {
aout(self) << "Actor nr. " aout(self) << "Actor nr. "
<< i << " says goodbye!" << endl; << i << " says goodbye!" << endl;
}); });
}); });
} }
// wait until all other actors we've spawned are done // wait until all other actors we've spawned are done
await_all_actors_done(); await_all_actors_done();
// done // done
shutdown(); shutdown();
return 0; return 0;
} }
This diff is collapsed.
#include <string> #include <string>
#include <iostream> #include <iostream>
#include "caf/all.hpp" #include "caf/all.hpp"
using namespace std; using namespace std;
using namespace caf; using namespace caf;
behavior mirror(event_based_actor* self) { behavior mirror(event_based_actor* self) {
// return the (initial) actor behavior // return the (initial) actor behavior
return { return {
// a handler for messages containing a single string // a handler for messages containing a single string
// that replies with a string // that replies with a string
[=](const string& what) -> string { [=](const string& what) -> string {
// prints "Hello World!" via aout (thread-safe cout wrapper) // prints "Hello World!" via aout (thread-safe cout wrapper)
aout(self) << what << endl; aout(self) << what << endl;
// terminates this actor ('become' otherwise loops forever) // terminates this actor ('become' otherwise loops forever)
self->quit(); self->quit();
// reply "!dlroW olleH" // reply "!dlroW olleH"
return string(what.rbegin(), what.rend()); return string(what.rbegin(), what.rend());
} }
}; };
} }
void hello_world(event_based_actor* self, const actor& buddy) { void hello_world(event_based_actor* self, const actor& buddy) {
// send "Hello World!" to our buddy ... // send "Hello World!" to our buddy ...
self->sync_send(buddy, "Hello World!").then( self->sync_send(buddy, "Hello World!").then(
// ... wait for a response ... // ... wait for a response ...
[=](const string& what) { [=](const string& what) {
// ... and print it // ... and print it
aout(self) << what << endl; aout(self) << what << endl;
} }
); );
} }
int main() { int main() {
// create a new actor that calls 'mirror()' // create a new actor that calls 'mirror()'
auto mirror_actor = spawn(mirror); auto mirror_actor = spawn(mirror);
// create another actor that calls 'hello_world(mirror_actor)'; // create another actor that calls 'hello_world(mirror_actor)';
spawn(hello_world, mirror_actor); spawn(hello_world, mirror_actor);
// wait until all other actors we have spawned are done // wait until all other actors we have spawned are done
await_all_actors_done(); await_all_actors_done();
// run cleanup code before exiting main // run cleanup code before exiting main
shutdown(); shutdown();
} }
/******************************************************************************\ /******************************************************************************\
* This example is a very basic, non-interactive math service implemented * * This example is a very basic, non-interactive math service implemented *
* for both the blocking and the event-based API. * * for both the blocking and the event-based API. *
\******************************************************************************/ \ ******************************************************************************/
#include <tuple> #include <tuple>
#include <cassert> #include <cassert>
...@@ -15,68 +15,68 @@ using namespace caf; ...@@ -15,68 +15,68 @@ using namespace caf;
// implementation using the blocking API // implementation using the blocking API
void blocking_math_fun(blocking_actor* self) { void blocking_math_fun(blocking_actor* self) {
bool done = false; bool done = false;
self->do_receive ( self->do_receive (
// "arg_match" matches the parameter types of given lambda expression // "arg_match" matches the parameter types of given lambda expression
// thus, it's equal to // thus, it's equal to
// - on<atom("plus"), int, int>() // - on<atom("plus"), int, int>()
// - on(atom("plus"), val<int>, val<int>) // - on(atom("plus"), val<int>, val<int>)
on(atom("plus"), arg_match) >> [](int a, int b) { on(atom("plus"), arg_match) >> [](int a, int b) {
return std::make_tuple(atom("result"), a + b); return std::make_tuple(atom("result"), a + b);
}, },
on(atom("minus"), arg_match) >> [](int a, int b) { on(atom("minus"), arg_match) >> [](int a, int b) {
return std::make_tuple(atom("result"), a - b); return std::make_tuple(atom("result"), a - b);
}, },
on(atom("quit")) >> [&]() { on(atom("quit")) >> [&]() {
// note: this actor uses the blocking API, hence self->quit() // note: this actor uses the blocking API, hence self->quit()
// would force stack unwinding by throwing an exception // would force stack unwinding by throwing an exception
done = true; done = true;
} }
).until(done); ).until(done);
} }
void calculator(event_based_actor* self) { void calculator(event_based_actor* self) {
// execute this behavior until actor terminates // execute this behavior until actor terminates
self->become ( self->become (
on(atom("plus"), arg_match) >> [](int a, int b) { on(atom("plus"), arg_match) >> [](int a, int b) {
return std::make_tuple(atom("result"), a + b); return std::make_tuple(atom("result"), a + b);
}, },
on(atom("minus"), arg_match) >> [](int a, int b) { on(atom("minus"), arg_match) >> [](int a, int b) {
return std::make_tuple(atom("result"), a - b); return std::make_tuple(atom("result"), a - b);
}, },
on(atom("quit")) >> [=] { on(atom("quit")) >> [=] {
// terminate actor with normal exit reason // terminate actor with normal exit reason
self->quit(); self->quit();
} }
); );
} }
void tester(event_based_actor* self, const actor& testee) { void tester(event_based_actor* self, const actor& testee) {
self->link_to(testee); self->link_to(testee);
// will be invoked if we receive an unexpected response message // will be invoked if we receive an unexpected response message
self->on_sync_failure([=] { self->on_sync_failure([=] {
aout(self) << "AUT (actor under test) failed" << endl; aout(self) << "AUT (actor under test) failed" << endl;
self->quit(exit_reason::user_shutdown); self->quit(exit_reason::user_shutdown);
}); });
// first test: 2 + 1 = 3 // first test: 2 + 1 = 3
self->sync_send(testee, atom("plus"), 2, 1).then( self->sync_send(testee, atom("plus"), 2, 1).then(
on(atom("result"), 3) >> [=] { on(atom("result"), 3) >> [=] {
// second test: 2 - 1 = 1 // second test: 2 - 1 = 1
self->sync_send(testee, atom("minus"), 2, 1).then( self->sync_send(testee, atom("minus"), 2, 1).then(
on(atom("result"), 1) >> [=] { on(atom("result"), 1) >> [=] {
// both tests succeeded // both tests succeeded
aout(self) << "AUT (actor under test) seems to be ok" aout(self) << "AUT (actor under test) seems to be ok"
<< endl; << endl;
self->send(testee, atom("quit")); self->send(testee, atom("quit"));
}
);
} }
); );
}
);
} }
int main() { int main() {
spawn(tester, spawn(calculator)); spawn(tester, spawn(calculator));
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
/******************************************************************************\ /******************************************************************************\
* This example illustrates how to do time-triggered loops in libcaf. * * This example illustrates how to do time-triggered loops in libcaf. *
\******************************************************************************/ \ ******************************************************************************/
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
...@@ -15,65 +15,66 @@ using namespace caf; ...@@ -15,65 +15,66 @@ using namespace caf;
// ASCII art figures // ASCII art figures
constexpr const char* figures[] = { constexpr const char* figures[] = {
"<(^.^<)", "<(^.^<)",
"<(^.^)>", "<(^.^)>",
"(>^.^)>" "(>^.^)>"
}; };
struct animation_step { size_t figure_idx; size_t offset; }; struct animation_step { size_t figure_idx; size_t offset; };
// array of {figure, offset} pairs // array of {figure, offset} pairs
constexpr animation_step animation_steps[] = { constexpr animation_step animation_steps[] = {
{1, 7}, {0, 7}, {0, 6}, {0, 5}, {1, 5}, {2, 5}, {2, 6}, {1, 7}, {0, 7}, {0, 6}, {0, 5}, {1, 5}, {2, 5}, {2, 6},
{2, 7}, {2, 8}, {2, 9}, {2, 10}, {1, 10}, {0, 10}, {0, 9}, {2, 7}, {2, 8}, {2, 9}, {2, 10}, {1, 10}, {0, 10}, {0, 9},
{1, 9}, {2, 10}, {2, 11}, {2, 12}, {2, 13}, {1, 13}, {0, 13}, {1, 9}, {2, 10}, {2, 11}, {2, 12}, {2, 13}, {1, 13}, {0, 13},
{0, 12}, {0, 11}, {0, 10}, {0, 9}, {0, 8}, {0, 7}, {1, 7} {0, 12}, {0, 11}, {0, 10}, {0, 9}, {0, 8}, {0, 7}, {1, 7}
}; };
template<typename T, size_t S> template <class T, size_t S>
constexpr size_t array_size(const T (&) [S]) { constexpr size_t array_size(const T (&) [S]) {
return S; return S;
} }
constexpr size_t animation_width = 20; constexpr size_t animation_width = 20;
// "draws" an animation step by printing "{offset_whitespaces}{figure}{padding}" // "draws" an animation step by printing "{offset_whitespaces}{figure}{padding}"
void draw_kirby(const animation_step& animation) { void draw_kirby(const animation_step& animation) {
cout.width(animation_width); cout.width(animation_width);
// override last figure // override last figure
cout << '\r'; cout << '\r';
// print offset // print offset
std::fill_n(std::ostream_iterator<char>{cout}, animation.offset, ' '); std::fill_n(std::ostream_iterator<char>{cout}, animation.offset, ' ');
// print figure // print figure
cout << figures[animation.figure_idx]; cout << figures[animation.figure_idx];
// print padding // print padding
cout.fill(' '); cout.fill(' ');
// make sure figure is printed // make sure figure is printed
cout.flush(); cout.flush();
} }
// uses a message-based loop to iterate over all animation steps // uses a message-based loop to iterate over all animation steps
void dancing_kirby(event_based_actor* self) { void dancing_kirby(event_based_actor* self) {
// let's get it started // let's get it started
self->send(self, atom("Step"), size_t{0}); self->send(self, atom("Step"), size_t{0});
self->become ( self->become (
on(atom("Step"), array_size(animation_steps)) >> [=] { on(atom("Step"), array_size(animation_steps)) >> [=] {
// we've printed all animation steps (done) // we've printed all animation steps (done)
cout << endl; cout << endl;
self->quit(); self->quit();
}, },
on(atom("Step"), arg_match) >> [=](size_t step) { on(atom("Step"), arg_match) >> [=](size_t step) {
// print given step // print given step
draw_kirby(animation_steps[step]); draw_kirby(animation_steps[step]);
// animate next step in 150ms // animate next step in 150ms
self->delayed_send(self, std::chrono::milliseconds(150), atom("Step"), step + 1); self->delayed_send(self, std::chrono::milliseconds(150),
} atom("Step"), step + 1);
); }
);
} }
int main() { int main() {
spawn(dancing_kirby); spawn(dancing_kirby);
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
/******************************************************************************\ /******************************************************************************\
* This example is an implementation of the classical Dining Philosophers * * This example is an implementation of the classical Dining Philosophers *
* exercise using only libcaf's event-based actor implementation. * * exercise using only libcaf's event-based actor implementation. *
\******************************************************************************/ \ ******************************************************************************/
#include <map> #include <map>
#include <vector> #include <vector>
...@@ -20,24 +20,24 @@ namespace { ...@@ -20,24 +20,24 @@ namespace {
// either taken by a philosopher or available // either taken by a philosopher or available
void chopstick(event_based_actor* self) { void chopstick(event_based_actor* self) {
self->become( self->become(
on(atom("take"), arg_match) >> [=](const actor& philos) { on(atom("take"), arg_match) >> [=](const actor& philos) {
// tell philosopher it took this chopstick // tell philosopher it took this chopstick
self->send(philos, atom("taken"), self); self->send(philos, atom("taken"), self);
// await 'put' message and reject other 'take' messages // await 'put' message and reject other 'take' messages
self->become( self->become(
// allows us to return to the previous behavior // allows us to return to the previous behavior
keep_behavior, keep_behavior,
on(atom("take"), arg_match) >> [=](const actor& other) { on(atom("take"), arg_match) >> [=](const actor& other) {
self->send(other, atom("busy"), self); self->send(other, atom("busy"), self);
}, },
on(atom("put"), philos) >> [=] { on(atom("put"), philos) >> [=] {
// return to previous behaivor, i.e., await next 'take' // return to previous behaivor, i.e., await next 'take'
self->unbecome(); self->unbecome();
}
);
} }
); );
}
);
} }
/* See: http://www.dalnefre.com/wp/2010/08/dining-philosophers-in-humus/ /* See: http://www.dalnefre.com/wp/2010/08/dining-philosophers-in-humus/
...@@ -73,127 +73,122 @@ void chopstick(event_based_actor* self) { ...@@ -73,127 +73,122 @@ void chopstick(event_based_actor* self) {
* [ X = right => Y = left ] * [ X = right => Y = left ]
*/ */
struct philosopher : event_based_actor { class philosopher : public event_based_actor {
public:
std::string name; // the name of this philosopher philosopher(const std::string& n, const actor& l, const actor& r)
actor left; // left chopstick : name(n), left(l), right(r) {
actor right; // right chopstick // a philosopher that receives {eat} stops thinking and becomes hungry
thinking = (
// note: we have to define all behaviors in the constructor because on(atom("eat")) >> [=] {
// non-static member initialization are not (yet) implemented in GCC become(hungry);
behavior thinking; send(left, atom("take"), this);
behavior hungry; send(right, atom("take"), this);
behavior denied; }
behavior eating; );
// wait for the first answer of a chopstick
// wait for second chopstick hungry = (
behavior waiting_for(const actor& what) { on(atom("taken"), left) >> [=] {
return ( become(waiting_for(right));
on(atom("taken"), what) >> [=] { },
aout(this) << name on(atom("taken"), right) >> [=] {
<< " has picked up chopsticks with IDs " become(waiting_for(left));
<< left->id() },
<< " and " on<atom("busy"), actor>() >> [=] {
<< right->id() become(denied);
<< " and starts to eat\n"; }
// eat some time );
delayed_send(this, seconds(5), atom("think")); // philosopher was not able to obtain the first chopstick
become(eating); denied = (
}, on(atom("taken"), arg_match) >> [=](const actor& ptr) {
on(atom("busy"), what) >> [=] { send(ptr, atom("put"), this);
send((what == left) ? right : left, atom("put"), this); send(this, atom("eat"));
send(this, atom("eat")); become(thinking);
become(thinking); },
} on<atom("busy"), actor>() >> [=] {
); send(this, atom("eat"));
} become(thinking);
}
philosopher(const std::string& n, const actor& l, const actor& r) );
: name(n), left(l), right(r) { // philosopher obtained both chopstick and eats (for five seconds)
// a philosopher that receives {eat} stops thinking and becomes hungry eating = (
thinking = ( on(atom("think")) >> [=] {
on(atom("eat")) >> [=] { send(left, atom("put"), this);
become(hungry); send(right, atom("put"), this);
send(left, atom("take"), this); delayed_send(this, seconds(5), atom("eat"));
send(right, atom("take"), this); aout(this) << name << " puts down his chopsticks and starts to think\n";
} become(thinking);
); }
// wait for the first answer of a chopstick );
hungry = ( }
on(atom("taken"), left) >> [=] {
become(waiting_for(right)); protected:
}, behavior make_behavior() override {
on(atom("taken"), right) >> [=] { // start thinking
become(waiting_for(left)); send(this, atom("think"));
}, // philosophers start to think after receiving {think}
on<atom("busy"), actor>() >> [=] { return (
become(denied); on(atom("think")) >> [=] {
} aout(this) << name << " starts to think\n";
); delayed_send(this, seconds(5), atom("eat"));
// philosopher was not able to obtain the first chopstick become(thinking);
denied = ( }
on(atom("taken"), arg_match) >> [=](const actor& ptr) { );
send(ptr, atom("put"), this); }
send(this, atom("eat"));
become(thinking); private:
}, // wait for second chopstick
on<atom("busy"), actor>() >> [=] { behavior waiting_for(const actor& what) {
send(this, atom("eat")); return {
become(thinking); on(atom("taken"), what) >> [=] {
} aout(this) << name
); << " has picked up chopsticks with IDs "
// philosopher obtained both chopstick and eats (for five seconds) << left->id() << " and " << right->id()
eating = ( << " and starts to eat\n";
on(atom("think")) >> [=] { // eat some time
send(left, atom("put"), this); delayed_send(this, seconds(5), atom("think"));
send(right, atom("put"), this); become(eating);
delayed_send(this, seconds(5), atom("eat")); },
aout(this) << name on(atom("busy"), what) >> [=] {
<< " puts down his chopsticks and starts to think\n"; send((what == left) ? right : left, atom("put"), this);
become(thinking); send(this, atom("eat"));
} become(thinking);
); }
} };
}
behavior make_behavior() override {
// start thinking std::string name; // the name of this philosopher
send(this, atom("think")); actor left; // left chopstick
// philosophers start to think after receiving {think} actor right; // right chopstick
return ( behavior thinking;
on(atom("think")) >> [=] { behavior hungry; // tries to take chopsticks
aout(this) << name << " starts to think\n"; behavior denied; // could not get chopsticks
delayed_send(this, seconds(5), atom("eat")); behavior eating; // wait for some time, then go thinking again
become(thinking);
}
);
}
}; };
void dining_philosophers() { void dining_philosophers() {
scoped_actor self; scoped_actor self;
// create five chopsticks // create five chopsticks
aout(self) << "chopstick ids are:"; aout(self) << "chopstick ids are:";
std::vector<actor> chopsticks; std::vector<actor> chopsticks;
for (size_t i = 0; i < 5; ++i) { for (size_t i = 0; i < 5; ++i) {
chopsticks.push_back(spawn(chopstick)); chopsticks.push_back(spawn(chopstick));
aout(self) << " " << chopsticks.back()->id(); aout(self) << " " << chopsticks.back()->id();
} }
aout(self) << endl; aout(self) << endl;
// spawn five philosophers // spawn five philosophers
std::vector<std::string> names { "Plato", "Hume", "Kant", std::vector<std::string> names {"Plato", "Hume", "Kant",
"Nietzsche", "Descartes" }; "Nietzsche", "Descartes"};
for (size_t i = 0; i < 5; ++i) { for (size_t i = 0; i < 5; ++i) {
spawn<philosopher>(names[i], chopsticks[i], chopsticks[(i+1)%5]); spawn<philosopher>(names[i], chopsticks[i], chopsticks[(i + 1) % 5]);
} }
} }
} // namespace <anonymous> } // namespace <anonymous>
int main(int, char**) { int main(int, char**) {
dining_philosophers(); dining_philosophers();
// real philosophers are never done // real philosophers are never done
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
/******************************************************************************\ /******************************************************************************\
* This example is a very basic, non-interactive math service implemented * * This example is a very basic, non-interactive math service implemented *
* using typed actors. * * using typed actors. *
\******************************************************************************/ \ ******************************************************************************/
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
...@@ -16,82 +16,80 @@ struct shutdown_request { }; ...@@ -16,82 +16,80 @@ struct shutdown_request { };
struct plus_request { int a; int b; }; struct plus_request { int a; int b; };
struct minus_request { int a; int b; }; struct minus_request { int a; int b; };
using calculator_type = typed_actor< using calculator_type = typed_actor<replies_to<plus_request>::with<int>,
replies_to<plus_request>::with<int>, replies_to<minus_request>::with<int>,
replies_to<minus_request>::with<int>, replies_to<shutdown_request>::with<void>>;
replies_to<shutdown_request>::with<void>
>;
calculator_type::behavior_type typed_calculator(calculator_type::pointer self) { calculator_type::behavior_type typed_calculator(calculator_type::pointer self) {
return { return {
[](const plus_request& pr) { [](const plus_request& pr) {
return pr.a + pr.b; return pr.a + pr.b;
}, },
[](const minus_request& pr) { [](const minus_request& pr) {
return pr.a - pr.b; return pr.a - pr.b;
}, },
[=](const shutdown_request&) { [=](const shutdown_request&) {
self->quit(); self->quit();
} }
}; };
} }
class typed_calculator_class : public calculator_type::base { class typed_calculator_class : public calculator_type::base {
protected: protected:
behavior_type make_behavior() override { behavior_type make_behavior() override {
return { return {
[](const plus_request& pr) { [](const plus_request& pr) {
return pr.a + pr.b; return pr.a + pr.b;
}, },
[](const minus_request& pr) { [](const minus_request& pr) {
return pr.a - pr.b; return pr.a - pr.b;
}, },
[=](const shutdown_request&) { [=](const shutdown_request&) {
quit(); quit();
} }
}; };
} }
}; };
void tester(event_based_actor* self, const calculator_type& testee) { void tester(event_based_actor* self, const calculator_type& testee) {
self->link_to(testee); self->link_to(testee);
// will be invoked if we receive an unexpected response message // will be invoked if we receive an unexpected response message
self->on_sync_failure([=] { self->on_sync_failure([=] {
aout(self) << "AUT (actor under test) failed" << endl; aout(self) << "AUT (actor under test) failed" << endl;
self->quit(exit_reason::user_shutdown); self->quit(exit_reason::user_shutdown);
}); });
// first test: 2 + 1 = 3 // first test: 2 + 1 = 3
self->sync_send(testee, plus_request{2, 1}).then( self->sync_send(testee, plus_request{2, 1}).then(
[=](int r1) { [=](int r1) {
assert(r1 == 3); assert(r1 == 3);
// second test: 2 - 1 = 1 // second test: 2 - 1 = 1
self->sync_send(testee, minus_request{2, 1}).then( self->sync_send(testee, minus_request{2, 1}).then(
[=](int r2) { [=](int r2) {
assert(r2 == 1); assert(r2 == 1);
// both tests succeeded // both tests succeeded
aout(self) << "AUT (actor under test) seems to be ok" aout(self) << "AUT (actor under test) seems to be ok"
<< endl; << endl;
self->send(testee, shutdown_request{}); self->send(testee, shutdown_request{});
}
);
} }
); );
}
);
} }
} // namespace <anonymous> } // namespace <anonymous>
int main() { int main() {
// announce custom message types // announce custom message types
announce<shutdown_request>(); announce<shutdown_request>();
announce<plus_request>(&plus_request::a, &plus_request::b); announce<plus_request>(&plus_request::a, &plus_request::b);
announce<minus_request>(&minus_request::a, &minus_request::b); announce<minus_request>(&minus_request::a, &minus_request::b);
// test function-based impl // test function-based impl
spawn(tester, spawn_typed(typed_calculator)); spawn(tester, spawn_typed(typed_calculator));
await_all_actors_done(); await_all_actors_done();
// test class-based impl // test class-based impl
spawn(tester, spawn_typed<typed_calculator_class>()); spawn(tester, spawn_typed<typed_calculator_class>());
await_all_actors_done(); await_all_actors_done();
// done // done
shutdown(); shutdown();
return 0; return 0;
} }
This diff is collapsed.
/******************************************************************************\ /******************************************************************************\
* ___ __ * * ___ __ *
* /\_ \ __/\ \ * * /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ * * \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ * * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ * * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ * * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ * * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ * * \ \_\ \ \_\ *
* \/_/ \/_/ * * \/_/ \/_/ *
* * * *
* Copyright (C) 2011-2014 * * Copyright (C) 2011-2014 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> * * Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> * * Raphael Hiesgen <raphael.hiesgen@haw-hamburg.de> *
* * * *
* This file is part of libcppa. * * This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under * * libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the * * the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License * * Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. * * or (at your option) any later version. *
* * * *
* libcppa is distributed in the hope that it will be useful, * * libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of * * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. * * See the GNU Lesser General Public License for more details. *
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \ ******************************************************************************/
#include <vector> #include <vector>
#include <iomanip> #include <iomanip>
...@@ -47,78 +47,78 @@ constexpr const char* kernel_name = "matrix_mult"; ...@@ -47,78 +47,78 @@ constexpr const char* kernel_name = "matrix_mult";
// opencl kernel, multiplies matrix1 and matrix2 // opencl kernel, multiplies matrix1 and matrix2
// last parameter is, by convention, the output parameter // last parameter is, by convention, the output parameter
constexpr const char* kernel_source = R"__( constexpr const char* kernel_source = R"__(
__kernel void matrix_mult(__global float* matrix1, __kernel void matrix_mult(__global float* matrix1,
__global float* matrix2, __global float* matrix2,
__global float* output) { __global float* output) {
// we only use square matrices, hence: width == height // we only use square matrices, hence: width == height
size_t size = get_global_size(0); // == get_global_size_(1); size_t size = get_global_size(0); // == get_global_size_(1);
size_t x = get_global_id(0); size_t x = get_global_id(0);
size_t y = get_global_id(1); size_t y = get_global_id(1);
float result = 0; float result = 0;
for (size_t idx = 0; idx < size; ++idx) { for (size_t idx = 0; idx < size; ++idx) {
result += matrix1[idx + y * size] * matrix2[x + idx * size]; result += matrix1[idx + y * size] * matrix2[x + idx * size];
}
output[x+y*size] = result;
} }
output[x+y*size] = result;
}
)__"; )__";
} // namespace <anonymous> } // namespace <anonymous>
void print_as_matrix(const vector<float>& matrix) { void print_as_matrix(const vector<float>& matrix) {
for (size_t column = 0; column < matrix_size; ++column) { for (size_t column = 0; column < matrix_size; ++column) {
for (size_t row = 0; row < matrix_size; ++row) { for (size_t row = 0; row < matrix_size; ++row) {
cout << fixed << setprecision(2) << setw(9) cout << fixed << setprecision(2) << setw(9)
<< matrix[row + column * matrix_size]; << matrix[row + column * matrix_size];
}
cout << endl;
} }
cout << endl;
}
} }
void multiplier(event_based_actor* self) { void multiplier(event_based_actor* self) {
// the opencl actor only understands vectors // the opencl actor only understands vectors
// so these vectors represent the matrices // so these vectors represent the matrices
vector<float> m1(matrix_size * matrix_size); vector<float> m1(matrix_size * matrix_size);
vector<float> m2(matrix_size * matrix_size); vector<float> m2(matrix_size * matrix_size);
// fill each with ascending values // fill each with ascending values
iota(m1.begin(), m1.end(), 0); iota(m1.begin(), m1.end(), 0);
iota(m2.begin(), m2.end(), 0); iota(m2.begin(), m2.end(), 0);
// print "source" matrix // print "source" matrix
cout << "calculating square of matrix:" << endl; cout << "calculating square of matrix:" << endl;
print_as_matrix(m1); print_as_matrix(m1);
cout << endl; cout << endl;
// spawn an opencl actor // spawn an opencl actor
// template parameter: signature of opencl kernel using proper return type // template parameter: signature of opencl kernel using proper return type
// instead of output parameter (implicitly // instead of output parameter (implicitly
// mapped to the last kernel argument) // mapped to the last kernel argument)
// 1st arg: source code of one or more kernels // 1st arg: source code of one or more kernels
// 2nd arg: name of the kernel to use // 2nd arg: name of the kernel to use
// 3rd arg: global dimension arguments for opencl's enqueue; // 3rd arg: global dimension arguments for opencl's enqueue;
// creates matrix_size * matrix_size global work items // creates matrix_size * matrix_size global work items
// 4th arg: offsets for global dimensions (optional) // 4th arg: offsets for global dimensions (optional)
// 5th arg: local dimensions (optional) // 5th arg: local dimensions (optional)
// 6th arg: number of elements in the result buffer // 6th arg: number of elements in the result buffer
auto worker = spawn_cl<float*(float*,float*)>(kernel_source, auto worker = spawn_cl<float*(float*,float*)>(kernel_source,
kernel_name, kernel_name,
{matrix_size, matrix_size}, {matrix_size, matrix_size},
{}, {},
{}, {},
matrix_size * matrix_size); matrix_size * matrix_size);
// send both matrices to the actor and wait for a result // send both matrices to the actor and wait for a result
self->sync_send(worker, move(m1), move(m2)).then( self->sync_send(worker, move(m1), move(m2)).then(
[](const vector<float>& result) { [](const vector<float>& result) {
cout << "result: " << endl; cout << "result: " << endl;
print_as_matrix(result); print_as_matrix(result);
} }
); );
} }
int main() { int main() {
announce<vector<float>>(); announce<vector<float>>();
spawn(multiplier); spawn(multiplier);
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* - ./build/bin/group_server -p 4242 * * - ./build/bin/group_server -p 4242 *
* - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice * * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice *
* - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob * * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob *
\******************************************************************************/ \ ******************************************************************************/
#include <set> #include <set>
#include <map> #include <map>
...@@ -26,136 +26,132 @@ using namespace caf; ...@@ -26,136 +26,132 @@ using namespace caf;
struct line { string str; }; struct line { string str; };
istream& operator>>(istream& is, line& l) { istream& operator>>(istream& is, line& l) {
getline(is, l.str); getline(is, l.str);
return is; return is;
} }
namespace { string s_last_line; } namespace { string s_last_line; }
message split_line(const line& l) { message split_line(const line& l) {
istringstream strs(l.str); istringstream strs(l.str);
s_last_line = move(l.str); s_last_line = move(l.str);
string tmp; string tmp;
message_builder mb; message_builder mb;
while (getline(strs, tmp, ' ')) { while (getline(strs, tmp, ' ')) {
if (!tmp.empty()) mb.append(std::move(tmp)); if (!tmp.empty()) mb.append(std::move(tmp));
} }
return mb.to_message(); return mb.to_message();
} }
void client(event_based_actor* self, const string& name) { void client(event_based_actor* self, const string& name) {
self->become ( self->become (
on(atom("broadcast"), arg_match) >> [=](const string& message) { on(atom("broadcast"), arg_match) >> [=](const string& message) {
for(auto& dest : self->joined_groups()) { for(auto& dest : self->joined_groups()) {
self->send(dest, name + ": " + message); self->send(dest, name + ": " + message);
} }
}, },
on(atom("join"), arg_match) >> [=](const group& what) { on(atom("join"), arg_match) >> [=](const group& what) {
for (auto g : self->joined_groups()) { for (auto g : self->joined_groups()) {
cout << "*** leave " << to_string(g) << endl; cout << "*** leave " << to_string(g) << endl;
self->send(self, g, name + " has left the chatroom"); self->send(self, g, name + " has left the chatroom");
self->leave(g); self->leave(g);
} }
cout << "*** join " << to_string(what) << endl; cout << "*** join " << to_string(what) << endl;
self->join(what); self->join(what);
self->send(what, name + " has entered the chatroom"); self->send(what, name + " has entered the chatroom");
}, },
[=](const string& txt) { [=](const string& txt) {
// don't print own messages // don't print own messages
if (self->last_sender() != self) cout << txt << endl; if (self->last_sender() != self) cout << txt << endl;
}, },
[=](const group_down_msg& g) { [=](const group_down_msg& g) {
cout << "*** chatroom offline: " << to_string(g.source) << endl; cout << "*** chatroom offline: " << to_string(g.source) << endl;
}, },
others() >> [=]() { others() >> [=]() {
cout << "unexpected: " << to_string(self->last_dequeued()) << endl; cout << "unexpected: " << to_string(self->last_dequeued()) << endl;
} }
); );
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
string name;
string name; string group_id;
string group_id; options_description desc;
options_description desc; bool args_valid = match_stream<string>(argv + 1, argv + argc) (
bool args_valid = match_stream<string>(argv + 1, argv + argc) ( on_opt1('n', "name", &desc, "set name") >> rd_arg(name),
on_opt1('n', "name", &desc, "set name") >> rd_arg(name), on_opt1('g', "group", &desc, "join group <arg1>") >> rd_arg(group_id),
on_opt1('g', "group", &desc, "join group <arg1>") >> rd_arg(group_id), on_opt0('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
on_opt0('h', "help", &desc, "print help") >> print_desc_and_exit(&desc) );
); if (!args_valid) {
print_desc_and_exit(&desc)();
if (!args_valid) print_desc_and_exit(&desc)(); }
while (name.empty()) {
while (name.empty()) { cout << "please enter your name: " << flush;
cout << "please enter your name: " << flush; if (!getline(cin, name)) {
if (!getline(cin, name)) { cerr << "*** no name given... terminating" << endl;
cerr << "*** no name given... terminating" << endl; return 1;
return 1;
}
} }
}
auto client_actor = spawn(client, name); auto client_actor = spawn(client, name);
// evaluate group parameters
// evaluate group parameters if (!group_id.empty()) {
if (!group_id.empty()) { auto p = group_id.find(':');
auto p = group_id.find(':'); if (p == std::string::npos) {
if (p == std::string::npos) { cerr << "*** error parsing argument " << group_id
cerr << "*** error parsing argument " << group_id << ", expected format: <module_name>:<group_id>";
<< ", expected format: <module_name>:<group_id>"; } else {
} try {
else { auto g = group::get(group_id.substr(0, p),
try { group_id.substr(p + 1));
auto g = group::get(group_id.substr(0, p), anon_send(client_actor, atom("join"), g);
group_id.substr(p + 1)); }
anon_send(client_actor, atom("join"), g); catch (exception& e) {
} ostringstream err;
catch (exception& e) { cerr << "*** exception: group::get(\"" << group_id.substr(0, p)
ostringstream err; << "\", \"" << group_id.substr(p + 1) << "\") failed; "
cerr << "*** exception: group::get(\"" << group_id.substr(0, p) << to_verbose_string(e) << endl;
<< "\", \"" << group_id.substr(p + 1) << "\") failed; " }
<< to_verbose_string(e) << endl;
}
}
} }
cout << "*** starting client, type '/help' for a list of commands" << endl; }
auto starts_with = [](const string& str) -> function<optional<string> (const string&)> { cout << "*** starting client, type '/help' for a list of commands" << endl;
return [=](const string& arg) -> optional<string> { auto starts_with = [](const string& str) -> function<optional<string> (const string&)> {
if (arg.compare(0, str.size(), str) == 0) { return [=](const string& arg) -> optional<string> {
return arg; if (arg.compare(0, str.size(), str) == 0) {
} return arg;
return none; }
}; return none;
}; };
istream_iterator<line> lines(cin); };
istream_iterator<line> eof; istream_iterator<line> lines(cin);
match_each (lines, eof, split_line) ( istream_iterator<line> eof;
on("/join", arg_match) >> [&](const string& mod, const string& id) { match_each (lines, eof, split_line) (
try { on("/join", arg_match) >> [&](const string& mod, const string& id) {
anon_send(client_actor, atom("join"), group::get(mod, id)); try {
} anon_send(client_actor, atom("join"), group::get(mod, id));
catch (exception& e) { }
cerr << "*** exception: " << to_verbose_string(e) << endl; catch (exception& e) {
} cerr << "*** exception: " << to_verbose_string(e) << endl;
}, }
on("/quit") >> [&] { },
// close STDIN; causes this match loop to quit on("/quit") >> [&] {
cin.setstate(ios_base::eofbit); // close STDIN; causes this match loop to quit
}, cin.setstate(ios_base::eofbit);
on(starts_with("/"), any_vals) >> [&] { },
cout << "*** available commands:\n" on(starts_with("/"), any_vals) >> [&] {
" /join <module> <group> join a new chat channel\n" cout << "*** available commands:\n"
" /quit quit the program\n" " /join <module> <group> join a new chat channel\n"
" /help print this text\n" << flush; " /quit quit the program\n"
}, " /help print this text\n" << flush;
others() >> [&] { },
if (!s_last_line.empty()) { others() >> [&] {
anon_send(client_actor, atom("broadcast"), s_last_line); if (!s_last_line.empty()) {
} anon_send(client_actor, atom("broadcast"), s_last_line);
} }
); }
// force actor to quit );
anon_send_exit(client_actor, exit_reason::user_shutdown); // force actor to quit
await_all_actors_done(); anon_send_exit(client_actor, exit_reason::user_shutdown);
shutdown(); await_all_actors_done();
return 0; shutdown();
return 0;
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* - ./build/bin/group_server -p 4242 * * - ./build/bin/group_server -p 4242 *
* - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice * * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n alice *
* - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob * * - ./build/bin/group_chat -g remote:chatroom@localhost:4242 -n bob *
\******************************************************************************/ \ ******************************************************************************/
#include <string> #include <string>
#include <iostream> #include <iostream>
...@@ -20,46 +20,46 @@ using namespace std; ...@@ -20,46 +20,46 @@ using namespace std;
using namespace caf; using namespace caf;
int main(int argc, char** argv) { int main(int argc, char** argv) {
uint16_t port = 0; uint16_t port = 0;
options_description desc; options_description desc;
bool args_valid = match_stream<string>(argv + 1, argv + argc) ( bool args_valid = match_stream<string>(argv + 1, argv + argc) (
on_opt1('p', "port", &desc, "set port") >> rd_arg(port), on_opt1('p', "port", &desc, "set port") >> rd_arg(port),
on_opt0('h', "help", &desc, "print help") >> print_desc_and_exit(&desc) on_opt0('h', "help", &desc, "print help") >> print_desc_and_exit(&desc)
); );
if (port <= 1024) { if (port <= 1024) {
cerr << "*** no port > 1024 given" << endl; cerr << "*** no port > 1024 given" << endl;
args_valid = false; args_valid = false;
} }
if (!args_valid) { if (!args_valid) {
// print_desc(&desc) returns a function printing the stored help text // print_desc(&desc) returns a function printing the stored help text
auto desc_printer = print_desc(&desc); auto desc_printer = print_desc(&desc);
desc_printer(); desc_printer();
return 1; return 1;
} }
try { try {
// try to bind the group server to the given port, // try to bind the group server to the given port,
// this allows other nodes to access groups of this server via // this allows other nodes to access groups of this server via
// group::get("remote", "<group>@<host>:<port>"); // group::get("remote", "<group>@<host>:<port>");
// note: it is not needed to explicitly create a <group> on the server, // note: it is not needed to explicitly create a <group> on the server,
// as groups are created on-the-fly on first usage // as groups are created on-the-fly on first usage
io::publish_local_groups(port); io::publish_local_groups(port);
} }
catch (bind_failure& e) { catch (bind_failure& e) {
// thrown if <port> is already in use // thrown if <port> is already in use
cerr << "*** bind_failure: " << e.what() << endl; cerr << "*** bind_failure: " << e.what() << endl;
return 2; return 2;
} }
catch (network_error& e) { catch (network_error& e) {
// thrown on errors in the socket API // thrown on errors in the socket API
cerr << "*** network error: " << e.what() << endl; cerr << "*** network error: " << e.what() << endl;
return 2; return 2;
} }
cout << "type 'quit' to shutdown the server" << endl; cout << "type 'quit' to shutdown the server" << endl;
string line; string line;
while (getline(cin, line)) { while (getline(cin, line)) {
if (line == "quit") return 0; if (line == "quit") return 0;
else cout << "illegal command" << endl; else cout << "illegal command" << endl;
} }
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -8,6 +8,6 @@ message Pong { ...@@ -8,6 +8,6 @@ message Pong {
} }
message PingOrPong { message PingOrPong {
optional Ping ping = 1; optional Ping ping = 1;
optional Pong pong = 2; optional Pong pong = 2;
} }
This diff is collapsed.
This diff is collapsed.
...@@ -15,14 +15,14 @@ using namespace caf; ...@@ -15,14 +15,14 @@ using namespace caf;
// POD struct // POD struct
struct foo { struct foo {
std::vector<int> a; std::vector<int> a;
int b; int b;
}; };
// announce requires foo to have the equal operator implemented // announce requires foo to have the equal operator implemented
bool operator==(const foo& lhs, const foo& rhs) { bool operator==(const foo& lhs, const foo& rhs) {
return lhs.a == rhs.a return lhs.a == rhs.a
&& lhs.b == rhs.b; && lhs.b == rhs.b;
} }
// a pair of two ints // a pair of two ints
...@@ -33,95 +33,95 @@ using foo_pair2 = std::pair<int, int>; ...@@ -33,95 +33,95 @@ using foo_pair2 = std::pair<int, int>;
// a struct with member vector<vector<...>> // a struct with member vector<vector<...>>
struct foo2 { struct foo2 {
int a; int a;
vector<vector<double>> b; vector<vector<double>> b;
}; };
bool operator==( const foo2& lhs, const foo2& rhs ) { bool operator==( const foo2& lhs, const foo2& rhs ) {
return lhs.a == rhs.a && lhs.b == rhs.b; return lhs.a == rhs.a && lhs.b == rhs.b;
} }
// receives `remaining` messages // receives `remaining` messages
void testee(event_based_actor* self, size_t remaining) { void testee(event_based_actor* self, size_t remaining) {
auto set_next_behavior = [=] { auto set_next_behavior = [=] {
if (remaining > 1) testee(self, remaining - 1); if (remaining > 1) testee(self, remaining - 1);
else self->quit(); else self->quit();
}; };
self->become ( self->become (
// note: we sent a foo_pair2, but match on foo_pair // note: we sent a foo_pair2, but match on foo_pair
// that's safe because both are aliases for std::pair<int, int> // that's safe because both are aliases for std::pair<int, int>
on<foo_pair>() >> [=](const foo_pair& val) { on<foo_pair>() >> [=](const foo_pair& val) {
cout << "foo_pair(" cout << "foo_pair("
<< val.first << ", " << val.first << ", "
<< val.second << ")" << val.second << ")"
<< endl; << endl;
set_next_behavior(); set_next_behavior();
}, },
on<foo>() >> [=](const foo& val) { on<foo>() >> [=](const foo& val) {
cout << "foo({"; cout << "foo({";
auto i = val.a.begin(); auto i = val.a.begin();
auto end = val.a.end(); auto end = val.a.end();
if (i != end) { if (i != end) {
cout << *i; cout << *i;
while (++i != end) { while (++i != end) {
cout << ", " << *i; cout << ", " << *i;
}
}
cout << "}, " << val.b << ")" << endl;
set_next_behavior();
} }
); }
cout << "}, " << val.b << ")" << endl;
set_next_behavior();
}
);
} }
int main(int, char**) { int main(int, char**) {
// announces foo to the libcaf type system; // announces foo to the libcaf type system;
// the function expects member pointers to all elements of foo // the function expects member pointers to all elements of foo
announce<foo>(&foo::a, &foo::b); announce<foo>(&foo::a, &foo::b);
// announce foo2 to the libcaf type system, // announce foo2 to the libcaf type system,
// note that recursive containers are managed automatically by libcaf // note that recursive containers are managed automatically by libcaf
announce<foo2>(&foo2::a, &foo2::b); announce<foo2>(&foo2::a, &foo2::b);
foo2 vd; foo2 vd;
vd.a = 5; vd.a = 5;
vd.b.resize(1); vd.b.resize(1);
vd.b.back().push_back(42); vd.b.back().push_back(42);
vector<char> buf; vector<char> buf;
binary_serializer bs(std::back_inserter(buf)); binary_serializer bs(std::back_inserter(buf));
bs << vd; bs << vd;
binary_deserializer bd(buf.data(), buf.size()); binary_deserializer bd(buf.data(), buf.size());
foo2 vd2; foo2 vd2;
uniform_typeid<foo2>()->deserialize(&vd2, &bd); uniform_typeid<foo2>()->deserialize(&vd2, &bd);
assert(vd == vd2); assert(vd == vd2);
// announce std::pair<int, int> to the type system; // announce std::pair<int, int> to the type system;
// NOTE: foo_pair is NOT distinguishable from foo_pair2! // NOTE: foo_pair is NOT distinguishable from foo_pair2!
auto uti = announce<foo_pair>(&foo_pair::first, &foo_pair::second); auto uti = announce<foo_pair>(&foo_pair::first, &foo_pair::second);
// since foo_pair and foo_pair2 are not distinguishable since typedefs // since foo_pair and foo_pair2 are not distinguishable since typedefs
// do not 'create' an own type, this announce fails, since // do not 'create' an own type, this announce fails, since
// std::pair<int, int> is already announced // std::pair<int, int> is already announced
assert(announce<foo_pair2>(&foo_pair2::first, &foo_pair2::second) == uti); assert(announce<foo_pair2>(&foo_pair2::first, &foo_pair2::second) == uti);
// libcaf returns the same uniform_type_info // libcaf returns the same uniform_type_info
// instance for foo_pair and foo_pair2 // instance for foo_pair and foo_pair2
assert(uniform_typeid<foo_pair>() == uniform_typeid<foo_pair2>()); assert(uniform_typeid<foo_pair>() == uniform_typeid<foo_pair2>());
// spawn a testee that receives two messages // spawn a testee that receives two messages
auto t = spawn(testee, 2); auto t = spawn(testee, 2);
{ {
scoped_actor self; scoped_actor self;
// send t a foo // send t a foo
self->send(t, foo{std::vector<int>{1, 2, 3, 4}, 5}); self->send(t, foo{std::vector<int>{1, 2, 3, 4}, 5});
// send t a foo_pair2 // send t a foo_pair2
self->send(t, foo_pair2{3, 4}); self->send(t, foo_pair2{3, 4});
} }
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -12,56 +12,56 @@ using namespace caf; ...@@ -12,56 +12,56 @@ using namespace caf;
// a simple class using getter and setter member functions // a simple class using getter and setter member functions
class foo { class foo {
int m_a; int m_a;
int m_b; int m_b;
public: public:
foo(int a0 = 0, int b0 = 0) : m_a(a0), m_b(b0) { } foo(int a0 = 0, int b0 = 0) : m_a(a0), m_b(b0) { }
foo(const foo&) = default; foo(const foo&) = default;
foo& operator=(const foo&) = default; foo& operator=(const foo&) = default;
int a() const { return m_a; } int a() const { return m_a; }
void set_a(int val) { m_a = val; } void set_a(int val) { m_a = val; }
int b() const { return m_b; } int b() const { return m_b; }
void set_b(int val) { m_b = val; } void set_b(int val) { m_b = val; }
}; };
// announce requires foo to be comparable // announce requires foo to be comparable
bool operator==(const foo& lhs, const foo& rhs) { bool operator==(const foo& lhs, const foo& rhs) {
return lhs.a() == rhs.a() return lhs.a() == rhs.a()
&& lhs.b() == rhs.b(); && lhs.b() == rhs.b();
} }
void testee(event_based_actor* self) { void testee(event_based_actor* self) {
self->become ( self->become (
on<foo>() >> [=](const foo& val) { on<foo>() >> [=](const foo& val) {
aout(self) << "foo(" aout(self) << "foo("
<< val.a() << ", " << val.a() << ", "
<< val.b() << ")" << val.b() << ")"
<< endl; << endl;
self->quit(); self->quit();
} }
); );
} }
int main(int, char**) { int main(int, char**) {
// if a class uses getter and setter member functions, // if a class uses getter and setter member functions,
// we pass those to the announce function as { getter, setter } pairs. // we pass those to the announce function as { getter, setter } pairs.
announce<foo>(make_pair(&foo::a, &foo::set_a), announce<foo>(make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)); make_pair(&foo::b, &foo::set_b));
{ {
scoped_actor self; scoped_actor self;
auto t = spawn(testee); auto t = spawn(testee);
self->send(t, foo{1, 2}); self->send(t, foo{1, 2});
} }
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -12,33 +12,33 @@ using namespace caf; ...@@ -12,33 +12,33 @@ using namespace caf;
// a simple class using overloaded getter and setter member functions // a simple class using overloaded getter and setter member functions
class foo { class foo {
int m_a; int m_a;
int m_b; int m_b;
public: public:
foo() : m_a(0), m_b(0) { } foo() : m_a(0), m_b(0) { }
foo(int a0, int b0) : m_a(a0), m_b(b0) { } foo(int a0, int b0) : m_a(a0), m_b(b0) { }
foo(const foo&) = default; foo(const foo&) = default;
foo& operator=(const foo&) = default; foo& operator=(const foo&) = default;
int a() const { return m_a; } int a() const { return m_a; }
void a(int val) { m_a = val; } void a(int val) { m_a = val; }
int b() const { return m_b; } int b() const { return m_b; }
void b(int val) { m_b = val; } void b(int val) { m_b = val; }
}; };
// announce requires foo to have the equal operator implemented // announce requires foo to have the equal operator implemented
bool operator==(const foo& lhs, const foo& rhs) { bool operator==(const foo& lhs, const foo& rhs) {
return lhs.a() == rhs.a() return lhs.a() == rhs.a()
&& lhs.b() == rhs.b(); && lhs.b() == rhs.b();
} }
// a member function pointer to get an attribute of foo // a member function pointer to get an attribute of foo
...@@ -47,43 +47,43 @@ using foo_getter = int (foo::*)() const; ...@@ -47,43 +47,43 @@ using foo_getter = int (foo::*)() const;
using foo_setter = void (foo::*)(int); using foo_setter = void (foo::*)(int);
void testee(event_based_actor* self) { void testee(event_based_actor* self) {
self->become ( self->become (
on<foo>() >> [=](const foo& val) { on<foo>() >> [=](const foo& val) {
aout(self) << "foo(" aout(self) << "foo("
<< val.a() << ", " << val.a() << ", "
<< val.b() << ")" << val.b() << ")"
<< endl; << endl;
self->quit(); self->quit();
} }
); );
} }
int main(int, char**) { int main(int, char**) {
// since the member function "a" is ambiguous, the compiler // since the member function "a" is ambiguous, the compiler
// also needs a type to select the correct overload // also needs a type to select the correct overload
foo_getter g1 = &foo::a; foo_getter g1 = &foo::a;
foo_setter s1 = &foo::a; foo_setter s1 = &foo::a;
// same is true for b // same is true for b
foo_getter g2 = &foo::b; foo_getter g2 = &foo::b;
foo_setter s2 = &foo::b; foo_setter s2 = &foo::b;
// equal to example 3 // equal to example 3
announce<foo>(make_pair(g1, s1), make_pair(g2, s2)); announce<foo>(make_pair(g1, s1), make_pair(g2, s2));
// alternative syntax that uses casts instead of variables // alternative syntax that uses casts instead of variables
// (returns false since foo is already announced) // (returns false since foo is already announced)
announce<foo>(make_pair(static_cast<foo_getter>(&foo::a), announce<foo>(make_pair(static_cast<foo_getter>(&foo::a),
static_cast<foo_setter>(&foo::a)), static_cast<foo_setter>(&foo::a)),
make_pair(static_cast<foo_getter>(&foo::b), make_pair(static_cast<foo_getter>(&foo::b),
static_cast<foo_setter>(&foo::b))); static_cast<foo_setter>(&foo::b)));
// spawn a new testee and send it a foo // spawn a new testee and send it a foo
{ {
scoped_actor self; scoped_actor self;
self->send(spawn(testee), foo{1, 2}); self->send(spawn(testee), foo{1, 2});
} }
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -11,129 +11,129 @@ using namespace caf; ...@@ -11,129 +11,129 @@ using namespace caf;
// the foo class from example 3 // the foo class from example 3
class foo { class foo {
int m_a; int m_a;
int m_b; int m_b;
public: public:
foo() : m_a(0), m_b(0) { } foo() : m_a(0), m_b(0) { }
foo(int a0, int b0) : m_a(a0), m_b(b0) { } foo(int a0, int b0) : m_a(a0), m_b(b0) { }
foo(const foo&) = default; foo(const foo&) = default;
foo& operator=(const foo&) = default; foo& operator=(const foo&) = default;
int a() const { return m_a; } int a() const { return m_a; }
void set_a(int val) { m_a = val; } void set_a(int val) { m_a = val; }
int b() const { return m_b; } int b() const { return m_b; }
void set_b(int val) { m_b = val; } void set_b(int val) { m_b = val; }
}; };
// needed for operator==() of bar // needed for operator==() of bar
bool operator==(const foo& lhs, const foo& rhs) { bool operator==(const foo& lhs, const foo& rhs) {
return lhs.a() == rhs.a() return lhs.a() == rhs.a()
&& lhs.b() == rhs.b(); && lhs.b() == rhs.b();
} }
// simple struct that has foo as a member // simple struct that has foo as a member
struct bar { struct bar {
foo f; foo f;
int i; int i;
}; };
// announce requires bar to have the equal operator implemented // announce requires bar to have the equal operator implemented
bool operator==(const bar& lhs, const bar& rhs) { bool operator==(const bar& lhs, const bar& rhs) {
return lhs.f == rhs.f return lhs.f == rhs.f
&& lhs.i == rhs.i; && lhs.i == rhs.i;
} }
// "worst case" class ... not a good software design at all ;) // "worst case" class ... not a good software design at all ;)
class baz { class baz {
foo m_f; foo m_f;
public: public:
bar b; bar b;
// announce requires a default constructor // announce requires a default constructor
baz() = default; baz() = default;
inline baz(const foo& mf, const bar& mb) : m_f(mf), b(mb) { } inline baz(const foo& mf, const bar& mb) : m_f(mf), b(mb) { }
const foo& f() const { return m_f; } const foo& f() const { return m_f; }
void set_f(const foo& val) { m_f = val; } void set_f(const foo& val) { m_f = val; }
}; };
// even worst case classes have to implement operator== // even worst case classes have to implement operator==
bool operator==(const baz& lhs, const baz& rhs) { bool operator==(const baz& lhs, const baz& rhs) {
return lhs.f() == rhs.f() return lhs.f() == rhs.f()
&& lhs.b == rhs.b; && lhs.b == rhs.b;
} }
// receives `remaining` messages // receives `remaining` messages
void testee(event_based_actor* self, size_t remaining) { void testee(event_based_actor* self, size_t remaining) {
auto set_next_behavior = [=] { auto set_next_behavior = [=] {
if (remaining > 1) testee(self, remaining - 1); if (remaining > 1) testee(self, remaining - 1);
else self->quit(); else self->quit();
}; };
self->become ( self->become (
on<bar>() >> [=](const bar& val) { on<bar>() >> [=](const bar& val) {
aout(self) << "bar(foo(" aout(self) << "bar(foo("
<< val.f.a() << ", " << val.f.a() << ", "
<< val.f.b() << "), " << val.f.b() << "), "
<< val.i << ")" << val.i << ")"
<< endl; << endl;
set_next_behavior(); set_next_behavior();
}, },
on<baz>() >> [=](const baz& val) { on<baz>() >> [=](const baz& val) {
// prints: baz ( foo ( 1, 2 ), bar ( foo ( 3, 4 ), 5 ) ) // prints: baz ( foo ( 1, 2 ), bar ( foo ( 3, 4 ), 5 ) )
aout(self) << to_string(make_message(val)) << endl; aout(self) << to_string(make_message(val)) << endl;
set_next_behavior(); set_next_behavior();
} }
); );
} }
int main(int, char**) { int main(int, char**) {
// bar has a non-trivial data member f, thus, we have to told // bar has a non-trivial data member f, thus, we have to told
// announce how to serialize/deserialize this member; // announce how to serialize/deserialize this member;
// this is was the compound_member function is for; // this is was the compound_member function is for;
// it takes a pointer to the non-trivial member as first argument // it takes a pointer to the non-trivial member as first argument
// followed by all "sub-members" either as member pointer or // followed by all "sub-members" either as member pointer or
// { getter, setter } pair // { getter, setter } pair
announce<bar>(compound_member(&bar::f, announce<bar>(compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a), make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)), make_pair(&foo::b, &foo::set_b)),
&bar::i); &bar::i);
// baz has non-trivial data members with getter/setter pair // baz has non-trivial data members with getter/setter pair
// and getter returning a mutable reference // and getter returning a mutable reference
announce<baz>(compound_member(make_pair(&baz::f, &baz::set_f), announce<baz>(compound_member(make_pair(&baz::f, &baz::set_f),
make_pair(&foo::a, &foo::set_a), make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)), make_pair(&foo::b, &foo::set_b)),
// compound member that has a compound member // compound member that has a compound member
compound_member(&baz::b, compound_member(&baz::b,
compound_member(&bar::f, compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a), make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)), make_pair(&foo::b, &foo::set_b)),
&bar::i)); &bar::i));
// spawn a testee that receives two messages // spawn a testee that receives two messages
auto t = spawn(testee, 2); auto t = spawn(testee, 2);
{ {
scoped_actor self; scoped_actor self;
self->send(t, bar{foo{1, 2}, 3}); self->send(t, bar{foo{1, 2}, 3});
self->send(t, baz{foo{1, 2}, bar{foo{3, 4}, 5}}); self->send(t, baz{foo{1, 2}, bar{foo{3, 4}, 5}});
} }
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
This diff is collapsed.
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the Boost Software License, Version 1.0. See *
* accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt *
******************************************************************************/
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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