Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/python/src/object/function.cpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 22.6 KB
Line 
1// Copyright David Abrahams 2001.
2// Distributed under the Boost Software License, Version 1.0. (See
3// accompanying file LICENSE_1_0.txt or copy at
4// http://www.boost.org/LICENSE_1_0.txt)
5
6#include <boost/python/docstring_options.hpp>
7#include <boost/python/object/function_object.hpp>
8#include <boost/python/object/function_handle.hpp>
9#include <boost/python/errors.hpp>
10#include <boost/python/str.hpp>
11#include <boost/python/object_attributes.hpp>
12#include <boost/python/args.hpp>
13#include <boost/python/refcount.hpp>
14#include <boost/python/extract.hpp>
15#include <boost/python/tuple.hpp>
16#include <boost/python/list.hpp>
17#include <boost/python/ssize_t.hpp>
18
19#include <boost/python/detail/signature.hpp>
20#include <boost/mpl/vector/vector10.hpp>
21
22#include <boost/bind.hpp>
23
24#include <algorithm>
25#include <cstring>
26
27#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES
28# include <cstdio>
29#endif
30
31namespace boost { namespace python {
32  volatile bool docstring_options::show_user_defined_ = true;
33  volatile bool docstring_options::show_signatures_ = true;
34}}
35
36namespace boost { namespace python { namespace objects { 
37
38py_function_impl_base::~py_function_impl_base()
39{
40}
41
42unsigned py_function_impl_base::max_arity() const
43{
44    return this->min_arity();
45}
46
47extern PyTypeObject function_type;
48
49function::function(
50    py_function const& implementation
51#if BOOST_WORKAROUND(__EDG_VERSION__, == 245)
52    , python::detail::keyword const*       names_and_defaults
53#else
54    , python::detail::keyword const* const names_and_defaults
55#endif
56    , unsigned num_keywords
57    )
58    : m_fn(implementation)
59    , m_nkeyword_values(0)
60{
61    if (names_and_defaults != 0)
62    {
63        unsigned int max_arity = m_fn.max_arity();
64        unsigned int keyword_offset
65            = max_arity > num_keywords ? max_arity - num_keywords : 0;
66
67
68        ssize_t tuple_size = num_keywords ? max_arity : 0;
69        m_arg_names = object(handle<>(PyTuple_New(tuple_size)));
70
71        if (num_keywords != 0)
72        {
73            for (unsigned j = 0; j < keyword_offset; ++j)
74                PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None));
75        }
76       
77        for (unsigned i = 0; i < num_keywords; ++i)
78        {
79            tuple kv;
80
81            python::detail::keyword const* const p = names_and_defaults + i;
82            if (p->default_value)
83            {
84                kv = make_tuple(p->name, p->default_value);
85                ++m_nkeyword_values;
86            }
87            else
88            {
89                kv = make_tuple(p->name);
90            }
91
92            PyTuple_SET_ITEM(
93                m_arg_names.ptr()
94                , i + keyword_offset
95                , incref(kv.ptr())
96                );
97        }
98    }
99   
100    PyObject* p = this;
101    if (function_type.ob_type == 0)
102    {
103        function_type.ob_type = &PyType_Type;
104        ::PyType_Ready(&function_type);
105    }
106   
107    (void)(     // warning suppression for GCC
108        PyObject_INIT(p, &function_type)
109    );
110}
111
112function::~function()
113{
114}
115
116PyObject* function::call(PyObject* args, PyObject* keywords) const
117{
118    std::size_t n_unnamed_actual = PyTuple_GET_SIZE(args);
119    std::size_t n_keyword_actual = keywords ? PyDict_Size(keywords) : 0;
120    std::size_t n_actual = n_unnamed_actual + n_keyword_actual;
121   
122    function const* f = this;
123
124    // Try overloads looking for a match
125    do
126    {
127        // Check for a plausible number of arguments
128        unsigned min_arity = f->m_fn.min_arity();
129        unsigned max_arity = f->m_fn.max_arity();
130
131        if (n_actual + f->m_nkeyword_values >= min_arity
132            && n_actual <= max_arity)
133        {
134            // This will be the args that actually get passed
135            handle<>inner_args(allow_null(borrowed(args)));
136
137            if (n_keyword_actual > 0      // Keyword arguments were supplied
138                 || n_actual < min_arity) // or default keyword values are needed
139            {                           
140                if (f->m_arg_names.ptr() == Py_None) 
141                {
142                    // this overload doesn't accept keywords
143                    inner_args = handle<>();
144                }
145                else
146                {
147                    // "all keywords are none" is a special case
148                    // indicating we will accept any number of keyword
149                    // arguments
150                    if (PyTuple_Size(f->m_arg_names.ptr()) == 0)
151                    {
152                        // no argument preprocessing
153                    }
154                    else if (n_actual > max_arity)
155                    {
156                        // too many arguments
157                        inner_args = handle<>();
158                    }
159                    else
160                    {
161                        // build a new arg tuple, will adjust its size later
162                        assert(max_arity <= ssize_t_max);
163                        inner_args = handle<>(
164                            PyTuple_New(static_cast<ssize_t>(max_arity)));
165
166                        // Fill in the positional arguments
167                        for (std::size_t i = 0; i < n_unnamed_actual; ++i)
168                            PyTuple_SET_ITEM(inner_args.get(), i, incref(PyTuple_GET_ITEM(args, i)));
169
170                        // Grab remaining arguments by name from the keyword dictionary
171                        std::size_t n_actual_processed = n_unnamed_actual;
172               
173                        for (std::size_t arg_pos = n_unnamed_actual; arg_pos < max_arity ; ++arg_pos)
174                        {
175                            // Get the keyword[, value pair] corresponding
176                            PyObject* kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos);
177
178                            // If there were any keyword arguments,
179                            // look up the one we need for this
180                            // argument position
181                            PyObject* value = n_keyword_actual
182                                ? PyDict_GetItem(keywords, PyTuple_GET_ITEM(kv, 0))
183                                : 0;
184
185                            if (!value)
186                            {
187                                // Not found; check if there's a default value
188                                if (PyTuple_GET_SIZE(kv) > 1)
189                                    value = PyTuple_GET_ITEM(kv, 1);
190                       
191                                if (!value)
192                                {
193                                    // still not found; matching fails
194                                    PyErr_Clear();
195                                    inner_args = handle<>();
196                                    break;
197                                }
198                            }
199                            else
200                            {
201                                ++n_actual_processed;
202                            }
203
204                            PyTuple_SET_ITEM(inner_args.get(), arg_pos, incref(value));
205                        }
206
207                        if (inner_args.get())
208                        {
209                            //check if we proccessed all the arguments
210                            if(n_actual_processed < n_actual)
211                                inner_args = handle<>();
212                        }
213                    }
214                }
215            }
216           
217            // Call the function.  Pass keywords in case it's a
218            // function accepting any number of keywords
219            PyObject* result = inner_args ? f->m_fn(inner_args.get(), keywords) : 0;
220           
221            // If the result is NULL but no error was set, m_fn failed
222            // the argument-matching test.
223
224            // This assumes that all other error-reporters are
225            // well-behaved and never return NULL to python without
226            // setting an error.
227            if (result != 0 || PyErr_Occurred())
228                return result;
229        }
230        f = f->m_overloads.get();
231    }
232    while (f);
233    // None of the overloads matched; time to generate the error message
234    argument_error(args, keywords);
235    return 0;
236}
237
238object function::signature(bool show_return_type) const
239{
240    py_function const& impl = m_fn;
241   
242    python::detail::signature_element const* return_type = impl.signature();
243    python::detail::signature_element const* s = return_type + 1;
244   
245    list formal_params;
246    if (impl.max_arity() == 0)
247        formal_params.append("void");
248
249    for (unsigned n = 0; n < impl.max_arity(); ++n)
250    {
251        if (s[n].basename == 0)
252        {
253            formal_params.append("...");
254            break;
255        }
256
257        str param(s[n].basename);
258        if (s[n].lvalue)
259            param += " {lvalue}";
260       
261        if (m_arg_names) // None or empty tuple will test false
262        {
263            object kv(m_arg_names[n]);
264            if (kv)
265            {
266                char const* const fmt = len(kv) > 1 ? " %s=%r" : " %s";
267                param += fmt % kv;
268            }
269        }
270       
271        formal_params.append(param);
272    }
273
274    if (show_return_type)
275        return "%s(%s) -> %s" % make_tuple(
276            m_name, str(", ").join(formal_params), return_type->basename);
277    return "%s(%s)" % make_tuple(
278        m_name, str(", ").join(formal_params));
279}
280
281object function::signatures(bool show_return_type) const
282{
283    list result;
284    for (function const* f = this; f; f = f->m_overloads.get()) {
285        result.append(f->signature(show_return_type));
286    }
287    return result;
288}
289
290void function::argument_error(PyObject* args, PyObject* /*keywords*/) const
291{
292    static handle<> exception(
293        PyErr_NewException("Boost.Python.ArgumentError", PyExc_TypeError, 0));
294
295    object message = "Python argument types in\n    %s.%s("
296        % make_tuple(this->m_namespace, this->m_name);
297   
298    list actual_args;
299    for (ssize_t i = 0; i < PyTuple_Size(args); ++i)
300    {
301        char const* name = PyTuple_GetItem(args, i)->ob_type->tp_name;
302        actual_args.append(str(name));
303    }
304    message += str(", ").join(actual_args);
305    message += ")\ndid not match C++ signature:\n    ";
306    message += str("\n    ").join(signatures());
307
308#if BOOST_PYTHON_DEBUG_ERROR_MESSAGES
309    std::printf("\n--------\n%s\n--------\n", extract<const char*>(message)());
310#endif
311    PyErr_SetObject(exception.get(), message.ptr());
312    throw_error_already_set();
313}
314
315void function::add_overload(handle<function> const& overload_)
316{
317    function* parent = this;
318   
319    while (parent->m_overloads)
320        parent = parent->m_overloads.get();
321
322    parent->m_overloads = overload_;
323
324    // If we have no documentation, get the docs from the overload
325    if (!m_doc)
326        m_doc = overload_->m_doc;
327}
328
329namespace
330{
331  char const* const binary_operator_names[] =
332  {
333      "add__",
334      "and__",
335      "div__",
336      "divmod__",
337      "eq__",
338      "floordiv__",
339      "ge__",
340      "gt__",
341      "le__",
342      "lshift__",
343      "lt__",
344      "mod__",
345      "mul__",
346      "ne__",
347      "or__",
348      "pow__",
349      "radd__",
350      "rand__",
351      "rdiv__",
352      "rdivmod__", 
353      "rfloordiv__",
354      "rlshift__",
355      "rmod__",
356      "rmul__",
357      "ror__",
358      "rpow__", 
359      "rrshift__",
360      "rshift__",
361      "rsub__",
362      "rtruediv__",
363      "rxor__",
364      "sub__",
365      "truediv__", 
366      "xor__"
367  };
368
369  struct less_cstring
370  {
371      bool operator()(char const* x, char const* y) const
372      {
373          return BOOST_CSTD_::strcmp(x,y) < 0;
374      }
375  };
376 
377  inline bool is_binary_operator(char const* name)
378  {
379      return name[0] == '_'
380          && name[1] == '_'
381          && std::binary_search(
382              &binary_operator_names[0]
383              , binary_operator_names + sizeof(binary_operator_names)/sizeof(*binary_operator_names)
384              , name + 2
385              , less_cstring()
386              );
387  }
388
389  // Something for the end of the chain of binary operators
390  PyObject* not_implemented(PyObject*, PyObject*)
391  {
392      Py_INCREF(Py_NotImplemented);
393      return Py_NotImplemented;
394  }
395 
396  handle<function> not_implemented_function()
397  {
398     
399      static object keeper(
400          function_object(
401              py_function(&not_implemented, mpl::vector1<void>(), 2)
402            , python::detail::keyword_range())
403          );
404      return handle<function>(borrowed(downcast<function>(keeper.ptr())));
405  }
406}
407
408void function::add_to_namespace(
409    object const& name_space, char const* name_, object const& attribute)
410{
411    add_to_namespace(name_space, name_, attribute, 0);
412}
413
414void function::add_to_namespace(
415    object const& name_space, char const* name_, object const& attribute, char const* doc)
416{
417    str const name(name_);
418    PyObject* const ns = name_space.ptr();
419   
420    if (attribute.ptr()->ob_type == &function_type)
421    {
422        function* new_func = downcast<function>(attribute.ptr());
423        PyObject* dict = 0;
424       
425        if (PyClass_Check(ns))
426            dict = ((PyClassObject*)ns)->cl_dict;
427        else if (PyType_Check(ns))
428            dict = ((PyTypeObject*)ns)->tp_dict;
429        else   
430            dict = PyObject_GetAttrString(ns, "__dict__");
431
432        if (dict == 0)
433            throw_error_already_set();
434
435        handle<> existing(allow_null(::PyObject_GetItem(dict, name.ptr())));
436       
437        if (existing)
438        {
439            if (existing->ob_type == &function_type)
440            {
441                new_func->add_overload(
442                    handle<function>(
443                        borrowed(
444                            downcast<function>(existing.get())
445                        )
446                    )
447                );
448            }
449            else if (existing->ob_type == &PyStaticMethod_Type)
450            {
451                char const* name_space_name = extract<char const*>(name_space.attr("__name__"));
452               
453                ::PyErr_Format(
454                    PyExc_RuntimeError
455                    , "Boost.Python - All overloads must be exported "
456                      "before calling \'class_<...>(\"%s\").staticmethod(\"%s\")\'"
457                    , name_space_name
458                    , name_
459                    );
460                throw_error_already_set();
461            }
462        }
463        else if (is_binary_operator(name_))
464        {
465            // Binary operators need an additional overload which
466            // returns NotImplemented, so that Python will try the
467            // __rxxx__ functions on the other operand. We add this
468            // when no overloads for the operator already exist.
469            new_func->add_overload(not_implemented_function());
470        }
471
472        // A function is named the first time it is added to a namespace.
473        if (new_func->name().ptr() == Py_None)
474            new_func->m_name = name;
475
476        handle<> name_space_name(
477            allow_null(::PyObject_GetAttrString(name_space.ptr(), "__name__")));
478       
479        if (name_space_name)
480            new_func->m_namespace = object(name_space_name);
481    }
482
483    // The PyObject_GetAttrString() or PyObject_GetItem calls above may
484    // have left an active error
485    PyErr_Clear();
486    if (PyObject_SetAttr(ns, name.ptr(), attribute.ptr()) < 0)
487        throw_error_already_set();
488
489    object mutable_attribute(attribute);
490    if (doc != 0 && docstring_options::show_user_defined_)
491    {
492        // Accumulate documentation
493       
494        if (
495            PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__")
496            && mutable_attribute.attr("__doc__"))
497        {
498            mutable_attribute.attr("__doc__") += "\n\n";
499            mutable_attribute.attr("__doc__") += doc;
500        }
501        else {
502            mutable_attribute.attr("__doc__") = doc;
503        }
504    }
505
506    if (docstring_options::show_signatures_)
507    {
508        if (   PyObject_HasAttrString(mutable_attribute.ptr(), "__doc__")
509            && mutable_attribute.attr("__doc__")) {
510            mutable_attribute.attr("__doc__") += "\n";
511        }
512        else {
513            mutable_attribute.attr("__doc__") = "";
514        }
515        function* f = downcast<function>(attribute.ptr());
516        mutable_attribute.attr("__doc__") += str("\n    ").join(make_tuple(
517          "C++ signature:", f->signature(true)));
518    }
519}
520
521BOOST_PYTHON_DECL void add_to_namespace(
522    object const& name_space, char const* name, object const& attribute)
523{
524    function::add_to_namespace(name_space, name, attribute, 0);
525}
526
527BOOST_PYTHON_DECL void add_to_namespace(
528    object const& name_space, char const* name, object const& attribute, char const* doc)
529{
530    function::add_to_namespace(name_space, name, attribute, doc);
531}
532
533
534namespace
535{
536  struct bind_return
537  {
538      bind_return(PyObject*& result, function const* f, PyObject* args, PyObject* keywords)
539          : m_result(result)
540            , m_f(f)
541            , m_args(args)
542            , m_keywords(keywords)
543      {}
544
545      void operator()() const
546      {
547          m_result = m_f->call(m_args, m_keywords);
548      }
549     
550   private:
551      PyObject*& m_result;
552      function const* m_f;
553      PyObject* m_args;
554      PyObject* m_keywords;
555  };
556}
557
558extern "C"
559{
560    // Stolen from Python's funcobject.c
561    static PyObject *
562    function_descr_get(PyObject *func, PyObject *obj, PyObject *type_)
563    {
564        if (obj == Py_None)
565            obj = NULL;
566        return PyMethod_New(func, obj, type_);
567    }
568
569    static void
570    function_dealloc(PyObject* p)
571    {
572        delete static_cast<function*>(p);
573    }
574
575    static PyObject *
576    function_call(PyObject *func, PyObject *args, PyObject *kw)
577    {
578        PyObject* result = 0;
579        handle_exception(bind_return(result, static_cast<function*>(func), args, kw));
580        return result;
581    }
582
583    //
584    // Here we're using the function's tp_getset rather than its
585    // tp_members to set up __doc__ and __name__, because tp_members
586    // really depends on having a POD object type (it relies on
587    // offsets). It might make sense to reformulate function as a POD
588    // at some point, but this is much more expedient.
589    //
590    static PyObject* function_get_doc(PyObject* op, void*)
591    {
592        function* f = downcast<function>(op);
593        return python::incref(f->doc().ptr());
594    }
595   
596    static int function_set_doc(PyObject* op, PyObject* doc, void*)
597    {
598        function* f = downcast<function>(op);
599        f->doc(doc ? object(python::detail::borrowed_reference(doc)) : object());
600        return 0;
601    }
602   
603    static PyObject* function_get_name(PyObject* op, void*)
604    {
605        function* f = downcast<function>(op);
606        if (f->name().ptr() == Py_None)
607            return PyString_InternFromString("<unnamed Boost.Python function>");
608        else
609            return python::incref(f->name().ptr());
610    }
611
612    // We add a dummy __class__ attribute in order to fool PyDoc into
613    // treating these as built-in functions and scanning their
614    // documentation
615    static PyObject* function_get_class(PyObject* /*op*/, void*)
616    {
617        return python::incref(upcast<PyObject>(&PyCFunction_Type));
618    }
619}
620
621static PyGetSetDef function_getsetlist[] = {
622    {"__name__", (getter)function_get_name, 0, 0, 0 },
623    {"func_name", (getter)function_get_name, 0, 0, 0 },
624    {"__class__", (getter)function_get_class, 0, 0, 0 },    // see note above
625    {"__doc__", (getter)function_get_doc, (setter)function_set_doc, 0, 0},
626    {"func_doc", (getter)function_get_doc, (setter)function_set_doc, 0, 0},
627    {NULL, 0, 0, 0, 0} /* Sentinel */
628};
629
630PyTypeObject function_type = {
631    PyObject_HEAD_INIT(0)
632    0,
633    "Boost.Python.function",
634    sizeof(function),
635    0,
636    (destructor)function_dealloc,               /* tp_dealloc */
637    0,                                  /* tp_print */
638    0,                                  /* tp_getattr */
639    0,                                  /* tp_setattr */
640    0,                                  /* tp_compare */
641    0, //(reprfunc)func_repr,                   /* tp_repr */
642    0,                                  /* tp_as_number */
643    0,                                  /* tp_as_sequence */
644    0,                                  /* tp_as_mapping */
645    0,                                  /* tp_hash */
646    function_call,                              /* tp_call */
647    0,                                  /* tp_str */
648    0, // PyObject_GenericGetAttr,            /* tp_getattro */
649    0, // PyObject_GenericSetAttr,            /* tp_setattro */
650    0,                                  /* tp_as_buffer */
651    Py_TPFLAGS_DEFAULT /* | Py_TPFLAGS_HAVE_GC */,/* tp_flags */
652    0,                                  /* tp_doc */
653    0, // (traverseproc)func_traverse,          /* tp_traverse */
654    0,                                  /* tp_clear */
655    0,                                  /* tp_richcompare */
656    0, //offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */
657    0,                                  /* tp_iter */
658    0,                                  /* tp_iternext */
659    0,                                  /* tp_methods */
660    0, // func_memberlist,              /* tp_members */
661    function_getsetlist,                /* tp_getset */
662    0,                                  /* tp_base */
663    0,                                  /* tp_dict */
664    function_descr_get,                 /* tp_descr_get */
665    0,                                  /* tp_descr_set */
666    0, //offsetof(PyFunctionObject, func_dict),      /* tp_dictoffset */
667    0,                                      /* tp_init */
668    0,                                      /* tp_alloc */
669    0,                                      /* tp_new */
670    0,                                      /* tp_free */
671    0,                                      /* tp_is_gc */
672    0,                                      /* tp_bases */
673    0,                                      /* tp_mro */
674    0,                                      /* tp_cache */
675    0,                                      /* tp_subclasses */
676    0,                                      /* tp_weaklist */
677#if PYTHON_API_VERSION >= 1012
678    0                                       /* tp_del */
679#endif
680};
681
682object function_object(
683    py_function const& f
684    , python::detail::keyword_range const& keywords)
685{
686    return python::object(
687        python::detail::new_non_null_reference(
688            new function(
689                f, keywords.first, keywords.second - keywords.first)));
690}
691
692object function_object(py_function const& f)
693{
694    return function_object(f, python::detail::keyword_range());
695}
696
697
698handle<> function_handle_impl(py_function const& f)
699{
700    return python::handle<>(
701        allow_null(
702            new function(f, 0, 0)));
703}
704
705} // namespace objects
706
707namespace detail
708{
709  object BOOST_PYTHON_DECL make_raw_function(objects::py_function f)
710  {
711      static keyword k;
712   
713      return objects::function_object(
714          f
715          , keyword_range(&k,&k));
716  }
717  void BOOST_PYTHON_DECL pure_virtual_called()
718  {
719      PyErr_SetString(PyExc_RuntimeError, "Pure virtual function called");
720      throw_error_already_set();
721  }
722}
723
724}} // namespace boost::python
Note: See TracBrowser for help on using the repository browser.