Skip to content
Snippets Groups Projects
Commit ecf5a859 authored by Carsten Gräser's avatar Carsten Gräser
Browse files

Add class Callable that encapsulates callable function objects

This class implements the various call() method that have been
on Reference before. Notice that these will be removed
from Reference.
parent e29231b5
Branches
Tags
No related merge requests found
install(FILES
callable.hh
common.hh
conversion.hh
function.hh
......
......@@ -5,6 +5,7 @@ SUBDIRS =
pythondir = $(includedir)/dune/fufem/python
python_HEADERS = \\
callable.hh \\
common.hh \\
conversion.hh \\
function.hh \\
......
// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set ts=8 sw=4 et sts=4:
#ifndef DUNE_FUFEM_PYTHON_CALLABLE_HH
#define DUNE_FUFEM_PYTHON_CALLABLE_HH
// Only introduce the dune-python interface if python
// was found and enabled.
#if HAVE_PYTHON
#include <Python.h>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <dune/common/exceptions.hh>
#include <dune/common/shared_ptr.hh>
#include <dune/common/fvector.hh>
#include <dune/common/function.hh>
#include <dune/common/parametertree.hh>
#include <dune/common/typetraits.hh>
#include <dune/grid/common/gridfactory.hh>
#include <dune/fufem/functions/virtualfunctiontoboundarysegmentadapter.hh>
#include <dune/fufem/formatstring.hh>
#include <dune/fufem/python/reference.hh>
namespace Python
{
// forward declarations
void handlePythonError(const std::string&, const std::string&);
/**
* \brief Wrapper class for callable python objects
*
* This class derives from Python::Reference and
* encapsulates functionality of callable objects.
*/
class Callable :
public Reference
{
public:
/**
* \brief Construct empty Callable
*/
Callable() :
Reference()
{}
/**
* \brief Construct Callable from PyObject*
*
* Only to be used if you want to extend the interface
* using the python api.
*
* This forwards to the corresponding constructor of Reference
* and then checks if the python object is callable. If this is
* not the case an exception is thrown. As a consequence the
* reference count of the PyObject will be correctly decreased by
* ~Reference even if the exception is thrown.
*
* But be carefull to always increment the count of a borrowed
* reference BEFORE calling this constructor. I.e. always use
*
* Callable(Imp::inc(p))
*
* instead of
*
* Imp::inc(Callable(p))
*
* The latter may throw an exception and then decrease the count
* before it is increased.
*
*/
Callable(PyObject* p) :
Reference(p)
{
assertCallable(p_, "Callable(PyObject*)");
}
/**
* \brief Construct Callable from Reference
*
* This checks if the python object is callable. If this is
* not the case an exception is thrown.
*
* For implementors:
*
* This will increment the count for the
* stored reference.
*/
Callable(const Reference& other) :
Reference(other)
{
assertCallable(p_, "Callable(Reference&)");
}
/**
* \brief Destructor
*/
virtual ~Callable()
{}
/**
* \brief Assignment
*
* This will checks if the python object is a module.
* If this is not the case an exception is thrown.
*/
virtual Callable& operator= (const Reference& other)
{
assertCallable(other, "Callable::operator=(Reference&)");
Reference::operator=(other);
return *this;
}
/**
* \brief Call this Reference with arguments given as tuple
*
* If the Reference represents a function it's called.
* If the Reference represents an instance its __call__ method is invoked.
* If the Reference represents a class a constructor is invoked.
* In any case the arguments are given as a tuple as obtained by the
* global method Python::makeTuple().
*
* Although the method is const it might change the refered object!
* This cannot be avoided since the python api does not know
* about const pointers so we use a mutable pointer internally.
*
* \param args Arguments represented as tuple
* \returns The result of the call
*
*/
Reference callWithArgumentTuple(const Reference& args) const
{
assertPyObject("Callable::callWithArgumentTuple()");
PyObject* result = PyObject_CallObject(p_, args);
if (not result)
handlePythonError("Callable::callWithArgumentTuple()", "failed to call object");
return result;
}
Reference call(const Reference& args) const DUNE_DEPRECATED
{
return callWithArgumentTuple(args);
}
/**
* \brief Call this object without arguments
*
* Shortcut for callWithArgumentTuple(makeTuple()).
*/
Reference operator() () const
{
return callWithArgumentTuple(makeTuple());
}
/**
* \brief Call this object with one argument
*
* Shortcut for callWithArgumentTuple(makeTuple(t0)).
*/
template<class T0>
Reference operator() (const T0& t0) const
{
return callWithArgumentTuple(makeTuple(t0));
}
/**
* \brief Call this object with two argument
*
* Shortcut for callWithArgumentTuple(makeTuple(t0,t1)).
*/
template<class T0, class T1>
Reference operator() (const T0& t0, const T1& t1) const
{
return callWithArgumentTuple(makeTuple(t0, t1));
}
/**
* \brief Call this object with three argument
*
* Shortcut for callWithArgumentTuple(makeTuple(t0,t1,t2)).
*/
template<class T0, class T1, class T2>
Reference operator() (const T0& t0, const T1& t1, const T2& t2) const
{
return callWithArgumentTuple(makeTuple(t0, t1, t2));
}
protected:
/**
* \brief Assert that internal PyObject* is not NULL and callable and raise exception otherwise
*
* \param origin A string describing the origin of the error
*/
static void assertCallable(PyObject* p, const std::string& origin)
{
if (p and (not PyCallable_Check(p)))
DUNE_THROW(Dune::Exception,
"Python error occured." << std::endl <<
" Origin: " << origin << std::endl <<
" Error: Trying to use a non-callable as callable");
}
};
}; // end of namespace Python
#else
#warning dunepython.hh was included but python was not found or enabled!
#endif // DUNE_FUFEM_PYTHON_CALLABLE_HH
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment