@@ -202,6 +202,19 @@ PyObject* FollowGetAttr(PyObject* self, PyObject* name)
202202 return result;
203203}
204204
205+ // - pointer checking bool converter -------------------------------------------
206+ PyObject* NullCheckBool (PyObject* self)
207+ {
208+ if (!CPPInstance_Check (self)) {
209+ PyErr_SetString (PyExc_TypeError, " C++ object proxy expected" );
210+ return nullptr ;
211+ }
212+
213+ if (!((CPPInstance*)self)->GetObject ())
214+ Py_RETURN_FALSE;
215+
216+ return PyObject_CallMethodNoArgs (self, PyStrings::gCppBool );
217+ }
205218
206219// - vector behavior as primitives ----------------------------------------------
207220#if PY_VERSION_HEX < 0x03040000
@@ -345,7 +358,7 @@ static bool FillVector(PyObject* vecin, PyObject* args, ItemGetter* getter)
345358 eb_args = PyTuple_New (1 );
346359 PyTuple_SET_ITEM (eb_args, 0 , item);
347360 } else if (PyTuple_CheckExact (item)) {
348- eb_args = item;
361+ eb_args = item;
349362 } else if (PyList_CheckExact (item)) {
350363 Py_ssize_t isz = PyList_GET_SIZE (item);
351364 eb_args = PyTuple_New (isz);
@@ -492,7 +505,8 @@ PyObject* VectorInit(PyObject* self, PyObject* args, PyObject* /* kwds */)
492505PyObject* VectorData (PyObject* self, PyObject*)
493506{
494507 PyObject* pydata = CallPyObjMethod (self, " __real_data" );
495- if (!LowLevelView_Check (pydata)) return pydata;
508+ if (!LowLevelView_Check (pydata) && !CPPInstance_Check (pydata))
509+ return pydata;
496510
497511 PyObject* pylen = PyObject_CallMethodNoArgs (self, PyStrings::gSize );
498512 if (!pylen) {
@@ -503,12 +517,12 @@ PyObject* VectorData(PyObject* self, PyObject*)
503517 long clen = PyInt_AsLong (pylen);
504518 Py_DECREF (pylen);
505519
506- // TODO: should be a LowLevelView helper
507- Py_buffer& bi = ((LowLevelView*)pydata)->fBufInfo ;
508- bi.len = clen * bi.itemsize ;
509- if (bi.ndim == 1 && bi.shape )
510- bi.shape [0 ] = clen;
520+ if (CPPInstance_Check (pydata)) {
521+ ((CPPInstance*)pydata)->CastToArray (clen);
522+ return pydata;
523+ }
511524
525+ ((LowLevelView*)pydata)->resize ((size_t )clen);
512526 return pydata;
513527}
514528
@@ -549,7 +563,18 @@ static PyObject* vector_iter(PyObject* v) {
549563
550564 if (PyLong_Check (pyvalue_type)) {
551565 Cppyy::TCppType_t value_type = PyLong_AsVoidPtr (pyvalue_type);
566+ value_type = Cppyy::ResolveType (value_type);
552567 vi->vi_klass = Cppyy::GetScopeFromType (value_type);
568+ if (!vi->vi_klass ) {
569+ // look for a special case of pointer to a class type (which is a builtin, but it
570+ // is more useful to treat it polymorphically by allowing auto-downcasts)
571+ const std::string& clean_type = TypeManip::clean_type (value_type, false , false );
572+ Cppyy::TCppScope_t c = Cppyy::GetScope (clean_type);
573+ if (c && TypeManip::compound (value_type) == " *" ) {
574+ vi->vi_klass = c;
575+ vi->vi_flags = vectoriterobject::kIsPolymorphic ;
576+ }
577+ }
553578 if (vi->vi_klass ) {
554579 vi->vi_converter = nullptr ;
555580 if (!vi->vi_flags ) {
@@ -810,7 +835,7 @@ static PyObject* MapFromPairs(PyObject* self, PyObject* pairs)
810835PyObject* MapInit (PyObject* self, PyObject* args, PyObject* /* kwds */ )
811836{
812837// Specialized map constructor to allow construction from mapping containers and
813- // from tuples of pairs ("intializer_list style").
838+ // from tuples of pairs ("initializer_list style").
814839
815840// PyMapping_Check is not very discriminatory, as it basically only checks for the
816841// existence of __getitem__, hence the most common cases of tuple and list are
@@ -1012,7 +1037,7 @@ PyObject* CheckedGetItem(PyObject* self, PyObject* obj)
10121037{
10131038// Implement a generic python __getitem__ for STL-like classes that are missing the
10141039// reflection info for their iterators. This is then used for iteration by means of
1015- // consecutive indeces , it such index is of integer type.
1040+ // consecutive indices , it such index is of integer type.
10161041 Py_ssize_t size = PySequence_Size(self);
10171042 Py_ssize_t idx = PyInt_AsSsize_t(obj);
10181043 if ((size == (Py_ssize_t)-1 || idx == (Py_ssize_t)-1) && PyErr_Occurred()) {
@@ -1236,7 +1261,7 @@ PyObject* STLStringContains(CPPInstance* self, PyObject* pyobj)
12361261 Py_RETURN_FALSE;
12371262}
12381263
1239- PyObject* STLStringReplace (CPPInstance* self, PyObject* args, PyObject* kwds)
1264+ PyObject* STLStringReplace (CPPInstance* self, PyObject* args, PyObject* /* kwds*/ )
12401265{
12411266 std::string* obj = GetSTLString (self);
12421267 if (!obj)
@@ -1267,7 +1292,7 @@ PyObject* STLStringReplace(CPPInstance* self, PyObject* args, PyObject* kwds)
12671292}
12681293
12691294#define CPYCPPYY_STRING_FINDMETHOD (name, cppname, pyname ) \
1270- PyObject* STLString##name(CPPInstance* self, PyObject* args, PyObject* kwds) \
1295+ PyObject* STLString##name(CPPInstance* self, PyObject* args, PyObject* /* kwds*/ ) \
12711296{ \
12721297 std::string* obj = GetSTLString (self); \
12731298 if (!obj) \
@@ -1387,7 +1412,6 @@ PyObject* StringViewInit(PyObject* self, PyObject* args, PyObject* /* kwds */)
13871412}
13881413
13891414
1390-
13911415// - STL iterator behavior ----------------------------------------------------
13921416PyObject* STLIterNext (PyObject* self)
13931417{
@@ -1590,6 +1614,16 @@ bool CPyCppyy::Pythonize(PyObject* pyclass, Cppyy::TCppScope_t scope)
15901614 else if (HasAttrDirect (pyclass, PyStrings::gFollow ) && !Cppyy::IsSmartPtr (klass->fCppType ))
15911615 Utility::AddToClass (pyclass, " __getattr__" , (PyCFunction)FollowGetAttr, METH_O);
15921616
1617+ // for pre-check of nullptr for boolean types
1618+ if (HasAttrDirect (pyclass, PyStrings::gCppBool )) {
1619+ #if PY_VERSION_HEX >= 0x03000000
1620+ const char * pybool_name = " __bool__" ;
1621+ #else
1622+ const char * pybool_name = " __nonzero__" ;
1623+ #endif
1624+ Utility::AddToClass (pyclass, pybool_name, (PyCFunction)NullCheckBool, METH_NOARGS);
1625+ }
1626+
15931627// for STL containers, and user classes modeled after them
15941628 if (HasAttrDirect (pyclass, PyStrings::gSize ))
15951629 Utility::AddToClass (pyclass, " __len__" , " size" );
@@ -1631,7 +1665,7 @@ bool CPyCppyy::Pythonize(PyObject* pyclass, Cppyy::TCppScope_t scope)
16311665 // Python will iterate over __getitem__ using integers, but C++ operator[] will never raise
16321666 // a StopIteration. A checked getitem (raising IndexError if beyond size()) works in some
16331667 // cases but would mess up if operator[] is meant to implement an associative container. So,
1634- // this has to be implemented as an interator protocol.
1668+ // this has to be implemented as an iterator protocol.
16351669 ((PyTypeObject*)pyclass)->tp_iter = (getiterfunc)index_iter;
16361670 Utility::AddToClass (pyclass, " __iter__" , (PyCFunction)index_iter, METH_NOARGS);
16371671 }
0 commit comments