Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
9944c2be
Commit
9944c2be
authored
Jun 09, 2016
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial commit
parents
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
486 additions
and
0 deletions
+486
-0
.gitmodules
.gitmodules
+3
-0
CMakeLists.txt
CMakeLists.txt
+59
-0
src/main.cpp
src/main.cpp
+423
-0
third_party/pybind
third_party/pybind
+1
-0
No files found.
.gitmodules
0 → 100644
View file @
9944c2be
[submodule "third_party/pybind"]
path = third_party/pybind
url = https://github.com/pybind/pybind11.git
CMakeLists.txt
0 → 100644
View file @
9944c2be
cmake_minimum_required
(
VERSION 2.8
)
project
(
caf_cash CXX
)
# check whether submodules are available
if
(
NOT EXISTS
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/third_party/pybind/CMakeLists.txt"
)
set
(
CAF_NO_PYTHON yes
)
else
()
message
(
STATUS
"try config bin:
${
CAF_PYTHON_CONFIG_BIN
}
"
)
if
(
NOT
"
${
CAF_PYTHON_CONFIG_BIN
}
"
STREQUAL
""
)
execute_process
(
COMMAND
"
${
CAF_PYTHON_CONFIG_BIN
}
"
--includes
OUTPUT_VARIABLE PYTHON_INCLUDE_FLAGS
)
string
(
STRIP
"
${
PYTHON_INCLUDE_FLAGS
}
"
PYTHON_INCLUDE_FLAGS
)
execute_process
(
COMMAND
"
${
CAF_PYTHON_CONFIG_BIN
}
"
--ldflags
OUTPUT_VARIABLE PYTHON_LDFLAGS
)
string
(
STRIP
"
${
PYTHON_LDFLAGS
}
"
PYTHON_LDFLAGS
)
if
(
"
${
LD_FLAGS
}
"
STREQUAL
""
)
set
(
LD_FLAGS
"
${
PYTHON_LDFLAGS
}
"
)
else
()
set
(
LD_FLAGS
"
${
LD_FLAGS
}
${
PYTHON_LDFLAGS
}
"
)
endif
()
string
(
REPLACE
" -I"
";-I"
dir_list
${
PYTHON_INCLUDE_FLAGS
}
)
foreach
(
flag
${
dir_list
}
)
# strip -I from each path
string
(
SUBSTRING
"
${
flag
}
"
2 -1 dir
)
include_directories
(
"
${
dir
}
"
)
endforeach
()
else
()
find_package
(
PythonLibs 3.5
)
if
(
NOT PYTHONLIBS_FOUND
)
message
(
STATUS
"Unable to find Python >= 3.5, disable Python binding"
)
message
(
STATUS
"Set CAF_PYTHON_CONFIG_BIN or use './configure --with-python-conf=...' to use python-conf"
)
set
(
CAF_NO_PYTHON yes
)
else
()
include_directories
(
${
PYTHON_INCLUDE_DIRS
}
)
endif
()
endif
()
endif
()
set
(
CAF_PYTHON_SRCS src/main.cpp
)
set
(
CAF_PYTHON_HDRS
)
# add targets to CMake
if
(
NOT CAF_NO_PYTHON
)
include_directories
(
"
${
CMAKE_CURRENT_SOURCE_DIR
}
"
)
add_executable
(
caf-python
${
CAF_PYTHON_SRCS
}
${
CAF_PYTHON_HDRS
}
)
target_link_libraries
(
caf-python
${
LD_FLAGS
}
${
CAF_LIBRARY_CORE
}
${
CAF_LIBRARY_IO
}
${
CAF_LIBRARY_RIAC
}
${
PTHREAD_LIBRARIES
}
${
LIBEDIT_LIBRARIES
}
${
PYTHON_LIBRARIES
}
)
install
(
PROGRAMS
${
EXECUTABLE_OUTPUT_PATH
}
/caf-python DESTINATION bin
)
else
()
add_custom_target
(
caf-python SOURCES
${
CAF_PYTHON_SRCS
}
${
CAF_PYTHON_HDRS
}
)
endif
()
src/main.cpp
0 → 100644
View file @
9944c2be
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#include <set>
#include <chrono>
#include <thread>
#include <iomanip>
#include <iostream>
#include <functional>
#include <unordered_map>
CAF_PUSH_WARNINGS
#include "third_party/pybind/include/pybind11/pybind11.h"
CAF_POP_WARNINGS
#include "caf/all.hpp"
#include "caf/io/all.hpp"
static_assert
(
PY_MAJOR_VERSION
>
3
||
(
PY_MAJOR_VERSION
==
3
&&
PY_MINOR_VERSION
>=
5
),
"CAF requires Python >= 3.5"
);
using
namespace
caf
;
using
namespace
std
;
constexpr
char
default_banner
[]
=
R"__(
_________ _____ __ __
/ ____/ | / ___// / / /
/ / / /| | \__ \/ /_/ / CAF
/ /___/ ___ |___/ / __ / Shell
\____/_/ |_/____/_/ /_/
)__"
;
namespace
py
=
pybind11
;
namespace
{
class
binding
{
public:
binding
(
std
::
string
python_name
,
std
::
string
portable_name
,
bool
builtin_type
)
:
python_name_
(
std
::
move
(
python_name
)),
portable_name_
(
std
::
move
(
portable_name
)),
builtin_
(
builtin_type
)
{
// nop
}
virtual
~
binding
()
{
//nop
}
inline
void
docstring
(
std
::
string
x
)
{
docstring_
=
std
::
move
(
x
);
}
inline
const
std
::
string
&
docstring
()
const
{
return
portable_name_
;
}
inline
const
std
::
string
&
python_name
()
const
{
return
python_name_
;
}
inline
const
std
::
string
&
portable_name
()
const
{
return
portable_name_
;
}
inline
bool
builtin
()
const
{
return
builtin_
;
}
virtual
void
append
(
message_builder
&
xs
,
py
::
handle
x
)
const
=
0
;
private:
std
::
string
python_name_
;
std
::
string
portable_name_
;
std
::
string
docstring_
;
bool
builtin_
;
};
class
py_binding
:
public
binding
{
public:
py_binding
(
std
::
string
name
)
:
binding
(
name
,
name
,
true
)
{
// nop
}
};
template
<
class
T
>
class
default_py_binding
:
public
py_binding
{
public:
using
py_binding
::
py_binding
;
void
append
(
message_builder
&
xs
,
py
::
handle
x
)
const
override
{
xs
.
append
(
x
.
cast
<
T
>
());
}
};
class
cpp_binding
:
public
binding
{
public:
using
binding
::
binding
;
virtual
void
register_type
(
pybind11
::
module
&
target
)
const
=
0
;
virtual
py
::
object
to_object
(
message
&
xs
,
size_t
pos
)
const
=
0
;
};
template
<
class
T
>
class
default_cpp_binding
:
public
cpp_binding
{
public:
using
cpp_binding
::
cpp_binding
;
void
append
(
message_builder
&
xs
,
py
::
handle
x
)
const
override
{
xs
.
append
(
x
.
cast
<
T
>
());
}
void
register_type
(
pybind11
::
module
&
target
)
const
override
{
py
::
class_
<
T
>
(
target
,
this
->
python_name
().
c_str
())
.
def
(
"__str__"
,
&
default_cpp_binding
::
str_impl
,
this
->
docstring
().
c_str
());
}
py
::
object
to_object
(
message
&
xs
,
size_t
pos
)
const
override
{
printf
(
"to_object %s
\n
"
,
portable_name
().
c_str
());
return
py
::
object
(
py
::
detail
::
type_caster
<
typename
py
::
detail
::
intrinsic_type
<
T
>::
type
>::
cast
(
xs
.
get_as
<
T
>
(
pos
),
py
::
return_value_policy
::
automatic_reference
,
nullptr
),
false
);
}
private:
static
std
::
string
str_impl
(
T
*
ptr
)
{
return
deep_to_string
(
*
ptr
);
}
static
std
::
string
repr_impl
(
T
*
ptr
)
{
}
};
using
binding_ptr
=
std
::
unique_ptr
<
binding
>
;
using
py_binding_ptr
=
std
::
unique_ptr
<
py_binding
>
;
using
cpp_binding_ptr
=
std
::
unique_ptr
<
cpp_binding
>
;
actor_system
*
s_system
;
scoped_actor
*
s_self
;
int
add
(
int
i
,
int
j
)
{
return
i
+
j
;
}
message
receive
()
{
return
message
{};
}
atom_value
atom_from_string
(
const
std
::
string
&
str
)
{
char
buf
[
11
];
strncpy
(
buf
,
str
.
c_str
(),
std
::
min
<
size_t
>
(
10
,
str
.
size
()));
buf
[
10
]
=
'\0'
;
return
atom
(
buf
);
}
std
::
string
atom_to_string
(
atom_value
*
ptr
)
{
return
to_string
(
*
ptr
);
}
std
::
string
message_to_string
(
message
*
ptr
)
{
return
to_string
(
*
ptr
);
}
inline
actor_system
&
system
()
{
CAF_ASSERT
(
s_system
);
return
*
s_system
;
}
class
py_config
:
public
actor_system_config
{
public:
std
::
string
pre_run
;
std
::
string
banner
=
default_banner
;
py_config
()
{
// allow CAF to convert native Python types to C++ types
add_py
<
int
>
(
"int"
);
add_py
<
bool
>
(
"bool"
);
add_py
<
float
>
(
"float"
);
add_py
<
std
::
string
>
(
"str"
);
// create Python bindings for builtin CAF types
add_cpp
<
actor
>
(
"actor"
,
"@actor"
);
add_cpp
<
message
>
(
"message"
,
"@message"
);
add_cpp
<
atom_value
>
(
"atom_value"
,
"@atom"
);
// fill list for native type bindings
add_cpp
<
actor
>
(
"bool"
,
"bool"
,
true
);
add_cpp
<
int32_t
>
(
"int32_t"
,
"@i32"
,
true
);
add_cpp
<
std
::
string
>
(
"str"
,
"@str"
,
true
);
}
template
<
class
T
>
actor_system_config
&
add_message_type
(
std
::
string
name
)
{
add_cpp
<
T
>
(
name
,
name
);
actor_system_config
::
add_message_type
<
T
>
(
std
::
move
(
name
));
}
void
py_init
(
py
::
module
&
x
)
const
{
for
(
auto
&
kvp
:
cpp_bindings_
)
if
(
!
kvp
.
second
->
builtin
())
kvp
.
second
->
register_type
(
x
);
}
std
::
string
ipython_script
()
const
{
// prepare preload script by formatting it with <space><space>'...'
std
::
vector
<
std
::
string
>
lines
;
split
(
lines
,
pre_run
,
is_any_of
(
"
\n
"
),
token_compress_on
);
for
(
auto
&
line
:
lines
)
{
line
.
insert
(
0
,
" '"
);
line
+=
"'"
;
}
std
::
ostringstream
oss
;
oss
<<
"import IPython"
<<
endl
<<
"c = IPython.Config()"
<<
endl
<<
"c.InteractiveShellApp.exec_lines = ["
<<
endl
<<
join
(
lines
,
"
\n
"
)
<<
endl
<<
"]"
<<
endl
<<
"c.PromptManager.in_template = ' $: '"
<<
endl
<<
"c.PromptManager.in2_template = ' -> '"
<<
endl
<<
"c.PromptManager.out_template = ' >> '"
<<
endl
<<
"c.display_banner = True"
<<
endl
<<
"c.TerminalInteractiveShell.banner1 =
\"\"\"
"
<<
endl
<<
banner
<<
endl
<<
"
\"\"\"
"
<<
endl
<<
"IPython.start_ipython(config=c)"
<<
endl
;
return
oss
.
str
();
}
const
std
::
unordered_map
<
std
::
string
,
binding
*>&
bindings
()
const
{
return
bindings_
;
}
const
std
::
unordered_map
<
std
::
string
,
cpp_binding
*>&
portable_bindings
()
const
{
return
portable_bindings_
;
}
const
std
::
unordered_map
<
std
::
string
,
cpp_binding_ptr
>&
cpp_bindings
()
const
{
return
cpp_bindings_
;
}
private:
template
<
class
T
>
void
add_py
(
std
::
string
name
)
{
auto
ptr
=
new
default_py_binding
<
T
>
(
name
);
py_bindings_
.
emplace
(
name
,
py_binding_ptr
{
ptr
});
bindings_
.
emplace
(
std
::
move
(
name
),
ptr
);
}
template
<
class
T
>
void
add_cpp
(
std
::
string
py_name
,
std
::
string
cpp_name
,
bool
builtin
=
false
)
{
auto
ptr
=
new
default_cpp_binding
<
T
>
(
py_name
,
cpp_name
,
builtin
);
// all type names are prefix with "CAF."
py_name
.
insert
(
0
,
"CAF."
);
cpp_bindings_
.
emplace
(
py_name
,
cpp_binding_ptr
{
ptr
});
bindings_
.
emplace
(
std
::
move
(
py_name
),
ptr
);
portable_bindings_
.
emplace
(
std
::
move
(
cpp_name
),
ptr
);
}
std
::
unordered_map
<
std
::
string
,
cpp_binding
*>
portable_bindings_
;
std
::
unordered_map
<
std
::
string
,
binding
*>
bindings_
;
std
::
unordered_map
<
std
::
string
,
cpp_binding_ptr
>
cpp_bindings_
;
std
::
unordered_map
<
std
::
string
,
py_binding_ptr
>
py_bindings_
;
};
struct
py_context
{
const
py_config
&
cfg
;
actor_system
&
system
;
scoped_actor
&
self
;
};
py_context
*
s_context
;
inline
void
set_py_exception_fill
(
std
::
ostream
&
)
{
// end of recursion
}
template
<
class
T
,
class
...
Ts
>
void
set_py_exception_fill
(
std
::
ostream
&
oss
,
T
&&
x
,
Ts
&&
...
xs
)
{
set_py_exception_fill
(
oss
<<
std
::
forward
<
T
>
(
x
),
std
::
forward
<
Ts
>
(
xs
)...);
}
template
<
class
...
Ts
>
void
set_py_exception
(
Ts
&&
...
xs
)
{
std
::
ostringstream
oss
;
set_py_exception_fill
(
oss
,
std
::
forward
<
Ts
>
(
xs
)...);
PyErr_SetString
(
PyExc_RuntimeError
,
oss
.
str
().
c_str
());
}
void
py_send
(
py
::
args
xs
)
{
if
(
xs
.
size
()
<
2
)
{
set_py_exception
(
"Too few arguments to call CAF.send"
);
return
;
}
auto
i
=
xs
.
begin
();
auto
dest
=
(
*
i
).
cast
<
actor
>
();
++
i
;
message_builder
mb
;
auto
&
bindings
=
s_context
->
cfg
.
bindings
();
for
(;
i
!=
xs
.
end
();
++
i
)
{
std
::
string
type_name
=
PyEval_GetFuncName
((
*
i
).
ptr
());
auto
kvp
=
bindings
.
find
(
type_name
);
if
(
kvp
==
bindings
.
end
())
{
set_py_exception
(
"Unable to add element of type
\"
"
,
type_name
,
"
\"
to message: type is unknown to CAF"
);
return
;
}
kvp
->
second
->
append
(
mb
,
*
i
);
}
s_context
->
self
->
send
(
dest
,
mb
.
move_to_message
());
}
py
::
tuple
py_receive
()
{
auto
&
self
=
s_context
->
self
;
self
->
await_data
();
auto
ptr
=
self
->
next_message
();
auto
&
msg
=
ptr
->
msg
;
auto
&
bindings
=
s_context
->
cfg
.
portable_bindings
();
py
::
tuple
result
(
msg
.
size
());
for
(
size_t
i
=
0
;
i
<
msg
.
size
();
++
i
)
{
auto
rtti
=
msg
.
type
(
i
);
auto
str_ptr
=
self
->
system
().
types
().
portable_name
(
rtti
);
if
(
!
str_ptr
)
{
set_py_exception
(
"Unable to extract element #"
,
i
,
" from message: "
,
"could not get portable name of "
,
rtti
.
second
->
name
());
return
{};
}
auto
kvp
=
bindings
.
find
(
*
str_ptr
);
if
(
kvp
==
bindings
.
end
())
{
set_py_exception
(
"Unable to add element of type
\"
"
,
*
str_ptr
,
"
\"
to message: type is unknown to CAF"
);
return
{};
}
auto
obj
=
kvp
->
second
->
to_object
(
msg
,
i
);
PyTuple_SET_ITEM
(
result
.
ptr
(),
static_cast
<
int
>
(
i
),
obj
.
release
().
ptr
());
}
return
result
;
}
actor
py_self
()
{
return
s_context
->
self
;
}
class
config
:
public
py_config
{
public:
std
::
string
py_file
;
config
()
{
pre_run
=
"from CAF import *"
;
opt_group
{
custom_options_
,
"global"
}
.
add
(
py_file
,
"file,f"
,
"Run script instead of interactive shell."
);
}
};
PyObject
*
caf_module_init
()
{
py
::
module
m
(
"CAF"
,
"Python binding for CAF"
);
s_context
->
cfg
.
py_init
(
m
);
// add classes
// add free functions
m
.
def
(
"add"
,
&
add
,
"A function which adds two numbers"
)
.
def
(
"send"
,
&
py_send
,
"Sends a message to an actor"
)
.
def
(
"receive"
,
&
py_receive
,
"Receives the next message"
)
.
def
(
"self"
,
&
py_self
,
"Returns the global self handle"
)
.
def
(
"atom"
,
&
atom_from_string
,
"Creates an atom from a string"
);
return
m
.
ptr
();
}
}
// namespace <anonymous>
void
caf_main
(
actor_system
&
system
,
const
config
&
cfg
)
{
// register system and scoped actor in global variables
scoped_actor
self
{
system
};
py_context
ctx
{
cfg
,
system
,
self
};
s_context
=
&
ctx
;
// init Python
PyImport_AppendInittab
(
"CAF"
,
caf_module_init
);
Py_Initialize
();
// create Python module for CAF
int
py_res
=
0
;
if
(
!
cfg
.
py_file
.
empty
())
{
auto
fp
=
fopen
(
cfg
.
py_file
.
c_str
()
,
"r"
);
if
(
!
fp
)
{
cerr
<<
"Unable to open file "
<<
cfg
.
py_file
<<
endl
;
Py_Finalize
();
return
;
}
py_res
=
PyRun_SimpleString
(
cfg
.
pre_run
.
c_str
());
if
(
py_res
==
0
)
py_res
=
PyRun_SimpleFileEx
(
fp
,
cfg
.
py_file
.
c_str
(),
1
);
}
else
{
auto
script
=
cfg
.
ipython_script
();
py_res
=
PyRun_SimpleString
(
script
.
c_str
());
}
if
(
py_res
!=
0
)
{
cerr
<<
"Unable to launch interactive Python shell!"
<<
endl
<<
"Please install it using: pip install ipython"
<<
endl
;
}
Py_Finalize
();
}
CAF_MAIN
()
pybind
@
19d95ef0
Subproject commit 19d95ef09a384d6631308161ead24e5a230c9bf8
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment