2
0
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:
Dave Abrahams
2000-11-03 16:10:28 +00:00
parent 6277023215
commit 39c3c45157
2 changed files with 167 additions and 1 deletions

View File

@@ -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
View File

@@ -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.