Commit e5fa9a1a authored by neverlord's avatar neverlord

examples and documentation

parent b045c90e
......@@ -218,4 +218,4 @@ libcppa_la_LDFLAGS = -release $(PACKAGE_VERSION) $(BOOST_CPPFLAGS)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libcppa.pc
SUBDIRS = . unit_testing
SUBDIRS = . unit_testing examples
......@@ -43,5 +43,5 @@ CPPFLAGS="$ORIGINAL_CPPFLAGS"
AC_ARG_VAR([NO_VERSIONED_INCLUDE_DIR], [set this to 1 in order to install headers into <prefix>/cppa/ rather than into <prefix>/cppa/<version>/cppa/])
AM_CONDITIONAL([VERSIONED_INCLUDE_DIR], [test "x$NO_VERSIONED_INCLUDE_DIR" != "x1"])
AC_CONFIG_FILES([Makefile unit_testing/Makefile libcppa.pc])
AC_CONFIG_FILES([Makefile unit_testing/Makefile examples/Makefile libcppa.pc])
AC_OUTPUT
......@@ -229,3 +229,8 @@ unit_testing/test__pattern.cpp
cppa/util/fixed_vector.hpp
cppa/detail/implicit_conversions.hpp
cppa/util/is_array_of.hpp
examples/announce_example_1.cpp
examples/announce_example_2.cpp
examples/announce_example_3.cpp
examples/announce_example_4.cpp
examples/announce_example_5.cpp
......@@ -59,8 +59,9 @@ namespace cppa {
*/
bool announce(const std::type_info& tinfo, uniform_type_info* utype);
// deals with member pointer
/**
* @brief Creates meta informations for a non-trivial member.
* @brief Creates meta informations for a non-trivial member @p C.
* @param c_ptr Pointer to the non-trivial member.
* @param args "Sub-members" of @p c_ptr
* @see {@link announce_example_4.cpp announce example 4}
......@@ -73,6 +74,26 @@ compound_member(C Parent::*c_ptr, const Args&... args)
return { c_ptr, new detail::default_uniform_type_info_impl<C>(args...) };
}
// deals with getter returning a mutable reference
template<class C, class Parent, typename... Args>
std::pair<C& (Parent::*)(), util::abstract_uniform_type_info<C>*>
compound_member(C& (Parent::*c_ptr)(), const Args&... args)
{
return { c_ptr, new detail::default_uniform_type_info_impl<C>(args...) };
}
// deals with getter/setter pair
template<class Parent, typename GRes,
typename SRes, typename SArg, typename... Args>
std::pair<std::pair<GRes (Parent::*)() const, SRes (Parent::*)(SArg)>,
util::abstract_uniform_type_info<typename util::rm_ref<GRes>::type>*>
compound_member(const std::pair<GRes (Parent::*)() const, SRes (Parent::*)(SArg)>& gspair,
const Args&... args)
{
return { gspair, new detail::default_uniform_type_info_impl<typename util::rm_ref<GRes>::type>(args...) };
}
/**
* @brief Adds a new type mapping for @p T to the libcppa type system.
* @param args Members of @p T.
......
......@@ -229,6 +229,16 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
push_back(std::forward<Args>(args)...);
}
// pr.first = getter / setter pair
// pr.second = meta object to handle pr.first
template<typename GRes, typename SRes, typename SArg, typename C, typename... Args>
void push_back(const std::pair<std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>, util::abstract_uniform_type_info<typename util::rm_ref<GRes>::type>*>& pr,
Args&&... args)
{
m_members.push_back({ pr.second, pr.first.first, pr.first.second });
push_back(std::forward<Args>(args)...);
}
// pr.first = getter member const function pointer
// pr.second = setter member function pointer
template<typename GRes, typename SRes, typename SArg, class C, typename... Args>
......@@ -303,14 +313,6 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
public:
/*
template<typename... Args>
default_uniform_type_info_impl(const Args&... args)
{
push_back(args...);
}
*/
template<typename... Args>
default_uniform_type_info_impl(Args&&... args)
{
......
#include <cassert>
#include <utility>
#include <iostream>
......@@ -8,34 +9,53 @@ using std::endl;
using namespace cppa;
// POD struct - pair of two ints
struct foo
{
int a;
int b;
};
// announce requires foo to have the equal operator implemented
bool operator==(const foo& lhs, const foo& rhs)
{
return lhs.a == rhs.a
&& lhs.b == rhs.b;
}
// another pair of two ints
typedef std::pair<int,int> foo_pair;
typedef std::pair<int,int> foo_pair2;
int main(int, char**)
{
announce<foo>(&foo::a, &foo::b);
announce<foo_pair>(&foo_pair::first,
&foo_pair::second);
// announces foo to the libcppa type system;
// the function expects member pointers to all elements of foo
assert(announce<foo>(&foo::a, &foo::b) == true);
// announce std::pair<int,int> to the type system;
// NOTE: foo_pair is NOT distinguishable from foo_pair2!
assert(announce<foo_pair>(&foo_pair::first, &foo_pair::second) == true);
// since foo_pair and foo_pair2 are not distinguishable since typedefs
// do not 'create' an own type, this announce fails, since
// std::pair<int,int> is already announced
assert(announce<foo_pair2>(&foo_pair2::first, &foo_pair2::second) == false);
// send a foo to ourselves
send(self(), foo{1,2});
send(self(), foo_pair{3,4});
// send a foo_pair2 to ourselves
send(self(), foo_pair2{3,4});
// quits the program
send(self(), atom("done"));
receive_loop
// receive two messages
int i = 0;
receive_while([&]() { return ++i <= 2; })
(
on<atom("done")>() >> []()
{
exit(0);
},
// note: we sent a foo_pair2, but match on foo_pair
// that's safe because both are aliases for std::pair<int,int>
on<foo_pair>() >> [](const foo_pair& val)
{
cout << "foo_pair("
......
......@@ -9,6 +9,7 @@ using std::make_pair;
using namespace cppa;
// a simple class using getter and setter member functions
class foo
{
......@@ -35,6 +36,7 @@ class foo
};
// announce requires foo to have the equal operator implemented
bool operator==(const foo& lhs, const foo& rhs)
{
return lhs.a() == rhs.a()
......@@ -43,11 +45,16 @@ bool operator==(const foo& lhs, const foo& rhs)
int main(int, char**)
{
// if a class uses getter and setter member functions,
// we pass those to the announce function as { getter, setter } pairs.
announce<foo>(make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b));
// send a foo to ourselves ...
send(self(), foo{1,2});
receive
(
// ... and receive it
on<foo>() >> [](const foo& val)
{
cout << "foo("
......
......@@ -9,6 +9,7 @@ using std::make_pair;
using namespace cppa;
// a simple class using overloaded getter and setter member functions
class foo
{
......@@ -35,26 +36,43 @@ class foo
};
// announce requires foo to have the equal operator implemented
bool operator==(const foo& lhs, const foo& rhs)
{
return lhs.a() == rhs.a()
&& lhs.b() == rhs.b();
}
// a member function pointer to get an attribute of foo
typedef int (foo::*foo_getter)() const;
// a member function pointer to set an attribute of foo
typedef void (foo::*foo_setter)(int);
int main(int, char**)
{
// since the member function "a" is ambiguous, the compiler
// also needs a type to select the correct overload
foo_getter g1 = &foo::a;
foo_setter s1 = &foo::a;
// same is true for b
foo_getter g2 = &foo::b;
foo_setter s2 = &foo::b;
announce<foo>(make_pair(g1, s1),
make_pair(g2, s2));
// equal to example 3
announce<foo>(make_pair(g1, s1), make_pair(g2, s2));
// alternative syntax that uses casts instead of variables
// (returns false since foo is already announced)
announce<foo>(make_pair(static_cast<foo_getter>(&foo::a),
static_cast<foo_setter>(&foo::a)),
make_pair(static_cast<foo_getter>(&foo::b),
static_cast<foo_setter>(&foo::b)));
// send a foo to ourselves ...
send(self(), foo{1,2});
receive
(
// ... and receive it
on<foo>() >> [](const foo& val)
{
cout << "foo("
......
#include <utility>
#include <iostream>
#include "cppa/cppa.hpp"
#include "cppa/to_string.hpp"
using std::cout;
using std::endl;
......@@ -9,6 +8,7 @@ using std::make_pair;
using namespace cppa;
// the foo class from example 3
class foo
{
......@@ -35,32 +35,88 @@ class foo
};
// needed for operator==() of bar
bool operator==(const foo& lhs, const foo& rhs)
{
return lhs.a() == rhs.a()
&& lhs.b() == rhs.b();
}
// simple struct that has foo as a member
struct bar
{
foo f;
int i;
};
// announce requires bar to have the equal operator implemented
bool operator==(const bar& lhs, const bar& rhs)
{
return lhs.f == rhs.f
&& lhs.i == rhs.i;
}
// "worst case" class ... not a good software design at all ;)
class baz
{
foo m_f;
public:
bar b;
// announce requires a default constructor
baz() = default;
inline baz(const foo& mf, const bar& mb) : m_f(mf), b(mb) { }
const foo& f() const { return m_f; }
void set_f(const foo& val) { m_f = val; }
};
// even worst case classes have to implement operator==
bool operator==(const baz& lhs, const baz& rhs)
{
return lhs.f() == rhs.f()
&& lhs.b == rhs.b;
}
int main(int, char**)
{
// bar has a non-trivial data member f, thus, we have to told
// announce how to serialize/deserialize this member;
// this is was the compound_member function is for;
// it takes a pointer to the non-trivial member as first argument
// followed by all "sub-members" either as member pointer or
// { getter, setter } pair
announce<bar>(compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
&bar::i);
// baz has non-trivial data members with getter/setter pair
// and getter returning a mutable reference
announce<baz>(compound_member(make_pair(&baz::f, &baz::set_f),
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
// compound member that has a compound member
compound_member(&baz::b,
compound_member(&bar::f,
make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)),
&bar::i));
// send a bar to ourselves
send(self(), bar{foo{1,2},3});
receive
// send a baz to ourselves
send(self(), baz{foo{1,2},bar{foo{3,4},5}});
// receive two messages
int i = 0;
receive_while([&]() { return ++i <= 2; })
(
on<bar>() >> [](const bar& val)
{
......@@ -69,7 +125,13 @@ int main(int, char**)
<< val.f.b() << "),"
<< val.i << ")"
<< endl;
},
on<baz>() >> []()
{
// prints: @<> ( { baz ( foo ( 1, 2 ), bar ( foo ( 3, 4 ), 5 ) ) } )
cout << to_string(last_received()) << endl;
}
);
return 0;
}
......
#! /bin/sh
# announce_example_5 - temporary wrapper script for .libs/announce_example_5
# Generated by libtool (GNU libtool) 2.4.2
#
# The announce_example_5 program cannot be directly executed until all the libtool
# libraries that it depends on are installed.
#
# This wrapper script should never be moved out of the build directory.
# If it is, it will not operate correctly.
# Sed substitution that helps us do robust quoting. It backslashifies
# metacharacters that are still active within double-quoted strings.
sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
# Be Bourne compatible
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
# Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
else
case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
fi
BIN_SH=xpg4; export BIN_SH # for Tru64
DUALCASE=1; export DUALCASE # for MKS sh
# The HP-UX ksh and POSIX shell print the target directory to stdout
# if CDPATH is set.
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
relink_command=""
# This environment variable determines our operation mode.
if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
# install mode needs the following variables:
generated_by_libtool_version='2.4.2'
notinst_deplibs=' /Users/neverlord/libcppa/.libs/libcppa.la'
else
# When we are sourced in execute mode, $file and $ECHO are already set.
if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
file="$0"
# A function that is used when there is no print builtin or printf.
func_fallback_echo ()
{
eval 'cat <<_LTECHO_EOF
$1
_LTECHO_EOF'
}
ECHO="printf %s\\n"
fi
# Very basic option parsing. These options are (a) specific to
# the libtool wrapper, (b) are identical between the wrapper
# /script/ and the wrapper /executable/ which is used only on
# windows platforms, and (c) all begin with the string --lt-
# (application programs are unlikely to have options which match
# this pattern).
#
# There are only two supported options: --lt-debug and
# --lt-dump-script. There is, deliberately, no --lt-help.
#
# The first argument to this parsing function should be the
# script's ../libtool value, followed by no.
lt_option_debug=
func_parse_lt_options ()
{
lt_script_arg0=$0
shift
for lt_opt
do
case "$lt_opt" in
--lt-debug) lt_option_debug=1 ;;
--lt-dump-script)
lt_dump_D=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
lt_dump_F=`$ECHO "X$lt_script_arg0" | /usr/bin/sed -e 's/^X//' -e 's%^.*/%%'`
cat "$lt_dump_D/$lt_dump_F"
exit 0
;;
--lt-*)
$ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
exit 1
;;
esac
done
# Print the debug banner immediately:
if test -n "$lt_option_debug"; then
echo "announce_example_5:announce_example_5:${LINENO}: libtool wrapper (GNU libtool) 2.4.2" 1>&2
fi
}
# Used when --lt-debug. Prints its arguments to stdout
# (redirection is the responsibility of the caller)
func_lt_dump_args ()
{
lt_dump_args_N=1;
for lt_arg
do
$ECHO "announce_example_5:announce_example_5:${LINENO}: newargv[$lt_dump_args_N]: $lt_arg"
lt_dump_args_N=`expr $lt_dump_args_N + 1`
done
}
# Core function for launching the target application
func_exec_program_core ()
{
if test -n "$lt_option_debug"; then
$ECHO "announce_example_5:announce_example_5:${LINENO}: newargv[0]: $progdir/$program" 1>&2
func_lt_dump_args ${1+"$@"} 1>&2
fi
exec "$progdir/$program" ${1+"$@"}
$ECHO "$0: cannot exec $program $*" 1>&2
exit 1
}
# A function to encapsulate launching the target application
# Strips options in the --lt-* namespace from $@ and
# launches target application with the remaining arguments.
func_exec_program ()
{
case " $* " in
*\ --lt-*)
for lt_wr_arg
do
case $lt_wr_arg in
--lt-*) ;;
*) set x "$@" "$lt_wr_arg"; shift;;
esac
shift
done ;;
esac
func_exec_program_core ${1+"$@"}
}
# Parse options
func_parse_lt_options "$0" ${1+"$@"}
# Find the directory that this script lives in.
thisdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
test "x$thisdir" = "x$file" && thisdir=.
# Follow symbolic links until we get to the real thisdir.
file=`ls -ld "$file" | /usr/bin/sed -n 's/.*-> //p'`
while test -n "$file"; do
destdir=`$ECHO "$file" | /usr/bin/sed 's%/[^/]*$%%'`
# If there was a directory component, then change thisdir.
if test "x$destdir" != "x$file"; then
case "$destdir" in
[\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
*) thisdir="$thisdir/$destdir" ;;
esac
fi
file=`$ECHO "$file" | /usr/bin/sed 's%^.*/%%'`
file=`ls -ld "$thisdir/$file" | /usr/bin/sed -n 's/.*-> //p'`
done
# Usually 'no', except on cygwin/mingw when embedded into
# the cwrapper.
WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
# special case for '.'
if test "$thisdir" = "."; then
thisdir=`pwd`
fi
# remove .libs from thisdir
case "$thisdir" in
*[\\/].libs ) thisdir=`$ECHO "$thisdir" | /usr/bin/sed 's%[\\/][^\\/]*$%%'` ;;
.libs ) thisdir=. ;;
esac
fi
# Try to get the absolute directory name.
absdir=`cd "$thisdir" && pwd`
test -n "$absdir" && thisdir="$absdir"
program='announce_example_5'
progdir="$thisdir/.libs"
if test -f "$progdir/$program"; then
# Add our own library path to DYLD_LIBRARY_PATH
DYLD_LIBRARY_PATH="/Users/neverlord/libcppa/.libs:$DYLD_LIBRARY_PATH"
# Some systems cannot cope with colon-terminated DYLD_LIBRARY_PATH
# The second colon is a workaround for a bug in BeOS R4 sed
DYLD_LIBRARY_PATH=`$ECHO "$DYLD_LIBRARY_PATH" | /usr/bin/sed 's/::*$//'`
export DYLD_LIBRARY_PATH
if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
# Run the actual program with our arguments.
func_exec_program ${1+"$@"}
fi
else
# The program doesn't exist.
$ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2
$ECHO "This script is just a wrapper for $program." 1>&2
$ECHO "See the libtool documentation for more information." 1>&2
exit 1
fi
fi
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