mirror of
https://github.com/boostorg/python.git
synced 2026-01-22 17:32:55 +00:00
no message
[SVN r8114]
This commit is contained in:
@@ -1,8 +1,16 @@
|
||||
2000-11-02 23:25
|
||||
2000-11-03 10:58
|
||||
|
||||
Fix friend function instantiation bug caught by Metrowerks (thanks
|
||||
Metrowerks!)
|
||||
|
||||
Add proof-of-concept for one technique of wrapping function that return a
|
||||
pointer
|
||||
|
||||
Worked around MSVC optimizer bug by writing to_python(double) and
|
||||
to_python(float) out-of-line
|
||||
|
||||
2000-11-02 23:25
|
||||
|
||||
Add /Zm200 option to vc6_prj to deal with MSVC resource limitations
|
||||
|
||||
Remove conflicting /Ot option from vc6_prj release build
|
||||
|
||||
158
todo.txt
158
todo.txt
@@ -129,7 +129,165 @@ Documentation:
|
||||
For example, you could use this to convert Python lists to/from
|
||||
std::vector<T> automatically.
|
||||
|
||||
Pointer return values
|
||||
|
||||
Case 1:
|
||||
|
||||
> I am now also able to wrap the problematic TextRecordIterator for Python.
|
||||
> However, one of its function compiles with this warning:
|
||||
>
|
||||
> d:\py_cpp/caller.h(33) : warning C4800: 'const class Record *const '
|
||||
> : forcing value to bool 'true' or 'false' (performance warning)
|
||||
> d:\py_cpp/functions.h(54) : see reference to function template
|
||||
> instantiation 'struct _object *__cdecl py::Caller::call(const class Record
|
||||
> *const (__thiscall TextRecordIterator::*)(void),struct _object *,struct
|
||||
> _object *)' being compiled
|
||||
>
|
||||
> If you look at the offending code, you'll see that we really do need to
|
||||
> get back that pointer:
|
||||
>
|
||||
> const Record* const TextRecordIterator::Next() {
|
||||
> if (fStatus != RecordIterator::SUCCESS) {
|
||||
> return 0;
|
||||
> } else {
|
||||
> return &fData;
|
||||
> }
|
||||
> }
|
||||
>
|
||||
> The point of the TextRecordIterator is to hand over one reord after
|
||||
> another. A bool wouldn't do us much good here :-)
|
||||
>
|
||||
> Do you have any suggestions for fixing this?
|
||||
|
||||
In general, py_cpp doesn't automatically convert pointer return values
|
||||
to_python because pointers have too many potential meanings. Is it an
|
||||
iterator? A pointer to a single element? An array? Is ownership being passed
|
||||
to Python or is the pointer really just a reference? If the latter, what
|
||||
happens when some C++ code deletes the referent. The only exception to this
|
||||
rule is const char*, since it has a generally accepted interpretation (could
|
||||
be trouble with some generic code, though!)
|
||||
|
||||
If you have wrapped the Record class, you could add this to namespace py:
|
||||
|
||||
PyObject* to_python(const Record* p) {
|
||||
return to_python(*p);
|
||||
}
|
||||
|
||||
Of course, this will cause the Record class to be copied. If you can't live
|
||||
with that (Record would have to be /really/ heavyweight to make this
|
||||
worthwhile), you can follow one of these dangerous approaches:
|
||||
|
||||
1. Use the technique I described with dangerous_array in
|
||||
http://www.egroups.com/message/boost/6196. You do not have to expose Record
|
||||
explicitly in this case. Instead the class you expose will be more of a
|
||||
Record_proxy
|
||||
|
||||
2. Wrap Record in the usual way, then add the following to namespace py:
|
||||
|
||||
PyObject* to_python(const Record* p)
|
||||
{
|
||||
return ExtensionClass<Record>::ptr_to_python(const_cast<Record*>(p));
|
||||
}
|
||||
|
||||
This will cause the Record* to be treated as though it were an owning smart
|
||||
pointer, even though it's not. Be sure you don't use the reference for
|
||||
anything from Python once the pointer becomes invalid, though. Don't worry
|
||||
too much about the const-correctness issue: Const-correctness is completely
|
||||
lost to Python anyway!
|
||||
|
||||
3. As above, but instead wrap const Record rather than plain Record. Then
|
||||
you can avoid the const_cast, but you obviously can't def() any non-const
|
||||
member functions of Record.
|
||||
|
||||
Case 2:
|
||||
|
||||
> I have yet another question. This is more a general wrapper question.
|
||||
> Let me say that there is a function that returns a float* which most
|
||||
> probably is an array. Similarly if I have a function that takes a
|
||||
> float* as an argument, what is the best way of wrapping this?
|
||||
|
||||
I think you have correctly perceived that it doesn't make sense for me to
|
||||
automatically convert all pointers, since the ownership semantics are so
|
||||
blurry.
|
||||
|
||||
> 1) If the array is small it makes sense to convert it to either a
|
||||
> tuple or list. What is the easiest way to do this?? I am looking
|
||||
> for a way that makes one write the least code. :)
|
||||
|
||||
How can you tell the length of the array from a single pointer?
|
||||
Once you've answered that question, you can expose a wrapper function which
|
||||
returns an instance of the py::Tuple or py::List class from objects.h. If
|
||||
you are using a List, for example, you could write something like this:
|
||||
|
||||
py::List wrap_f()
|
||||
{
|
||||
T* start = f();
|
||||
py::List x;
|
||||
for (T* p = start; p != start + length_constant; ++p)
|
||||
x.push_back(py::to_python(*p));
|
||||
return x;
|
||||
}
|
||||
|
||||
> 2) If the array is large it may not make sense to use a list/tuple
|
||||
> esp. if the values are used for computationally intense programs.
|
||||
|
||||
In this case you can do one of several somewhat dangerous things. Why
|
||||
dangerous? Because python can not control the lifetime of the data, so the
|
||||
data in the array may be destroyed or become invalid before the last
|
||||
reference to it disappears. The basic approach is to make a small C++ class
|
||||
which contains the pointer, and expose that:
|
||||
|
||||
// UNTESTED
|
||||
template <class T>
|
||||
struct dangerous_array
|
||||
{
|
||||
dangerous_array(T* start, T* end)
|
||||
: m_start(start), m_end(end) {}
|
||||
|
||||
// exposed as "__len__"
|
||||
std::size_t length() {
|
||||
return m_end - m_start;
|
||||
}
|
||||
|
||||
// exposed as "__getitem__"
|
||||
T get_item(std::size_t n) {
|
||||
check_range(n);
|
||||
return start[n];
|
||||
}
|
||||
|
||||
// exposed as "__setitem__" if the array is mutable
|
||||
void set_item(std::size_t n, const T& x) {
|
||||
check_range(n);
|
||||
start[n] = x;
|
||||
}
|
||||
private:
|
||||
void check_range(std::size_t n) {
|
||||
if (n >= m_end - m_start) {
|
||||
PyErr_SetString(PyExc_IndexError, "array index out of range");
|
||||
throw py::ErrorAlreadySet;
|
||||
}
|
||||
}
|
||||
T* m_start;
|
||||
T* m_end;
|
||||
};
|
||||
|
||||
A reasonably safe approach would be to make a wrapper function for each
|
||||
function that returns a T*, and expose that instead. If you're too lazy and
|
||||
you really like to live on the edge, though, you can write to_python(T*) in
|
||||
terms of to_python(const dangerous_array<T>&), and you'll automatically
|
||||
convert all T* return values to a wrapped dangerous_array.
|
||||
|
||||
> 3) For an arbitrary class "class_A", say, can py_cpp handle
|
||||
> references to class_A &instance, or class_A *instance?? i.e. will it
|
||||
> wrap function calls to such objects? This question is obviously
|
||||
> related to the earlier questions.
|
||||
|
||||
Yes, iff class_A has been exposed to python with a ClassWrapper<class_A>.
|
||||
See http://people.ne.mediaone.net/abrahams/downloads/under-the-hood.html for
|
||||
a few details.
|
||||
|
||||
Types that are already wrapped by other libraries
|
||||
|
||||
It's not documented yet, but you should be able to use a raw PyObject* or a
|
||||
py::Ptr as one parameter to your C++ function. Then you can manipulate it as
|
||||
any other generic Python object.
|
||||
|
||||
Reference in New Issue
Block a user