low-level support for python copy and pickle modules

This commit is contained in:
David Rose 2009-12-10 01:09:06 +00:00
parent 3e82b3d163
commit 816ddc0387
29 changed files with 1221 additions and 295 deletions

View File

@ -302,6 +302,30 @@ Filename(const Filename &dirname, const Filename &basename) {
} }
} }
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: Filename::__reduce__
// Access: Published
// Description: This special Python method is implement to provide
// support for the pickle module.
////////////////////////////////////////////////////////////////////
PyObject *Filename::
__reduce__(PyObject *self) const {
// We should return at least a 2-tuple, (Class, (args)): the
// necessary class object whose constructor we should call
// (e.g. this), and the arguments necessary to reconstruct this
// object.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *result = Py_BuildValue("(O(s))", this_class, c_str());
Py_DECREF(this_class);
return result;
}
#endif // HAVE_PYTHON
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Filename::from_os_specific // Function: Filename::from_os_specific
// Access: Published, Static // Access: Published, Static

View File

@ -66,6 +66,10 @@ PUBLISHED:
Filename(const Filename &dirname, const Filename &basename); Filename(const Filename &dirname, const Filename &basename);
INLINE ~Filename(); INLINE ~Filename();
#ifdef HAVE_PYTHON
PyObject *__reduce__(PyObject *self) const;
#endif
// Static constructors to explicitly create a filename that refers // Static constructors to explicitly create a filename that refers
// to a text or binary file. This is in lieu of calling set_text() // to a text or binary file. This is in lieu of calling set_text()
// or set_binary() or set_type(). // or set_binary() or set_type().

View File

@ -297,6 +297,16 @@ make_wrapper_entry(FunctionIndex function_index) {
assert(!iwrapper._parameters.empty()); assert(!iwrapper._parameters.empty());
iwrapper._parameters.front()._parameter_flags |= iwrapper._parameters.front()._parameter_flags |=
InterrogateFunctionWrapper::PF_is_this; InterrogateFunctionWrapper::PF_is_this;
if (_parameters.size() >= 2 && _parameters[1]._name == "self" &&
TypeManager::is_pointer_to_PyObject(_parameters[1]._remap->get_orig_type())) {
// Here's a special case. If the first parameter of a nonstatic
// method is a PyObject * called "self", then we will
// automatically fill it in from the this pointer, and remove it
// from the generated parameter list.
_parameters.erase(_parameters.begin() + 1);
_flags |= F_explicit_self;
}
} }
if (!_void_return) { if (!_void_return) {
@ -382,6 +392,14 @@ get_call_str(const string &container, const vector_string &pexprs) const {
} }
call << "("; call << "(";
if (_flags & F_explicit_self) {
// Pass on the PyObject * that we stripped off above.
call << "self";
if (_first_true_parameter < (int)_parameters.size()) {
call << ", ";
}
}
int pn = _first_true_parameter; int pn = _first_true_parameter;
if (pn < (int)_parameters.size()) { if (pn < (int)_parameters.size()) {
_parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs)); _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
@ -630,6 +648,23 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
// It receives no parameters, and returns an integer. // It receives no parameters, and returns an integer.
_flags |= F_size; _flags |= F_size;
} }
} else if (fname == "make_copy" ) {
if (_has_this && _parameters.size() == 1 &&
TypeManager::is_pointer(_return_type->get_new_type())) {
// It receives no parameters, and returns a pointer.
_flags |= F_make_copy;
}
}
} else if (_type == T_constructor) {
if (!_has_this && _parameters.size() == 1) {
if (TypeManager::unwrap(_parameters[0]._remap->get_orig_type()) ==
TypeManager::unwrap(_return_type->get_orig_type())) {
// If this is the only parameter, and it's the same as the
// "this" type, this is a copy constructor.
_flags |= F_copy_constructor;
}
} }
} }

View File

@ -79,11 +79,14 @@ public:
}; };
enum Flags { enum Flags {
F_getitem = 0x0001, F_getitem = 0x0001,
F_getitem_int = 0x0002, F_getitem_int = 0x0002,
F_size = 0x0004, F_size = 0x0004,
F_setitem = 0x0008, F_setitem = 0x0008,
F_setitem_int = 0x0010, F_setitem_int = 0x0010,
F_make_copy = 0x0020,
F_copy_constructor = 0x0040,
F_explicit_self = 0x0080,
}; };
typedef vector<Parameter> Parameters; typedef vector<Parameter> Parameters;

View File

@ -123,6 +123,10 @@ check_protocols() {
int flags = 0; int flags = 0;
Functions::const_iterator fi; Functions::const_iterator fi;
for (fi = _constructors.begin(); fi != _constructors.end(); ++fi) {
Function *func = (*fi);
flags |= func->_flags;
}
for (fi = _methods.begin(); fi != _methods.end(); ++fi) { for (fi = _methods.begin(); fi != _methods.end(); ++fi) {
Function *func = (*fi); Function *func = (*fi);
flags |= func->_flags; flags |= func->_flags;
@ -140,6 +144,16 @@ check_protocols() {
_protocol_types |= PT_mapping; _protocol_types |= PT_mapping;
} }
if (flags & FunctionRemap::F_make_copy) {
// It's not exactly a protocol, but if we have a make_copy()
// method, we can use it to synthesize a __copy__ and __deepcopy__
// Python method to support the copy module.
_protocol_types |= PT_make_copy;
} else if (flags & FunctionRemap::F_copy_constructor) {
// Ditto for the copy constructor.
_protocol_types |= PT_copy_constructor;
}
// Now are there any make_seq requests within this class? // Now are there any make_seq requests within this class?
CPPStructType *stype = _itype._cpptype->as_struct_type(); CPPStructType *stype = _itype._cpptype->as_struct_type();
if (stype != (CPPStructType *)NULL) { if (stype != (CPPStructType *)NULL) {

View File

@ -110,8 +110,10 @@ public:
MakeSeqs _make_seqs; MakeSeqs _make_seqs;
enum ProtocolTypes { enum ProtocolTypes {
PT_sequence = 0x0001, PT_sequence = 0x0001,
PT_mapping = 0x0002, PT_mapping = 0x0002,
PT_make_copy = 0x0004,
PT_copy_constructor = 0x0008,
}; };
int _protocol_types; int _protocol_types;
}; };

View File

@ -97,7 +97,10 @@ RenameSet methodRenameDictionary[] = {
{ "operator <<=" , "__ilshift__", 1 }, { "operator <<=" , "__ilshift__", 1 },
{ "operator >>=" , "__irshift__", 1 }, { "operator >>=" , "__irshift__", 1 },
{ "operator typecast bool", "__nonzero__", 0 }, { "operator typecast bool", "__nonzero__", 0 },
{ "__nonzero__" , "__nonzero__", 0 }, { "__nonzero__" , "__nonzero__", 0 },
{ "__reduce__" , "__reduce__", 0 },
{ "__copy__" , "__copy__", 0 },
{ "__deepcopy__" , "__deepcopy__", 0 },
{ "print" , "Cprint", 0 }, { "print" , "Cprint", 0 },
{ "CInterval.set_t", "_priv__cSetT", 0 }, { "CInterval.set_t", "_priv__cSetT", 0 },
{ NULL, NULL, -1 } { NULL, NULL, -1 }
@ -159,34 +162,36 @@ RenameSet classRenameDictionary[] = {
/////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////
const char * pythonKeywords[] = { const char * pythonKeywords[] = {
"and", "and",
"del", "del",
"for", "for",
"is", "is",
"raise", "raise",
"assert", "assert",
"elif", "elif",
"from", "from",
"lambda", "lambda",
"return", "return",
"break", "break",
"else", "else",
"global", "global",
"not", "not",
"try", "try",
"class", "class",
"except", "except",
"if", "if",
"or", "or",
"while", "while",
"continue", "continue",
"exec", "exec",
"import", "import",
"pass", "pass",
"def", "def",
"finally", "finally",
"in", "in",
"print", "print",
NULL}; NULL
};
/////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////
std::string checkKeyword(std::string & cppName) std::string checkKeyword(std::string & cppName)
{ {
@ -813,69 +818,69 @@ void InterfaceMakerPythonNative::write_prototypes_class(ostream &out_code,ostrea
void InterfaceMakerPythonNative::write_functions(ostream &out) void InterfaceMakerPythonNative::write_functions(ostream &out)
{ {
inside_python_native = true; inside_python_native = true;
out << "//********************************************************************\n"; out << "//********************************************************************\n";
out << "//*** Functions for .. Global \n" ; out << "//*** Functions for .. Global \n" ;
out << "//********************************************************************\n"; out << "//********************************************************************\n";
Functions::iterator fi; Functions::iterator fi;
for (fi = _functions.begin(); fi != _functions.end(); ++fi) for (fi = _functions.begin(); fi != _functions.end(); ++fi)
{
Function *func = (*fi);
if(!func->_itype.is_global() && isFunctionLegal(func))
write_function_for_top(out, NULL, func,"");
}
Objects::iterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi)
{
Object *object = (*oi).second;
if(object->_itype.is_class() ||object->_itype.is_struct())
{
if(isCppTypeLegal(object->_itype._cpptype))
if(isExportThisRun(object->_itype._cpptype))
write_ClasseDetails(out,object);
}
}
// Objects::iterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi)
{ {
Object *object = (*oi).second; Function *func = (*fi);
if(!object->_itype.get_outer_class()) if(!func->_itype.is_global() && isFunctionLegal(func))
write_function_for_top(out, NULL, func,"");
}
Objects::iterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi)
{
Object *object = (*oi).second;
if(object->_itype.is_class() ||object->_itype.is_struct())
{ {
if(object->_itype.is_class() ||object->_itype.is_struct()) if(isCppTypeLegal(object->_itype._cpptype))
if(isCppTypeLegal(object->_itype._cpptype)) if(isExportThisRun(object->_itype._cpptype))
if(isExportThisRun(object->_itype._cpptype)) write_ClasseDetails(out,object);
write_module_class(out,object); }
}
// Objects::iterator oi;
for (oi = _objects.begin(); oi != _objects.end(); ++oi)
{
Object *object = (*oi).second;
if(!object->_itype.get_outer_class())
{
if(object->_itype.is_class() ||object->_itype.is_struct())
if(isCppTypeLegal(object->_itype._cpptype))
if(isExportThisRun(object->_itype._cpptype))
write_module_class(out,object);
} }
} }
inside_python_native = true; inside_python_native = true;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Function : write_ClasseDetails // Function : write_ClasseDetails
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void InterfaceMakerPythonNative::write_ClasseDetails(ostream &out, Object * obj) void InterfaceMakerPythonNative::write_ClasseDetails(ostream &out, Object * obj)
{ {
Functions::iterator fi; Functions::iterator fi;
//std::string cClassName = obj->_itype.get_scoped_name(); //std::string cClassName = obj->_itype.get_scoped_name();
std::string ClassName = make_safe_name(obj->_itype.get_scoped_name()); std::string ClassName = make_safe_name(obj->_itype.get_scoped_name());
std::string cClassName = obj->_itype.get_true_name(); std::string cClassName = obj->_itype.get_true_name();
std::string export_class_name = classNameFromCppName(obj->_itype.get_name()); std::string export_class_name = classNameFromCppName(obj->_itype.get_name());
out << "//********************************************************************\n"; out << "//********************************************************************\n";
out << "//*** Functions for .. "<< cClassName <<" \n" ; out << "//*** Functions for .. "<< cClassName <<" \n" ;
out << "//********************************************************************\n"; out << "//********************************************************************\n";
for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi) for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi)
{ {
Function *func = (*fi); Function *func = (*fi);
if( (func)) if( (func))
{ {
SlottedFunctionDef def; SlottedFunctionDef def;
get_slotted_function_def(obj, func, def); get_slotted_function_def(obj, func, def);
ostringstream GetThis; ostringstream GetThis;
GetThis << " "<<cClassName << " * local_this = NULL;\n"; GetThis << " "<<cClassName << " * local_this = NULL;\n";
GetThis << " DTOOL_Call_ExtractThisPointerForType(self,&Dtool_"<< ClassName<<",(void **)&local_this);\n"; GetThis << " DTOOL_Call_ExtractThisPointerForType(self,&Dtool_"<< ClassName<<",(void **)&local_this);\n";
@ -887,7 +892,7 @@ void InterfaceMakerPythonNative::write_ClasseDetails(ostream &out, Object * obj)
// likes to call on the wrong-type objects. // likes to call on the wrong-type objects.
GetThis << " Py_INCREF(Py_NotImplemented);\n"; GetThis << " Py_INCREF(Py_NotImplemented);\n";
GetThis << " return Py_NotImplemented;\n"; GetThis << " return Py_NotImplemented;\n";
} else { } else {
// Other functions should raise an exception if the this // Other functions should raise an exception if the this
// pointer isn't set or is the wrong type. // pointer isn't set or is the wrong type.
@ -898,100 +903,100 @@ void InterfaceMakerPythonNative::write_ClasseDetails(ostream &out, Object * obj)
write_function_for_top(out, obj, func,GetThis.str()); write_function_for_top(out, obj, func,GetThis.str());
} }
} }
// bool AnyLeganConstructors; // bool AnyLeganConstructors;
if(obj->_constructors.size() == 0) if(obj->_constructors.size() == 0)
{ {
std::string fname = "int Dtool_Init_"+ClassName+"(PyObject *self, PyObject *args, PyObject *kwds)"; std::string fname = "int Dtool_Init_"+ClassName+"(PyObject *self, PyObject *args, PyObject *kwds)";
out << fname << "\n"; out << fname << "\n";
out << "{\n"; out << "{\n";
out << " PyErr_SetString(PyExc_TypeError, \"Error Can Not Init Constant Class (" << cClassName << ")\");\n"; out << " PyErr_SetString(PyExc_TypeError, \"Error Can Not Init Constant Class (" << cClassName << ")\");\n";
out << " return -1;\n" ; out << " return -1;\n" ;
out << "}\n"; out << "}\n";
} }
else else
{ {
for (fi = obj->_constructors.begin(); fi != obj->_constructors.end(); ++fi) for (fi = obj->_constructors.begin(); fi != obj->_constructors.end(); ++fi)
{ {
Function *func = (*fi); Function *func = (*fi);
std::string fname = "int Dtool_Init_"+ClassName+"(PyObject *self, PyObject *args, PyObject *kwds) "; std::string fname = "int Dtool_Init_"+ClassName+"(PyObject *self, PyObject *args, PyObject *kwds) ";
write_function_for_name(out, obj, func,fname,"",ClassName); write_function_for_name(out, obj, func,fname,"",ClassName);
} }
} }
MakeSeqs::iterator msi; MakeSeqs::iterator msi;
for (msi = obj->_make_seqs.begin(); msi != obj->_make_seqs.end(); ++msi) { for (msi = obj->_make_seqs.begin(); msi != obj->_make_seqs.end(); ++msi) {
write_make_seq(out, obj, ClassName, *msi); write_make_seq(out, obj, ClassName, *msi);
}
CPPType *cpptype = TypeManager::resolve_type(obj->_itype._cpptype);
std::map< string ,CastDetails > details;
std::map< string ,CastDetails >::iterator di;
builder.get_type(TypeManager::unwrap(cpptype),false);
GetValideChildClasses(details, cpptype->as_struct_type());
for(di = details.begin(); di != details.end(); di++)
{
//InterrogateType ptype =idb->get_type(di->first);
if(di->second._is_legal_py_class && !isExportThisRun(di->second._structType))
_external_imports.insert(make_safe_name(di->second._to_class_name));
//out << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << make_safe_name(di->second._to_class_name) <<";\n";
} }
{ // the Cast Converter
out << "inline void * Dtool_UpcastInterface_"<< ClassName << "(PyObject *self, Dtool_PyTypedObject *requested_type)\n";
out << "{\n";
out << " Dtool_PyTypedObject *SelfType = ((Dtool_PyInstDef *)self)->_My_Type;\n";
out << " if(SelfType != &Dtool_" << ClassName <<")\n";
out << " {\n";
out << " printf(\""<<ClassName<<" ** Bad Source Type-- Requesting Conversion from %s to %s\\n\",((Dtool_PyInstDef *)self)->_My_Type->_name,requested_type->_name);fflush(NULL);\n";;
out << " return NULL;\n";
out << " }\n";
out << " \n";
out << " "<<cClassName<<" * local_this = (" << cClassName<<" *)((Dtool_PyInstDef *)self)->_ptr_to_object;\n";
out << " if(requested_type == &Dtool_"<<ClassName<<")\n";
out << " return local_this;\n";
CPPType *cpptype = TypeManager::resolve_type(obj->_itype._cpptype);
std::map< string ,CastDetails > details;
std::map< string ,CastDetails >::iterator di;
builder.get_type(TypeManager::unwrap(cpptype),false);
GetValideChildClasses(details, cpptype->as_struct_type());
for(di = details.begin(); di != details.end(); di++) for(di = details.begin(); di != details.end(); di++)
{ {
//InterrogateType ptype =idb->get_type(di->first); if(di->second._is_legal_py_class)
if(di->second._is_legal_py_class && !isExportThisRun(di->second._structType)) {
_external_imports.insert(make_safe_name(di->second._to_class_name)); out << " if(requested_type == &Dtool_"<<make_safe_name(di->second._to_class_name)<<")\n";
//out << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << make_safe_name(di->second._to_class_name) <<";\n"; out << " return "<< di->second._up_cast_string << " local_this;\n";
}
} }
out << " return NULL;\n";
out << "}\n";
{ // the Cast Converter out << "inline void * Dtool_DowncastInterface_"<< ClassName << "(void *from_this, Dtool_PyTypedObject *from_type)\n";
out << "{\n";
out << "inline void * Dtool_UpcastInterface_"<< ClassName << "(PyObject *self, Dtool_PyTypedObject *requested_type)\n"; out << " if(from_this == NULL || from_type == NULL)\n";
out << "{\n"; out << " return NULL;\n";
out << " Dtool_PyTypedObject *SelfType = ((Dtool_PyInstDef *)self)->_My_Type;\n"; out << " if(from_type == &Dtool_" << ClassName<<")\n";
out << " if(SelfType != &Dtool_" << ClassName <<")\n"; out << " return from_this;\n";
out << " {\n"; for(di = details.begin(); di != details.end(); di++)
out << " printf(\""<<ClassName<<" ** Bad Source Type-- Requesting Conversion from %s to %s\\n\",((Dtool_PyInstDef *)self)->_My_Type->_name,requested_type->_name);fflush(NULL);\n";; {
out << " return NULL;\n"; if(di->second._can_downcast && di->second._is_legal_py_class)
out << " }\n"; {
out << " \n"; out << " if(from_type == &Dtool_"<<make_safe_name(di->second._to_class_name)<<")\n";
out << " "<<cClassName<<" * local_this = (" << cClassName<<" *)((Dtool_PyInstDef *)self)->_ptr_to_object;\n"; out << " {\n";
out << " if(requested_type == &Dtool_"<<ClassName<<")\n"; out << " "<< di->second._to_class_name << "* other_this = ("<< di->second._to_class_name << "*)from_this;\n" ;
out << " return local_this;\n"; out << " return ("<< cClassName << "*)other_this;\n";
out << " }\n";
for(di = details.begin(); di != details.end(); di++) }
{ }
if(di->second._is_legal_py_class) out << " return (void *) NULL;\n";
{ out << "}\n";
out << " if(requested_type == &Dtool_"<<make_safe_name(di->second._to_class_name)<<")\n";
out << " return "<< di->second._up_cast_string << " local_this;\n";
}
}
out << " return NULL;\n";
out << "}\n";
out << "inline void * Dtool_DowncastInterface_"<< ClassName << "(void *from_this, Dtool_PyTypedObject *from_type)\n";
out << "{\n";
out << " if(from_this == NULL || from_type == NULL)\n";
out << " return NULL;\n";
out << " if(from_type == &Dtool_" << ClassName<<")\n";
out << " return from_this;\n";
for(di = details.begin(); di != details.end(); di++)
{
if(di->second._can_downcast && di->second._is_legal_py_class)
{
out << " if(from_type == &Dtool_"<<make_safe_name(di->second._to_class_name)<<")\n";
out << " {\n";
out << " "<< di->second._to_class_name << "* other_this = ("<< di->second._to_class_name << "*)from_this;\n" ;
out << " return ("<< cClassName << "*)other_this;\n";
out << " }\n";
}
}
out << " return (void *) NULL;\n";
out << "}\n";
}
}
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Function : write_ClasseDeclarations /// Function : write_ClasseDeclarations
// //
@ -1215,9 +1220,18 @@ write_module_class(ostream &out, Object *obj) {
std::map<Function *, std::string > normal_Operator_functions; std::map<Function *, std::string > normal_Operator_functions;
std::map<Function *, SlottedFunctionDef> wraped_Operator_functions; std::map<Function *, SlottedFunctionDef> wraped_Operator_functions;
// function Table // function Table
bool got_copy = false;
bool got_deepcopy = false;
int x; int x;
for (x = 0, fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi,x++) { for (x = 0, fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi,x++) {
Function *func = (*fi); Function *func = (*fi);
if (func->_name == "__copy__") {
got_copy = true;
} else if (func->_name == "__deepcopy__") {
got_deepcopy = true;
}
SlottedFunctionDef slotted_def; SlottedFunctionDef slotted_def;
if (!get_slotted_function_def(obj, func, slotted_def)) { if (!get_slotted_function_def(obj, func, slotted_def)) {
out << " { \"" << methodNameFromCppName(func,export_calss_name) << "\",(PyCFunction ) &" out << " { \"" << methodNameFromCppName(func,export_calss_name) << "\",(PyCFunction ) &"
@ -1248,6 +1262,22 @@ write_module_class(ostream &out, Object *obj) {
} }
} }
if (obj->_protocol_types & Object::PT_make_copy) {
if (!got_copy) {
out << " { \"__copy__\", (PyCFunction)&copy_from_make_copy, METH_NOARGS, NULL},\n";
got_copy = true;
}
} else if (obj->_protocol_types & Object::PT_copy_constructor) {
if (!got_copy) {
out << " { \"__copy__\", (PyCFunction)&copy_from_copy_constructor, METH_NOARGS, NULL},\n";
got_copy = true;
}
}
if (got_copy && !got_deepcopy) {
out << " { \"__deepcopy__\", (PyCFunction)&map_deepcopy_to_copy, METH_VARARGS, NULL},\n";
}
MakeSeqs::iterator msi; MakeSeqs::iterator msi;
for (msi = obj->_make_seqs.begin(); msi != obj->_make_seqs.end(); ++msi) { for (msi = obj->_make_seqs.begin(); msi != obj->_make_seqs.end(); ++msi) {
out << " { \"" out << " { \""

View File

@ -708,6 +708,42 @@ PyObject *make_list_for_item(PyObject *self, const char *num_name,
return list; return list;
} }
////////////////////////////////////////////////////////////////////
// Function: copy_from_make_copy
// Description: This is a support function for a synthesized
// __copy__() method from a C++ make_copy() method.
////////////////////////////////////////////////////////////////////
PyObject *copy_from_make_copy(PyObject *self) {
return PyObject_CallMethod(self, (char *)"makeCopy", (char *)"()");
}
////////////////////////////////////////////////////////////////////
// Function: copy_from_make_copy
// Description: This is a support function for a synthesized
// __copy__() method from a C++ copy constructor.
////////////////////////////////////////////////////////////////////
PyObject *copy_from_copy_constructor(PyObject *self) {
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *result = PyObject_CallFunction(this_class, (char *)"(O)", self);
Py_DECREF(this_class);
return result;
}
////////////////////////////////////////////////////////////////////
// Function: copy_from_make_copy
// Description: This is a support function for a synthesized
// __deepcopy__() method for any class that has a
// __copy__() method. The sythethic method simply
// invokes __copy__().
////////////////////////////////////////////////////////////////////
PyObject *map_deepcopy_to_copy(PyObject *self, PyObject *args) {
return PyObject_CallMethod(self, (char *)"__copy__", (char *)"()");
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PyLongOrInt_FromUnsignedLong // Function: PyLongOrInt_FromUnsignedLong
// Description: Similar to PyLong_FromUnsignedLong(), but returns // Description: Similar to PyLong_FromUnsignedLong(), but returns

View File

@ -174,114 +174,118 @@ struct Dtool_PyTypedObject {
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Macro's from Hell.. May want to Just Add this to the Code generator.. // Macros from Hell.. May want to just add this to the code generator..
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
#define Define_Dtool_Class(MODULE_NAME, CLASS_NAME, PUBLIC_NAME) \ #define Define_Dtool_Class(MODULE_NAME, CLASS_NAME, PUBLIC_NAME) \
static PyNumberMethods Dtool_PyNumberMethods_##CLASS_NAME ={\ static PyNumberMethods Dtool_PyNumberMethods_##CLASS_NAME = \
0,/*binaryfunc nb_add*/\ { \
0,/*binaryfunc nb_subtract*/\ 0,/*binaryfunc nb_add*/ \
0,/*binaryfunc nb_multiply*/\ 0,/*binaryfunc nb_subtract*/ \
0,/*binaryfunc nb_divide*/\ 0,/*binaryfunc nb_multiply*/ \
0,/*binaryfunc nb_remainder*/\ 0,/*binaryfunc nb_divide*/ \
0,/*binaryfunc nb_divmod*/\ 0,/*binaryfunc nb_remainder*/ \
0,/*ternaryfunc nb_power*/\ 0,/*binaryfunc nb_divmod*/ \
0,/*unaryfunc nb_negative*/\ 0,/*ternaryfunc nb_power*/ \
0,/*unaryfunc nb_positive*/\ 0,/*unaryfunc nb_negative*/ \
0,/*unaryfunc nb_absolute*/\ 0,/*unaryfunc nb_positive*/ \
0,/*inquiry nb_nonzero*/\ 0,/*unaryfunc nb_absolute*/ \
0,/*unaryfunc nb_invert*/\ 0,/*inquiry nb_nonzero*/ \
0,/*binaryfunc nb_lshift*/\ 0,/*unaryfunc nb_invert*/ \
0,/*binaryfunc nb_rshift*/\ 0,/*binaryfunc nb_lshift*/ \
0,/*binaryfunc nb_and*/\ 0,/*binaryfunc nb_rshift*/ \
0,/*binaryfunc nb_xor*/\ 0,/*binaryfunc nb_and*/ \
0,/*binaryfunc nb_or*/\ 0,/*binaryfunc nb_xor*/ \
0,/*coercion nb_coerce*/\ 0,/*binaryfunc nb_or*/ \
0,/*unaryfunc nb_int*/\ 0,/*coercion nb_coerce*/ \
0,/*unaryfunc nb_long*/\ 0,/*unaryfunc nb_int*/ \
0,/*unaryfunc nb_float*/\ 0,/*unaryfunc nb_long*/ \
0,/*unaryfunc nb_oct*/\ 0,/*unaryfunc nb_float*/ \
0,/*unaryfunc nb_hex*/\ 0,/*unaryfunc nb_oct*/ \
0,/*binaryfunc nb_inplace_add*/\ 0,/*unaryfunc nb_hex*/ \
0,/*binaryfunc nb_inplace_subtract*/\ 0,/*binaryfunc nb_inplace_add*/ \
0,/*binaryfunc nb_inplace_multiply*/\ 0,/*binaryfunc nb_inplace_subtract*/ \
0,/*binaryfunc nb_inplace_divide*/\ 0,/*binaryfunc nb_inplace_multiply*/ \
0,/*binaryfunc nb_inplace_remainder*/\ 0,/*binaryfunc nb_inplace_divide*/ \
0,/*ternaryfunc nb_inplace_power*/\ 0,/*binaryfunc nb_inplace_remainder*/ \
0,/*binaryfunc nb_inplace_lshift*/\ 0,/*ternaryfunc nb_inplace_power*/ \
0,/*binaryfunc nb_inplace_rshift*/\ 0,/*binaryfunc nb_inplace_lshift*/ \
0,/*binaryfunc nb_inplace_and*/\ 0,/*binaryfunc nb_inplace_rshift*/ \
0,/*binaryfunc nb_inplace_xor*/\ 0,/*binaryfunc nb_inplace_and*/ \
0,/*binaryfunc nb_inplace_or*/\ 0,/*binaryfunc nb_inplace_xor*/ \
0,/*binaryfunc nb_floor_divide*/\ 0,/*binaryfunc nb_inplace_or*/ \
0,/*binaryfunc nb_true_divide*/\ 0,/*binaryfunc nb_floor_divide*/ \
0,/*binaryfunc nb_inplace_floor_divide*/\ 0,/*binaryfunc nb_true_divide*/ \
0,/*binaryfunc nb_inplace_true_divide*/\ 0,/*binaryfunc nb_inplace_floor_divide*/ \
};\ 0,/*binaryfunc nb_inplace_true_divide*/ \
static PySequenceMethods Dtool_PySequenceMethods_##CLASS_NAME ={\ }; \
0,/*lenfunc sq_length */\ static PySequenceMethods Dtool_PySequenceMethods_##CLASS_NAME = \
0,/*binaryfunc sq_concat */\ { \
0,/*ssizeargfunc sq_repeat */\ 0,/*lenfunc sq_length */ \
0,/*ssizeargfunc sq_item */\ 0,/*binaryfunc sq_concat */ \
0,/*ssizeargfunc sq_ass_item */\ 0,/*ssizeargfunc sq_repeat */ \
0,/*objobjproc sq_contains */\ 0,/*ssizeargfunc sq_item */ \
0,/*binaryfunc sq_inplace_concat */\ 0,/*ssizeargfunc sq_ass_item */ \
0,/*ssizeargfunc sq_inplace_repeat */\ 0,/*objobjproc sq_contains */ \
};\ 0,/*binaryfunc sq_inplace_concat */ \
static PyMappingMethods Dtool_PyMappingMethods_##CLASS_NAME ={\ 0,/*ssizeargfunc sq_inplace_repeat */ \
0,/*inquiry mp_length */\ }; \
0,/*binaryfunc mp_subscript */\ static PyMappingMethods Dtool_PyMappingMethods_##CLASS_NAME = \
0,/*objobjargproc mp_ass_subscript */\ { \
};\ 0,/*inquiry mp_length */ \
EXPORT_THIS Dtool_PyTypedObject Dtool_##CLASS_NAME = {\ 0,/*binaryfunc mp_subscript */ \
{\ 0,/*objobjargproc mp_ass_subscript */ \
PyObject_HEAD_INIT(NULL)\ }; \
0,\ EXPORT_THIS Dtool_PyTypedObject Dtool_##CLASS_NAME = \
"lib" #MODULE_NAME "." #PUBLIC_NAME, /*type name with module */ \ { \
sizeof(Dtool_PyInstDef), /* tp_basicsize*/ \ { \
0, /*tp_itemsize*/ \ PyObject_HEAD_INIT(NULL) \
&Dtool_Deallocate_General, /*Dtool_Deallocate_##CLASS_NAME,*/ /*tp_dealloc*/\ 0, \
0, /*tp_print*/\ "lib" #MODULE_NAME "." #PUBLIC_NAME, /*type name with module */ \
0, /*tp_getattr*/\ sizeof(Dtool_PyInstDef), /* tp_basicsize */ \
0, /*tp_setattr*/\ 0, /* tp_itemsize */ \
0, /*tp_compare*/\ &Dtool_Deallocate_General, /* tp_dealloc */ \
0, /*tp_repr*/\ 0, /* tp_print */ \
&Dtool_PyNumberMethods_##CLASS_NAME, /*tp_as_number*/\ 0, /* tp_getattr */ \
&Dtool_PySequenceMethods_##CLASS_NAME, /*tp_as_sequence*/\ 0, /* tp_setattr */ \
&Dtool_PyMappingMethods_##CLASS_NAME, /*tp_as_mapping*/\ 0, /* tp_compare */ \
0, /*tp_hash */\ 0, /* tp_repr */ \
0, /* tp_call */\ &Dtool_PyNumberMethods_##CLASS_NAME, /* tp_as_number */ \
0, /* tp_str */\ &Dtool_PySequenceMethods_##CLASS_NAME, /* tp_as_sequence */ \
PyObject_GenericGetAttr, /* tp_getattro */\ &Dtool_PyMappingMethods_##CLASS_NAME, /* tp_as_mapping */ \
PyObject_GenericSetAttr, /* tp_setattro */\ 0, /* tp_hash */ \
0, /* tp_as_buffer */\ 0, /* tp_call */ \
(Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES), /* tp_flags */\ 0, /* tp_str */ \
0, /* tp_doc */\ PyObject_GenericGetAttr, /* tp_getattro */ \
0, /* tp_traverse */\ PyObject_GenericSetAttr, /* tp_setattro */ \
0, /* tp_clear */\ 0, /* tp_as_buffer */ \
0, /* tp_richcompare */\ (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES), /* tp_flags */ \
0, /* tp_weaklistoffset */\ 0, /* tp_doc */ \
0, /* tp_iter */\ 0, /* tp_traverse */ \
0, /* tp_iternext */\ 0, /* tp_clear */ \
Dtool_Methods_##CLASS_NAME, /* tp_methods */\ 0, /* tp_richcompare */ \
standard_type_members, /* tp_members */\ 0, /* tp_weaklistoffset */ \
0, /* tp_getset */\ 0, /* tp_iter */ \
0, /* tp_base */\ 0, /* tp_iternext */ \
0, /* tp_dict */\ Dtool_Methods_##CLASS_NAME, /* tp_methods */ \
0, /* tp_descr_get */\ standard_type_members, /* tp_members */ \
0, /* tp_descr_set */\ 0, /* tp_getset */ \
0, /* tp_dictoffset */\ 0, /* tp_base */ \
Dtool_Init_##CLASS_NAME, /* tp_init */\ 0, /* tp_dict */ \
PyType_GenericAlloc, /* tp_alloc */\ 0, /* tp_descr_get */ \
Dtool_new_##CLASS_NAME, /* tp_new */\ 0, /* tp_descr_set */ \
_PyObject_Del, /* tp_free */\ 0, /* tp_dictoffset */ \
},\ Dtool_Init_##CLASS_NAME, /* tp_init */ \
#CLASS_NAME, \ PyType_GenericAlloc, /* tp_alloc */ \
false,\ Dtool_new_##CLASS_NAME, /* tp_new */ \
Dtool_UpcastInterface_##CLASS_NAME, \ _PyObject_Del, /* tp_free */ \
Dtool_DowncastInterface_##CLASS_NAME, \ }, \
Dtool_FreeInstance_##CLASS_NAME, \ #CLASS_NAME, \
Dtool_PyModuleClassInit_##CLASS_NAME\ false, \
}; Dtool_UpcastInterface_##CLASS_NAME, \
Dtool_DowncastInterface_##CLASS_NAME, \
Dtool_FreeInstance_##CLASS_NAME, \
Dtool_PyModuleClassInit_##CLASS_NAME \
};
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -538,6 +542,16 @@ EXPCL_DTOOLCONFIG int DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2);
EXPCL_DTOOLCONFIG PyObject * EXPCL_DTOOLCONFIG PyObject *
make_list_for_item(PyObject *self, const char *num_name, make_list_for_item(PyObject *self, const char *num_name,
const char *element_name); const char *element_name);
EXPCL_DTOOLCONFIG PyObject *
copy_from_make_copy(PyObject *self);
EXPCL_DTOOLCONFIG PyObject *
copy_from_copy_constructor(PyObject *self);
EXPCL_DTOOLCONFIG PyObject *
map_deepcopy_to_copy(PyObject *self, PyObject *args);
EXPCL_DTOOLCONFIG PyObject * EXPCL_DTOOLCONFIG PyObject *
PyLongOrInt_FromUnsignedLong(unsigned long value); PyLongOrInt_FromUnsignedLong(unsigned long value);

View File

@ -51,6 +51,7 @@ extern "C" {
EXPCL_DTOOLCONFIG int PyGen_Type(...); EXPCL_DTOOLCONFIG int PyGen_Type(...);
EXPCL_DTOOLCONFIG int PyGILState_Ensure(...); EXPCL_DTOOLCONFIG int PyGILState_Ensure(...);
EXPCL_DTOOLCONFIG int PyGILState_Release(...); EXPCL_DTOOLCONFIG int PyGILState_Release(...);
EXPCL_DTOOLCONFIG int PyImport_GetModuleDict(...);
EXPCL_DTOOLCONFIG int PyInt_AsLong(...); EXPCL_DTOOLCONFIG int PyInt_AsLong(...);
EXPCL_DTOOLCONFIG int PyInt_AsSsize_t(...); EXPCL_DTOOLCONFIG int PyInt_AsSsize_t(...);
EXPCL_DTOOLCONFIG int PyInt_FromLong(...); EXPCL_DTOOLCONFIG int PyInt_FromLong(...);
@ -74,6 +75,7 @@ extern "C" {
EXPCL_DTOOLCONFIG int PyModule_AddObject(...); EXPCL_DTOOLCONFIG int PyModule_AddObject(...);
EXPCL_DTOOLCONFIG int PyNumber_Long(...); EXPCL_DTOOLCONFIG int PyNumber_Long(...);
EXPCL_DTOOLCONFIG int PyObject_Call(...); EXPCL_DTOOLCONFIG int PyObject_Call(...);
EXPCL_DTOOLCONFIG int PyObject_CallFunction(...);
EXPCL_DTOOLCONFIG int PyObject_CallMethod(...); EXPCL_DTOOLCONFIG int PyObject_CallMethod(...);
EXPCL_DTOOLCONFIG int PyObject_CallMethodObjArgs(...); EXPCL_DTOOLCONFIG int PyObject_CallMethodObjArgs(...);
EXPCL_DTOOLCONFIG int PyObject_CallObject(...); EXPCL_DTOOLCONFIG int PyObject_CallObject(...);
@ -88,6 +90,7 @@ extern "C" {
EXPCL_DTOOLCONFIG int PyObject_Repr(...); EXPCL_DTOOLCONFIG int PyObject_Repr(...);
EXPCL_DTOOLCONFIG int PyObject_SetAttrString(...); EXPCL_DTOOLCONFIG int PyObject_SetAttrString(...);
EXPCL_DTOOLCONFIG int PyObject_Str(...); EXPCL_DTOOLCONFIG int PyObject_Str(...);
EXPCL_DTOOLCONFIG int PyObject_Type(...);
EXPCL_DTOOLCONFIG int PySequence_Check(...); EXPCL_DTOOLCONFIG int PySequence_Check(...);
EXPCL_DTOOLCONFIG int PySequence_GetItem(...); EXPCL_DTOOLCONFIG int PySequence_GetItem(...);
EXPCL_DTOOLCONFIG int PySequence_Size(...); EXPCL_DTOOLCONFIG int PySequence_Size(...);
@ -180,6 +183,7 @@ int PyGen_Check(...) { return 0; }
int PyGen_Type(...) { return 0; } int PyGen_Type(...) { return 0; }
int PyGILState_Ensure(...) { return 0; } int PyGILState_Ensure(...) { return 0; }
int PyGILState_Release(...) { return 0; } int PyGILState_Release(...) { return 0; }
int PyImport_GetModuleDict(...) { return 0; }
int PyInt_AsLong(...) { return 0; } int PyInt_AsLong(...) { return 0; }
int PyInt_AsSsize_t(...) { return 0; } int PyInt_AsSsize_t(...) { return 0; }
int PyInt_FromLong(...) { return 0; } int PyInt_FromLong(...) { return 0; }
@ -203,6 +207,7 @@ int PyModule_AddIntConstant(...) { return 0; };
int PyModule_AddObject(...) { return 0; }; int PyModule_AddObject(...) { return 0; };
int PyNumber_Long(...) { return 0; } int PyNumber_Long(...) { return 0; }
int PyObject_Call(...) { return 0; } int PyObject_Call(...) { return 0; }
int PyObject_CallFunction(...) { return 0; }
int PyObject_CallMethod(...) { return 0; } int PyObject_CallMethod(...) { return 0; }
int PyObject_CallMethodObjArgs(...) { return 0; } int PyObject_CallMethodObjArgs(...) { return 0; }
int PyObject_CallObject(...) { return 0; } int PyObject_CallObject(...) { return 0; }
@ -217,6 +222,7 @@ int PyObject_IsTrue(...) { return 0; }
int PyObject_Repr(...) { return 0; } int PyObject_Repr(...) { return 0; }
int PyObject_SetAttrString(...) { return 0; } int PyObject_SetAttrString(...) { return 0; }
int PyObject_Str(...) { return 0; } int PyObject_Str(...) { return 0; }
int PyObject_Type(...) { return 0; }
int PySequence_Check(...) { return 0; } int PySequence_Check(...) { return 0; }
int PySequence_GetItem(...) { return 0; } int PySequence_GetItem(...) { return 0; }
int PySequence_Size(...) { return 0; } int PySequence_Size(...) { return 0; }

View File

@ -46,6 +46,33 @@ const FLOATNAME(LMatrix3) FLOATNAME(LMatrix3)::_ly_to_rz_mat =
FLOATNAME(LMatrix3)::_flip_z_mat * FLOATNAME(LMatrix3)::_y_to_z_up_mat; FLOATNAME(LMatrix3)::_flip_z_mat * FLOATNAME(LMatrix3)::_y_to_z_up_mat;
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: LMatrix3::__reduce__
// Access: Published
// Description: This special Python method is implement to provide
// support for the pickle module.
////////////////////////////////////////////////////////////////////
PyObject *FLOATNAME(LMatrix3)::
__reduce__(PyObject *self) const {
// We should return at least a 2-tuple, (Class, (args)): the
// necessary class object whose constructor we should call
// (e.g. this), and the arguments necessary to reconstruct this
// object.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *result = Py_BuildValue("(O(fffffffff))", this_class,
_m.m._00, _m.m._01, _m.m._02,
_m.m._10, _m.m._11, _m.m._12,
_m.m._20, _m.m._21, _m.m._22);
Py_DECREF(this_class);
return result;
}
#endif // HAVE_PYTHON
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: LMatrix::set_scale_shear_mat // Function: LMatrix::set_scale_shear_mat
// Access: Public // Access: Public

View File

@ -65,6 +65,10 @@ PUBLISHED:
FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22); FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22);
ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix3)); ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix3));
#ifdef HAVE_PYTHON
PyObject *__reduce__(PyObject *self) const;
#endif
void fill(FLOATTYPE fill_value); void fill(FLOATTYPE fill_value);
INLINE_LINMATH void set( INLINE_LINMATH void set(
FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02, FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02,

View File

@ -62,6 +62,35 @@ const FLOATNAME(LMatrix4) FLOATNAME(LMatrix4)::_lz_to_ry_mat =
const FLOATNAME(LMatrix4) FLOATNAME(LMatrix4)::_ly_to_rz_mat = const FLOATNAME(LMatrix4) FLOATNAME(LMatrix4)::_ly_to_rz_mat =
FLOATNAME(LMatrix4)::_flip_z_mat * FLOATNAME(LMatrix4)::_y_to_z_up_mat; FLOATNAME(LMatrix4)::_flip_z_mat * FLOATNAME(LMatrix4)::_y_to_z_up_mat;
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: LMatrix4::__reduce__
// Access: Published
// Description: This special Python method is implement to provide
// support for the pickle module.
////////////////////////////////////////////////////////////////////
PyObject *FLOATNAME(LMatrix4)::
__reduce__(PyObject *self) const {
// We should return at least a 2-tuple, (Class, (args)): the
// necessary class object whose constructor we should call
// (e.g. this), and the arguments necessary to reconstruct this
// object.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *result = Py_BuildValue("(O(ffffffffffffffff))", this_class,
_m.m._00, _m.m._01, _m.m._02, _m.m._03,
_m.m._10, _m.m._11, _m.m._12, _m.m._13,
_m.m._20, _m.m._21, _m.m._22, _m.m._23,
_m.m._30, _m.m._31, _m.m._32, _m.m._33);
Py_DECREF(this_class);
return result;
}
#endif // HAVE_PYTHON
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: LMatrix::convert_mat // Function: LMatrix::convert_mat
// Access: Public, Static // Access: Public, Static

View File

@ -60,6 +60,10 @@ PUBLISHED:
FLOATTYPE e30, FLOATTYPE e31, FLOATTYPE e32, FLOATTYPE e33); FLOATTYPE e30, FLOATTYPE e31, FLOATTYPE e32, FLOATTYPE e33);
ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix4)); ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix4));
#ifdef HAVE_PYTHON
PyObject *__reduce__(PyObject *self) const;
#endif
// Construct a 4x4 matrix given a 3x3 rotation matrix and an optional // Construct a 4x4 matrix given a 3x3 rotation matrix and an optional
// translation component. // translation component.
INLINE_LINMATH FLOATNAME(LMatrix4)(const FLOATNAME(LMatrix3) &upper3); INLINE_LINMATH FLOATNAME(LMatrix4)(const FLOATNAME(LMatrix3) &upper3);

View File

@ -21,6 +21,31 @@ const FLOATNAME(LVecBase2) FLOATNAME(LVecBase2)::_unit_x =
const FLOATNAME(LVecBase2) FLOATNAME(LVecBase2)::_unit_y = const FLOATNAME(LVecBase2) FLOATNAME(LVecBase2)::_unit_y =
FLOATNAME(LVecBase2)(0.0f, 1.0f); FLOATNAME(LVecBase2)(0.0f, 1.0f);
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: LVecBase2::__reduce__
// Access: Published
// Description: This special Python method is implement to provide
// support for the pickle module.
////////////////////////////////////////////////////////////////////
PyObject *FLOATNAME(LVecBase2)::
__reduce__(PyObject *self) const {
// We should return at least a 2-tuple, (Class, (args)): the
// necessary class object whose constructor we should call
// (e.g. this), and the arguments necessary to reconstruct this
// object.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *result = Py_BuildValue("(O(ff))", this_class,
(*this)[0], (*this)[1]);
Py_DECREF(this_class);
return result;
}
#endif // HAVE_PYTHON
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: LVecBase2::init_type // Function: LVecBase2::init_type
// Access: Public, Static // Access: Public, Static

View File

@ -39,6 +39,10 @@ PUBLISHED:
INLINE_LINMATH ~FLOATNAME(LVecBase2)(); INLINE_LINMATH ~FLOATNAME(LVecBase2)();
#ifdef HAVE_PYTHON
PyObject *__reduce__(PyObject *self) const;
#endif
INLINE_LINMATH FLOATTYPE operator [](int i) const; INLINE_LINMATH FLOATTYPE operator [](int i) const;
INLINE_LINMATH FLOATTYPE &operator [](int i); INLINE_LINMATH FLOATTYPE &operator [](int i);
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON

View File

@ -12,6 +12,7 @@
// //
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
TypeHandle FLOATNAME(LVecBase3)::_type_handle; TypeHandle FLOATNAME(LVecBase3)::_type_handle;
const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_zero = const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_zero =
@ -23,6 +24,32 @@ const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_unit_y =
const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_unit_z = const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_unit_z =
FLOATNAME(LVecBase3)(0.0f, 0.0f, 1.0f); FLOATNAME(LVecBase3)(0.0f, 0.0f, 1.0f);
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: LVecBase3::__reduce__
// Access: Published
// Description: This special Python method is implement to provide
// support for the pickle module.
////////////////////////////////////////////////////////////////////
PyObject *FLOATNAME(LVecBase3)::
__reduce__(PyObject *self) const {
// We should return at least a 2-tuple, (Class, (args)): the
// necessary class object whose constructor we should call
// (e.g. this), and the arguments necessary to reconstruct this
// object.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *result = Py_BuildValue("(O(fff))", this_class,
(*this)[0], (*this)[1], (*this)[2]);
Py_DECREF(this_class);
return result;
}
#endif // HAVE_PYTHON
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: LVecBase3::init_type // Function: LVecBase3::init_type
// Access: Public, Static // Access: Public, Static

View File

@ -37,6 +37,10 @@ PUBLISHED:
INLINE_LINMATH ~FLOATNAME(LVecBase3)(); INLINE_LINMATH ~FLOATNAME(LVecBase3)();
#ifdef HAVE_PYTHON
PyObject *__reduce__(PyObject *self) const;
#endif
INLINE_LINMATH FLOATTYPE operator [](int i) const; INLINE_LINMATH FLOATTYPE operator [](int i) const;
INLINE_LINMATH FLOATTYPE &operator [](int i); INLINE_LINMATH FLOATTYPE &operator [](int i);
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON

View File

@ -25,6 +25,31 @@ const FLOATNAME(LVecBase4) FLOATNAME(LVecBase4)::_unit_z =
const FLOATNAME(LVecBase4) FLOATNAME(LVecBase4)::_unit_w = const FLOATNAME(LVecBase4) FLOATNAME(LVecBase4)::_unit_w =
FLOATNAME(LVecBase4)(0.0f, 0.0f, 0.0f, 1.0f); FLOATNAME(LVecBase4)(0.0f, 0.0f, 0.0f, 1.0f);
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: LVecBase4::__reduce__
// Access: Published
// Description: This special Python method is implement to provide
// support for the pickle module.
////////////////////////////////////////////////////////////////////
PyObject *FLOATNAME(LVecBase4)::
__reduce__(PyObject *self) const {
// We should return at least a 2-tuple, (Class, (args)): the
// necessary class object whose constructor we should call
// (e.g. this), and the arguments necessary to reconstruct this
// object.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *result = Py_BuildValue("(O(ffff))", this_class,
(*this)[0], (*this)[1], (*this)[2], (*this)[3]);
Py_DECREF(this_class);
return result;
}
#endif // HAVE_PYTHON
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: LVecBase4::init_type // Function: LVecBase4::init_type
// Access: Public, Static // Access: Public, Static

View File

@ -38,6 +38,10 @@ PUBLISHED:
INLINE_LINMATH ~FLOATNAME(LVecBase4)(); INLINE_LINMATH ~FLOATNAME(LVecBase4)();
#ifdef HAVE_PYTHON
PyObject *__reduce__(PyObject *self) const;
#endif
INLINE_LINMATH FLOATTYPE operator [](int i) const; INLINE_LINMATH FLOATTYPE operator [](int i) const;
INLINE_LINMATH FLOATTYPE &operator [](int i); INLINE_LINMATH FLOATTYPE &operator [](int i);
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON

View File

@ -66,6 +66,7 @@
#include "pStatCollector.h" #include "pStatCollector.h"
#include "pStatTimer.h" #include "pStatTimer.h"
#include "modelNode.h" #include "modelNode.h"
#include "py_panda.h"
// stack seems to overflow on Intel C++ at 7000. If we need more than // stack seems to overflow on Intel C++ at 7000. If we need more than
// 7000, need to increase stack size. // 7000, need to increase stack size.
@ -127,6 +128,128 @@ static ConfigVariableEnum<EmptyNodePathType> empty_node_path
// ***End temporary transition code for operator bool // ***End temporary transition code for operator bool
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::__copy__
// Access: Published
// Description: A special Python method that is invoked by
// copy.copy(node). Unlike the NodePath copy
// constructor, this makes a duplicate copy of the
// underlying PandaNode (but shares children, instead of
// copying them or omitting them).
////////////////////////////////////////////////////////////////////
NodePath NodePath::
__copy__() const {
if (is_empty()) {
// Invoke the copy constructor if we have no node.
return *this;
}
// If we do have a node, duplicate it, and wrap it in a new
// NodePath.
return NodePath(node()->__copy__());
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::__deepcopy__
// Access: Published
// Description: A special Python method that is invoked by
// copy.deepcopy(np). This calls copy_to() unless the
// NodePath is already present in the provided
// dictionary.
////////////////////////////////////////////////////////////////////
PyObject *NodePath::
__deepcopy__(PyObject *self, PyObject *memo) const {
IMPORT_THIS struct Dtool_PyTypedObject Dtool_NodePath;
// Borrowed reference.
PyObject *dupe = PyDict_GetItem(memo, self);
if (dupe != NULL) {
// Already in the memo dictionary.
Py_INCREF(dupe);
return dupe;
}
NodePath *np_dupe;
if (is_empty()) {
np_dupe = new NodePath(*this);
} else {
np_dupe = new NodePath(copy_to(NodePath()));
}
dupe = DTool_CreatePyInstance((void *)np_dupe, Dtool_NodePath,
true, false);
if (PyDict_SetItem(memo, self, dupe) != 0) {
Py_DECREF(dupe);
return NULL;
}
return dupe;
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: NodePath::__reduce__
// Access: Published
// Description: This special Python method is implement to provide
// support for the pickle module.
////////////////////////////////////////////////////////////////////
PyObject *NodePath::
__reduce__(PyObject *self) const {
// We should return at least a 2-tuple, (Class, (args)): the
// necessary class object whose constructor we should call
// (e.g. this), and the arguments necessary to reconstruct this
// object.
if (is_empty()) {
// Reconstruct an empty NodePath. Not a 100% reconstruction,
// because we lose the specific error status, but I don't think
// that matters much.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *result = Py_BuildValue("(O())", this_class);
Py_DECREF(this_class);
return result;
}
// We have a non-empty NodePath. We need to streamify the
// underlying node.
string bam_stream;
if (!node()->encode_to_bam_stream(bam_stream)) {
ostringstream stream;
stream << "Could not bamify object of type " << node()->get_type() << "\n";
string message = stream.str();
PyErr_SetString(PyExc_TypeError, message.c_str());
return NULL;
}
// Start by getting this class object.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *func = TypedWritable::find_global_decode(this_class, "pyDecodeNodePathFromBamStream");
if (func == NULL) {
PyErr_SetString(PyExc_TypeError, "Couldn't find pyDecodeNodePathFromBamStream()");
Py_DECREF(this_class);
return NULL;
}
Py_DECREF(this_class);
PyObject *result = Py_BuildValue("(O(s#))", func, bam_stream.data(), bam_stream.size());
Py_DECREF(func);
return result;
}
#endif // HAVE_PYTHON
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: NodePath::operator bool // Function: NodePath::operator bool
// Access: Published // Access: Published
@ -7292,3 +7415,23 @@ r_find_all_materials(PandaNode *node, const RenderState *state,
r_find_all_materials(child, next_state, materials); r_find_all_materials(child, next_state, materials);
} }
} }
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: py_decode_NodePath_from_bam_stream
// Access: Published
// Description: This wrapper is defined as a global function to suit
// pickle's needs.
////////////////////////////////////////////////////////////////////
NodePath
py_decode_NodePath_from_bam_stream(const string &data) {
PT(PandaNode) node = PandaNode::decode_from_bam_stream(data);
if (node == (PandaNode *)NULL) {
PyErr_SetString(PyExc_ValueError, "Could not unpack bam stream");
return NodePath();
}
return NodePath(node);
}
#endif // HAVE_PYTHON

View File

@ -168,6 +168,12 @@ PUBLISHED:
INLINE NodePath(const NodePath &copy); INLINE NodePath(const NodePath &copy);
INLINE void operator = (const NodePath &copy); INLINE void operator = (const NodePath &copy);
#ifdef HAVE_PYTHON
NodePath __copy__() const;
PyObject *__deepcopy__(PyObject *self, PyObject *memo) const;
PyObject *__reduce__(PyObject *self) const;
#endif
INLINE static NodePath not_found(); INLINE static NodePath not_found();
INLINE static NodePath removed(); INLINE static NodePath removed();
INLINE static NodePath fail(); INLINE static NodePath fail();
@ -949,6 +955,12 @@ private:
INLINE ostream &operator << (ostream &out, const NodePath &node_path); INLINE ostream &operator << (ostream &out, const NodePath &node_path);
#ifdef HAVE_PYTHON
BEGIN_PUBLISH
NodePath py_decode_NodePath_from_bam_stream(const string &data);
END_PUBLISH
#endif
#include "nodePath.I" #include "nodePath.I"
#endif #endif

View File

@ -28,6 +28,7 @@
#include "config_mathutil.h" #include "config_mathutil.h"
#include "lightReMutexHolder.h" #include "lightReMutexHolder.h"
#include "graphicsStateGuardianBase.h" #include "graphicsStateGuardianBase.h"
#include "py_panda.h"
// This category is just temporary for debugging convenience. // This category is just temporary for debugging convenience.
NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH); NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
@ -211,20 +212,6 @@ as_reference_count() {
return this; return this;
} }
////////////////////////////////////////////////////////////////////
// Function: PandaNode::make_copy
// Access: Public, Virtual
// Description: Returns a newly-allocated PandaNode that is a shallow
// copy of this one. It will be a different pointer,
// but its internal data may or may not be shared with
// that of the original PandaNode. No children will be
// copied.
////////////////////////////////////////////////////////////////////
PandaNode *PandaNode::
make_copy() const {
return new PandaNode(*this);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::dupe_for_flatten // Function: PandaNode::dupe_for_flatten
// Access: Public, Virtual // Access: Public, Virtual
@ -608,6 +595,20 @@ void PandaNode::
add_for_draw(CullTraverser *, CullTraverserData &) { add_for_draw(CullTraverser *, CullTraverserData &) {
} }
////////////////////////////////////////////////////////////////////
// Function: PandaNode::make_copy
// Access: Published, Virtual
// Description: Returns a newly-allocated PandaNode that is a shallow
// copy of this one. It will be a different pointer,
// but its internal data may or may not be shared with
// that of the original PandaNode. No children will be
// copied.
////////////////////////////////////////////////////////////////////
PandaNode *PandaNode::
make_copy() const {
return new PandaNode(*this);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::copy_subgraph // Function: PandaNode::copy_subgraph
// Access: Published // Access: Published
@ -618,12 +619,79 @@ add_for_draw(CullTraverser *, CullTraverserData &) {
// will impede normal use of the PandaNode. // will impede normal use of the PandaNode.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
PT(PandaNode) PandaNode:: PT(PandaNode) PandaNode::
copy_subgraph(Thread *current_thread) const copy_subgraph(Thread *current_thread) const {
{
InstanceMap inst_map; InstanceMap inst_map;
return r_copy_subgraph(inst_map, current_thread); return r_copy_subgraph(inst_map, current_thread);
} }
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::__copy__
// Access: Published
// Description: A special Python method that is invoked by
// copy.copy(node). Unlike the PandaNode copy
// constructor, which creates a new node without
// children, this shares child pointers (essentially
// making every child an instance). This is intended to
// simulate the behavior of copy.copy() for other
// objects.
////////////////////////////////////////////////////////////////////
PT(PandaNode) PandaNode::
__copy__() const {
Thread *current_thread = Thread::get_current_thread();
PT(PandaNode) node_dupe = make_copy();
Children children = get_children(current_thread);
int num_children = children.get_num_children();
for (int i = 0; i < num_children; ++i) {
PandaNode *child = children.get_child(i);
node_dupe->add_child(children.get_child(i), children.get_child_sort(i));
}
return node_dupe;
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: PandaNode::__deepcopy__
// Access: Published
// Description: A special Python method that is invoked by
// copy.deepcopy(node). This calls copy_subgraph()
// unless the node is already present in the provided
// dictionary.
////////////////////////////////////////////////////////////////////
PyObject *PandaNode::
__deepcopy__(PyObject *self, PyObject *memo) const {
IMPORT_THIS struct Dtool_PyTypedObject Dtool_PandaNode;
// Borrowed reference.
PyObject *dupe = PyDict_GetItem(memo, self);
if (dupe != NULL) {
// Already in the memo dictionary.
Py_INCREF(dupe);
return dupe;
}
PT(PandaNode) node_dupe = copy_subgraph();
// DTool_CreatePyInstanceTyped() steals a C++ reference.
node_dupe->ref();
dupe = DTool_CreatePyInstanceTyped
((void *)node_dupe.p(), Dtool_PandaNode, true, false,
node_dupe->get_type_index());
if (PyDict_SetItem(memo, self, dupe) != 0) {
Py_DECREF(dupe);
return NULL;
}
return dupe;
}
#endif // HAVE_PYTHON
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::count_num_descendants // Function: PandaNode::count_num_descendants
// Access: Published // Access: Published
@ -2597,6 +2665,32 @@ is_ambient_light() const {
return false; return false;
} }
////////////////////////////////////////////////////////////////////
// Function: PandaNode::decode_from_bam_stream
// Access: Published, Static
// Description: Reads the string created by a previous call to
// encode_to_bam_stream(), and extracts and returns the
// single object on that string. Returns NULL on error.
//
// This method is intended to replace
// decode_raw_from_bam_stream() when you know the stream
// in question returns an object of type PandaNode,
// allowing for easier reference count management. Note
// that the caller is still responsible for maintaining
// the reference count on the return value.
////////////////////////////////////////////////////////////////////
PT(PandaNode) PandaNode::
decode_from_bam_stream(const string &data) {
TypedWritable *object;
ReferenceCount *ref_ptr;
if (!TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, data)) {
return NULL;
}
return DCAST(PandaNode, object);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_internal_bounds // Function: PandaNode::get_internal_bounds
// Access: Protected // Access: Protected

View File

@ -84,7 +84,6 @@ private:
public: public:
virtual ReferenceCount *as_reference_count(); virtual ReferenceCount *as_reference_count();
virtual PandaNode *make_copy() const;
virtual PandaNode *dupe_for_flatten() const; virtual PandaNode *dupe_for_flatten() const;
virtual bool safe_to_flatten() const; virtual bool safe_to_flatten() const;
@ -116,8 +115,14 @@ public:
virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data); virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data);
PUBLISHED: PUBLISHED:
virtual PandaNode *make_copy() const;
PT(PandaNode) copy_subgraph(Thread *current_thread = Thread::get_current_thread()) const; PT(PandaNode) copy_subgraph(Thread *current_thread = Thread::get_current_thread()) const;
#ifdef HAVE_PYTHON
PT(PandaNode) __copy__() const;
PyObject *__deepcopy__(PyObject *self, PyObject *memo) const;
#endif
INLINE int get_num_parents(Thread *current_thread = Thread::get_current_thread()) const; INLINE int get_num_parents(Thread *current_thread = Thread::get_current_thread()) const;
INLINE PandaNode *get_parent(int n, Thread *current_thread = Thread::get_current_thread()) const; INLINE PandaNode *get_parent(int n, Thread *current_thread = Thread::get_current_thread()) const;
INLINE int find_parent(PandaNode *node, Thread *current_thread = Thread::get_current_thread()) const; INLINE int find_parent(PandaNode *node, Thread *current_thread = Thread::get_current_thread()) const;
@ -300,6 +305,10 @@ PUBLISHED:
}; };
INLINE int get_fancy_bits(Thread *current_thread = Thread::get_current_thread()) const; INLINE int get_fancy_bits(Thread *current_thread = Thread::get_current_thread()) const;
PUBLISHED:
static PT(PandaNode) decode_from_bam_stream(const string &data);
protected: protected:
class BoundsData; class BoundsData;

View File

@ -66,3 +66,28 @@ INLINE UpdateSeq TypedWritable::
get_bam_modified() const { get_bam_modified() const {
return _bam_modified; return _bam_modified;
} }
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::encode_to_bam_stream
// Access: Published
// Description: Converts the TypedWritable object into a single
// stream of data using a BamWriter, and returns that
// data as a string string. Returns empty string on
// failure.
//
// This is a convenience method particularly useful for
// cases when you are only serializing a single object.
// If you have many objects to process, it is more
// efficient to use the same BamWriter to serialize all
// of them together.
////////////////////////////////////////////////////////////////////
string TypedWritable::
encode_to_bam_stream() const {
string data;
if (!encode_to_bam_stream(data)) {
return string();
}
return data;
}

View File

@ -14,7 +14,11 @@
#include "typedWritable.h" #include "typedWritable.h"
#include "bamWriter.h" #include "bamWriter.h"
#include "bamReader.h"
#include "datagramOutputFile.h"
#include "datagramInputFile.h"
#include "lightMutexHolder.h" #include "lightMutexHolder.h"
#include "bam.h"
LightMutex TypedWritable::_bam_writers_lock; LightMutex TypedWritable::_bam_writers_lock;
@ -144,3 +148,276 @@ ReferenceCount *TypedWritable::
as_reference_count() { as_reference_count() {
return NULL; return NULL;
} }
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::__reduce__
// Access: Published
// Description: This special Python method is implement to provide
// support for the pickle module.
////////////////////////////////////////////////////////////////////
PyObject *TypedWritable::
__reduce__(PyObject *self) const {
// We should return at least a 2-tuple, (Class, (args)): the
// necessary class object whose constructor we should call
// (e.g. this), and the arguments necessary to reconstruct this
// object.
// Check that we have a decodeFromBamStream python method. If not,
// we can't use this interface.
PyObject *method = PyObject_GetAttrString(self, "decodeFromBamStream");
if (method == NULL) {
ostringstream stream;
stream << "Cannot pickle objects of type " << get_type() << "\n";
string message = stream.str();
PyErr_SetString(PyExc_TypeError, message.c_str());
return NULL;
}
Py_DECREF(method);
// First, streamify the object, if possible.
string bam_stream;
if (!encode_to_bam_stream(bam_stream)) {
ostringstream stream;
stream << "Could not bamify object of type " << get_type() << "\n";
string message = stream.str();
PyErr_SetString(PyExc_TypeError, message.c_str());
return NULL;
}
// Start by getting this class object.
PyObject *this_class = PyObject_Type(self);
if (this_class == NULL) {
return NULL;
}
PyObject *func = find_global_decode(this_class, "pyDecodeTypedWritableFromBamStream");
if (func == NULL) {
PyErr_SetString(PyExc_TypeError, "Couldn't find pyDecodeTypedWritableFromBamStream()");
Py_DECREF(this_class);
return NULL;
}
PyObject *result = Py_BuildValue("(O(Os#))", func, this_class, bam_stream.data(), bam_stream.size());
Py_DECREF(func);
Py_DECREF(this_class);
return result;
}
#endif // HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::encode_to_bam_stream
// Access: Published
// Description: Converts the TypedWritable object into a single
// stream of data using a BamWriter, and stores that
// data in the indicated string. Returns true on
// success, false on failure.
//
// This is a convenience method particularly useful for
// cases when you are only serializing a single object.
// If you have many objects to process, it is more
// efficient to use the same BamWriter to serialize all
// of them together.
////////////////////////////////////////////////////////////////////
bool TypedWritable::
encode_to_bam_stream(string &data) const {
data.clear();
ostringstream stream;
// We use nested scoping to ensure the destructors get called in the
// right order.
{
DatagramOutputFile dout;
if (!dout.open(stream)) {
return false;
}
if (!dout.write_header(_bam_header)) {
return false;
}
{
BamWriter writer(&dout, "bam_stream");
if (!writer.init()) {
return false;
}
if (!writer.write_object(this)) {
return false;
}
}
}
data = stream.str();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::decode_raw_from_bam_stream
// Access: Published, Static
// Description: Reads the string created by a previous call to
// encode_to_bam_stream(), and extracts the single
// object on that string. Returns true on success,
// false on on error.
//
// This variant sets the TypedWritable and
// ReferenceCount pointers separately; both are pointers
// to the same object. The reference count is not
// incremented; it is the caller's responsibility to
// manage the reference count.
//
// Note that this method cannot be used to retrieve
// objects that do not inherit from ReferenceCount,
// because these objects cannot persist beyond the
// lifetime of the BamReader that reads them. To
// retrieve these objects from a bam stream, you must
// construct a BamReader directly.
//
// If you happen to know that the particular object in
// question inherits from TypedWritableReferenceCount or
// PandaNode, consider calling the variant of
// decode_from_bam_stream() defined for those methods,
// which presents a simpler interface.
////////////////////////////////////////////////////////////////////
bool TypedWritable::
decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr,
const string &data) {
istringstream stream(data);
DatagramInputFile din;
if (!din.open(stream)) {
return false;
}
string head;
if (!din.read_header(head, _bam_header.size())) {
return false;
}
if (head != _bam_header) {
return false;
}
// We scope this so we can control when the BamReader destructs.
{
BamReader reader(&din, "bam_stream");
if (!reader.init()) {
return false;
}
if (!reader.read_object(ptr, ref_ptr)) {
return false;
}
if (!reader.resolve()) {
return false;
}
if (ref_ptr == NULL) {
// Can't support non-reference-counted objects.
return false;
}
// Protect the pointer from accidental deletion when the BamReader
// goes away.
ref_ptr->ref();
}
// Now decrement the ref count, without deleting the object. This
// may reduce the reference count to zero, but that's OK--we trust
// the caller to manage the reference count from this point on.
ref_ptr->unref();
return true;
}
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: TypedWritable::find_global_decode
// Access: Public, Static
// Description: This is a support function for __reduce__(). It
// searches for the global function
// pyDecodeTypedWritableFromBamStream() in this class's
// module, or in the module for any base class. (It's
// really looking for the libpanda module, but we can't
// be sure what name that module was loaded under, so we
// search upwards this way.)
//
// Returns: new reference on success, or NULL on failure.
////////////////////////////////////////////////////////////////////
PyObject *TypedWritable::
find_global_decode(PyObject *this_class, const char *func_name) {
PyObject *module_name = PyObject_GetAttrString(this_class, "__module__");
if (module_name != NULL) {
// borrowed reference
PyObject *sys_modules = PyImport_GetModuleDict();
if (sys_modules != NULL) {
// borrowed reference
PyObject *module = PyDict_GetItem(sys_modules, module_name);
if (module != NULL){
PyObject *func = PyObject_GetAttrString(module, func_name);
if (func != NULL) {
Py_DECREF(module_name);
return func;
}
}
}
}
Py_DECREF(module_name);
PyObject *bases = PyObject_GetAttrString(this_class, "__bases__");
if (bases != NULL) {
if (PySequence_Check(bases)) {
Py_ssize_t size = PySequence_Size(bases);
for (Py_ssize_t i = 0; i < size; ++i) {
PyObject *base = PySequence_GetItem(bases, i);
if (base != NULL) {
PyObject *func = find_global_decode(base, func_name);
Py_DECREF(base);
if (func != NULL) {
Py_DECREF(bases);
return func;
}
}
}
}
Py_DECREF(bases);
}
return NULL;
}
#endif // HAVE_PYTHON
#ifdef HAVE_PYTHON
////////////////////////////////////////////////////////////////////
// Function: py_decode_TypedWritable_from_bam_stream
// Access: Published
// Description: This wrapper is defined as a global function to suit
// pickle's needs.
////////////////////////////////////////////////////////////////////
PyObject *
py_decode_TypedWritable_from_bam_stream(PyObject *this_class, const string &data) {
// We need the function TypedWritable::decode_from_bam_stream, which
// invokes the BamReader to reconstruct this object. Since we use
// the specific object's class as the pointer, we get the particular
// instance of decode_from_bam_stream appropriate to this class.
PyObject *func = PyObject_GetAttrString(this_class, "decodeFromBamStream");
if (func == NULL) {
return NULL;
}
PyObject *result = PyObject_CallFunction(func, (char *)"(s#)", data.data(), data.size());
if (result == NULL) {
return NULL;
}
if (result == Py_None) {
Py_DECREF(result);
PyErr_SetString(PyExc_ValueError, "Could not unpack bam stream");
return NULL;
}
return result;
}
#endif // HAVE_PYTHON

View File

@ -60,6 +60,21 @@ PUBLISHED:
INLINE void mark_bam_modified(); INLINE void mark_bam_modified();
INLINE UpdateSeq get_bam_modified() const; INLINE UpdateSeq get_bam_modified() const;
#ifdef HAVE_PYTHON
PyObject *__reduce__(PyObject *self) const;
#endif
INLINE string encode_to_bam_stream() const;
bool encode_to_bam_stream(string &data) const;
static bool decode_raw_from_bam_stream(TypedWritable *&ptr,
ReferenceCount *&ref_ptr,
const string &data);
public:
#ifdef HAVE_PYTHON
static PyObject *find_global_decode(PyObject *this_class, const char *func_name);
#endif
private: private:
// We may need to store a list of the BamWriter(s) that have a // We may need to store a list of the BamWriter(s) that have a
// reference to this object, so that we can remove the object from // reference to this object, so that we can remove the object from
@ -70,12 +85,10 @@ private:
UpdateSeq _bam_modified; UpdateSeq _bam_modified;
PUBLISHED: public:
static TypeHandle get_class_type() { static TypeHandle get_class_type() {
return _type_handle; return _type_handle;
} }
public:
static void init_type() { static void init_type() {
TypedObject::init_type(); TypedObject::init_type();
register_type(_type_handle, "TypedWritable", register_type(_type_handle, "TypedWritable",
@ -96,6 +109,12 @@ private:
friend class BamWriter; friend class BamWriter;
}; };
#ifdef HAVE_PYTHON
BEGIN_PUBLISH
PyObject *py_decode_TypedWritable_from_bam_stream(PyObject *this_class, const string &data);
END_PUBLISH
#endif
#include "typedWritable.I" #include "typedWritable.I"
#endif #endif

View File

@ -26,3 +26,30 @@ ReferenceCount *TypedWritableReferenceCount::
as_reference_count() { as_reference_count() {
return this; return this;
} }
////////////////////////////////////////////////////////////////////
// Function: TypedWritableReferenceCount::decode_from_bam_stream
// Access: Published, Static
// Description: Reads the string created by a previous call to
// encode_to_bam_stream(), and extracts and returns the
// single object on that string. Returns NULL on error.
//
// This method is intended to replace
// decode_raw_from_bam_stream() when you know the stream
// in question returns an object of type
// TypedWritableReferenceCount, allowing for easier
// reference count management. Note that the caller is
// still responsible for maintaining the reference count
// on the return value.
////////////////////////////////////////////////////////////////////
PT(TypedWritableReferenceCount) TypedWritableReferenceCount::
decode_from_bam_stream(const string &data) {
TypedWritable *object;
ReferenceCount *ref_ptr;
if (!TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, data)) {
return NULL;
}
return DCAST(TypedWritableReferenceCount, object);
}

View File

@ -40,18 +40,17 @@ public:
virtual ReferenceCount *as_reference_count(); virtual ReferenceCount *as_reference_count();
PUBLISHED:
static PT(TypedWritableReferenceCount) decode_from_bam_stream(const string &data);
public: public:
virtual TypeHandle get_type() const { virtual TypeHandle get_type() const {
return get_class_type(); return get_class_type();
} }
virtual TypeHandle force_init_type() {init_type(); return get_class_type();} virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
PUBLISHED:
static TypeHandle get_class_type() { static TypeHandle get_class_type() {
return _type_handle; return _type_handle;
} }
public:
static void init_type() { static void init_type() {
TypedWritable::init_type(); TypedWritable::init_type();
ReferenceCount::init_type(); ReferenceCount::init_type();