summaryrefslogtreecommitdiff
path: root/python/gras/GRAS_PyBlock.i
diff options
context:
space:
mode:
Diffstat (limited to 'python/gras/GRAS_PyBlock.i')
-rw-r--r--python/gras/GRAS_PyBlock.i321
1 files changed, 321 insertions, 0 deletions
diff --git a/python/gras/GRAS_PyBlock.i b/python/gras/GRAS_PyBlock.i
new file mode 100644
index 0000000..a588a88
--- /dev/null
+++ b/python/gras/GRAS_PyBlock.i
@@ -0,0 +1,321 @@
+// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information.
+
+////////////////////////////////////////////////////////////////////////
+// SWIG director shit - be explicit with all virtual methods
+////////////////////////////////////////////////////////////////////////
+%module(directors="1") GRAS_Block
+%feature("director") gras::BlockPython;
+%feature("nodirector") gras::BlockPython::input_buffer_allocator;
+%feature("nodirector") gras::BlockPython::output_buffer_allocator;
+%feature("nodirector") gras::BlockPython::propagate_tags;
+%feature("nodirector") gras::BlockPython::notify_active;
+%feature("nodirector") gras::BlockPython::notify_inactive;
+%feature("nodirector") gras::BlockPython::notify_topology;
+%feature("nodirector") gras::BlockPython::work;
+%feature("nodirector") gras::BlockPython::_handle_prop_access;
+
+////////////////////////////////////////////////////////////////////////
+// http://www.swig.org/Doc2.0/Library.html#Library_stl_exceptions
+////////////////////////////////////////////////////////////////////////
+%include <exception.i>
+
+%exception
+{
+ try
+ {
+ $action
+ }
+ catch (const Swig::DirectorException &e)
+ {
+ SWIG_fail;
+ }
+ catch (const std::exception& e)
+ {
+ SWIG_exception(SWIG_RuntimeError, e.what());
+ }
+}
+
+%feature("director:except")
+{
+ if ($error != NULL)
+ {
+ throw Swig::DirectorMethodException();
+ }
+}
+
+%{
+#include <gras/block.hpp>
+%}
+
+////////////////////////////////////////////////////////////////////////
+// SWIG up the representation for IO work arrays
+////////////////////////////////////////////////////////////////////////
+%include <std_vector.i>
+%template () std::vector<size_t>;
+%template () std::vector<void *>;
+
+////////////////////////////////////////////////////////////////////////
+// Pull in the implementation goodies
+////////////////////////////////////////////////////////////////////////
+%import <gras/element.i>
+%import <gras/tags.i>
+%include <gras/tag_iter.i>
+%import <gras/block.i>
+
+%include "GRAS_Utils.i"
+
+////////////////////////////////////////////////////////////////////////
+// Make a special block with safe overloads
+////////////////////////////////////////////////////////////////////////
+%inline %{
+
+namespace gras
+{
+
+struct BlockPython : Block
+{
+ BlockPython(const std::string &name):
+ Block(name)
+ {
+ //NOP
+ }
+
+ virtual ~BlockPython(void)
+ {
+ PyTSPhondler phil;
+ this->reset();
+ }
+
+ void notify_active(void)
+ {
+ PyGILPhondler phil;
+ return this->_Py_notify_active();
+ }
+
+ virtual void _Py_notify_active(void) = 0;
+
+ void notify_inactive(void)
+ {
+ PyGILPhondler phil;
+ return this->_Py_notify_inactive();
+ }
+
+ virtual void _Py_notify_inactive(void) = 0;
+
+ void notify_topology(const size_t num_inputs, const size_t num_outputs)
+ {
+ _input_addrs.resize(num_inputs);
+ _input_sizes.resize(num_inputs);
+ _output_addrs.resize(num_outputs);
+ _output_sizes.resize(num_outputs);
+
+ PyGILPhondler phil;
+ return this->_Py_notify_topology(num_inputs, num_outputs);
+ }
+
+ virtual void _Py_notify_topology(const size_t, const size_t) = 0;
+
+ void work
+ (
+ const InputItems &input_items,
+ const OutputItems &output_items
+ )
+ {
+ for (size_t i = 0; i < input_items.size(); i++)
+ {
+ _input_addrs[i] = (void *)(input_items[i].get());
+ _input_sizes[i] = input_items[i].size();
+ }
+
+ for (size_t i = 0; i < output_items.size(); i++)
+ {
+ _output_addrs[i] = (void *)(output_items[i].get());
+ _output_sizes[i] = output_items[i].size();
+ }
+
+ PyGILPhondler phil;
+ return this->_Py_work(_input_addrs, _input_sizes, _output_addrs, _output_sizes);
+ }
+
+ std::vector<void *> _input_addrs;
+ std::vector<size_t> _input_sizes;
+ std::vector<void *> _output_addrs;
+ std::vector<size_t> _output_sizes;
+
+ virtual void _Py_work
+ (
+ const std::vector<void *> &,
+ const std::vector<size_t> &,
+ const std::vector<void *> &,
+ const std::vector<size_t> &
+ ) = 0;
+
+ void propagate_tags(const size_t which_input, const TagIter &iter)
+ {
+ PyGILPhondler phil;
+ return this->_Py_propagate_tags(which_input, iter);
+ }
+
+ virtual void _Py_propagate_tags(const size_t which_input, const TagIter &iter) = 0;
+
+ void _set_property(const std::string &key, const PMCC &value)
+ {
+ PyTSPhondler phil;
+ return Block::_set_property(key, value);
+ }
+
+ PMCC _get_property(const std::string &key)
+ {
+ PyTSPhondler phil;
+ return Block::_get_property(key);
+ }
+
+ PMCC _handle_prop_access(const std::string &key, const PMCC &value, const bool set)
+ {
+ PyGILPhondler phil;
+ return this->_Py_handle_prop_access(key, value, set);
+ }
+
+ virtual PMCC _Py_handle_prop_access(const std::string &key, const PMCC &value, const bool set) = 0;
+
+ void dummy_setter(const PMCC &)
+ {
+ //NOP
+ }
+ PMCC dummy_getter(void)
+ {
+ return PMC();
+ }
+
+ void _Py_register_dummy_setter(const std::string &key)
+ {
+ this->register_setter(key, &BlockPython::dummy_setter);
+ }
+
+ void _Py_register_dummy_getter(const std::string &key)
+ {
+ this->register_getter(key, &BlockPython::dummy_getter);
+ }
+
+};
+
+}
+
+%}
+
+////////////////////////////////////////////////////////////////////////
+// Python overload for adding pythonic interfaces
+////////////////////////////////////////////////////////////////////////
+%pythoncode %{
+
+import numpy
+import traceback
+from GRAS_Utils import pointer_to_ndarray
+from PMC import *
+
+def sig_to_dtype_sig(sig):
+ if sig is None: sig = ()
+ return map(numpy.dtype, sig)
+
+class PyBlock(BlockPython):
+ def __init__(self, name='Block', in_sig=None, out_sig=None):
+ BlockPython.__init__(self, name)
+ self.set_input_signature(in_sig)
+ self.set_output_signature(out_sig)
+ self.__getter_registry = dict()
+ self.__setter_registry = dict()
+
+ def set_input_signature(self, sig):
+ self.__in_sig = sig_to_dtype_sig(sig)
+ for i, n in enumerate(self.__in_sig): self.input_config(i).item_size = n.itemsize
+
+ def set_output_signature(self, sig):
+ self.__out_sig = sig_to_dtype_sig(sig)
+ for i, n in enumerate(self.__out_sig): self.output_config(i).item_size = n.itemsize
+
+ def input_signature(self): return self.__in_sig
+ def output_signature(self): return self.__out_sig
+
+ def _Py_work(self, input_addrs, input_sizes, output_addrs, output_sizes):
+
+ try:
+
+ input_arrays = list()
+ for i in self.__in_indexes:
+ addr = long(input_addrs[i])
+ nitems = input_sizes[i]
+ ndarray = pointer_to_ndarray(addr=addr, dtype=self.__in_sig[i], nitems=nitems, readonly=True)
+ input_arrays.append(ndarray)
+
+ output_arrays = list()
+ for i in self.__out_indexes:
+ addr = long(output_addrs[i])
+ nitems = output_sizes[i]
+ ndarray = pointer_to_ndarray(addr=addr, dtype=self.__out_sig[i], nitems=nitems, readonly=False)
+ output_arrays.append(ndarray)
+
+ ret = self.work(input_arrays, output_arrays)
+ if ret is not None:
+ raise Exception, 'work return != None, did you call consume/produce?'
+ except: traceback.print_exc(); raise
+
+ def work(self, *args):
+ print 'Implement Work!'
+
+ def _Py_notify_topology(self, num_inputs, num_outputs):
+
+ #extend input signature from back to match topology
+ while len(self.__in_sig) < num_inputs:
+ self.__in_sig.append(self.__in_sig[-1])
+
+ #extend output signature from back to match topology
+ while len(self.__out_sig) < num_outputs:
+ self.__out_sig.append(self.__out_sig[-1])
+
+ self.__in_indexes = range(num_inputs)
+ self.__out_indexes = range(num_outputs)
+ try: return self.notify_topology(num_inputs, num_outputs)
+ except: traceback.print_exc(); raise
+
+ def notify_topology(self, *args): return
+
+ def _Py_notify_active(self):
+ try: return self.notify_active()
+ except: traceback.print_exc(); raise
+
+ def notify_active(self): pass
+
+ def _Py_notify_inactive(self):
+ try: return self.notify_inactive()
+ except: traceback.print_exc(); raise
+
+ def notify_inactive(self): pass
+
+ def _Py_propagate_tags(self, which_input, iter):
+ try: return self.propagate_tags(which_input, iter)
+ except: traceback.print_exc(); raise
+
+ def propagate_tags(self, i, iter):
+ for o in self.__out_indexes:
+ for t in iter:
+ t.offset += self.get_produced(o)
+ t.offset -= self.get_consumed(i)
+ self.post_output_tag(o, t)
+
+ def _Py_handle_prop_access(self, key, value, set):
+ if set:
+ setter = self.__setter_registry[key]
+ setter(value())
+ return PMCC()
+ else:
+ getter = self.__getter_registry[key]
+ return PMC_M(getter())
+
+ def register_getter(self, key, getter):
+ self._Py_register_dummy_getter(key)
+ self.__getter_registry[key] = getter
+
+ def register_setter(self, key, setter):
+ self._Py_register_dummy_setter(key)
+ self.__setter_registry[key] = setter
+%}