mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
struct constructors
This commit is contained in:
parent
fab56fbd65
commit
3f96b1adf9
@ -34,6 +34,7 @@ DCClass(const string &name, bool is_struct, bool bogus_class) :
|
||||
_bogus_class(bogus_class)
|
||||
{
|
||||
_number = -1;
|
||||
_constructor = NULL;
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
_class_def = NULL;
|
||||
@ -47,6 +48,10 @@ DCClass(const string &name, bool is_struct, bool bogus_class) :
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCClass::
|
||||
~DCClass() {
|
||||
if (_constructor != (DCField *)NULL) {
|
||||
delete _constructor;
|
||||
}
|
||||
|
||||
Fields::iterator fi;
|
||||
for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
|
||||
delete (*fi);
|
||||
@ -112,6 +117,29 @@ get_parent() const {
|
||||
nassertr(has_parent(), NULL);
|
||||
return _parents.front();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCClass::has_constructor
|
||||
// Access: Published
|
||||
// Description: Returns true if this class has a constructor method,
|
||||
// false if it just uses the default constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool DCClass::
|
||||
has_constructor() const {
|
||||
return (_constructor != (DCField *)NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCClass::get_constructor
|
||||
// Access: Published
|
||||
// Description: Returns the constructor method for this class if it
|
||||
// is defined, or NULL if the class uses the default
|
||||
// constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCField *DCClass::
|
||||
get_constructor() const {
|
||||
return _constructor;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DCClass::get_num_fields
|
||||
@ -473,38 +501,49 @@ pack_required_field(DCPacker &packer, PyObject *distobj,
|
||||
// good, robust way to get this; presently, we just mangle the
|
||||
// "setFoo()" name of the required field into "getFoo()" and call
|
||||
// that.
|
||||
string set_name = atom->get_name();
|
||||
string setter_name = atom->get_name();
|
||||
|
||||
if (setter_name.empty()) {
|
||||
ostringstream strm;
|
||||
strm << "Required field is unnamed!";
|
||||
nassert_raise(strm.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (atom->get_num_elements() == 0) {
|
||||
// It sure doesn't make sense to have a required field with no
|
||||
// parameters. What data, exactly, is required?
|
||||
ostringstream strm;
|
||||
strm << "Required field " << set_name << " has no parameters!";
|
||||
strm << "Required field " << setter_name << " has no parameters!";
|
||||
nassert_raise(strm.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (set_name.substr(0, 3) != string("set")) {
|
||||
// This is required to suit our set/get mangling convention.
|
||||
ostringstream strm;
|
||||
strm << "Required field " << set_name << " does not begin with 'set'";
|
||||
nassert_raise(strm.str());
|
||||
return false;
|
||||
string getter_name = setter_name;
|
||||
if (setter_name.substr(0, 3) == "set") {
|
||||
// If the original method started with "set", we mangle this
|
||||
// directly to "get".
|
||||
getter_name[0] = 'g';
|
||||
|
||||
} else {
|
||||
// Otherwise, we add a "get" prefix, and capitalize the next
|
||||
// letter.
|
||||
getter_name = "get" + setter_name;
|
||||
getter_name[3] = toupper(getter_name[3]);
|
||||
}
|
||||
string get_name = set_name;
|
||||
get_name[0] = 'g';
|
||||
|
||||
// Now we have to look up the getter on the distributed object
|
||||
// and call it.
|
||||
if (!PyObject_HasAttrString(distobj, (char *)get_name.c_str())) {
|
||||
if (!PyObject_HasAttrString(distobj, (char *)getter_name.c_str())) {
|
||||
ostringstream strm;
|
||||
strm << "Required field " << set_name
|
||||
<< " doesn't have matching field named " << get_name;
|
||||
strm << "Distributed class " << get_name()
|
||||
<< " doesn't have getter named " << getter_name
|
||||
<< " to match required field " << setter_name;
|
||||
nassert_raise(strm.str());
|
||||
return false;
|
||||
}
|
||||
PyObject *func =
|
||||
PyObject_GetAttrString(distobj, (char *)get_name.c_str());
|
||||
PyObject_GetAttrString(distobj, (char *)getter_name.c_str());
|
||||
nassertr(func != (PyObject *)NULL, false);
|
||||
|
||||
PyObject *empty_args = PyTuple_New(0);
|
||||
@ -514,7 +553,7 @@ pack_required_field(DCPacker &packer, PyObject *distobj,
|
||||
if (result == (PyObject *)NULL) {
|
||||
// We don't set this as an exception, since presumably the Python
|
||||
// method itself has already triggered a Python exception.
|
||||
cerr << "Error when calling " << get_name << "\n";
|
||||
cerr << "Error when calling " << getter_name << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -695,6 +734,10 @@ write(ostream &out, bool brief, int indent_level) const {
|
||||
}
|
||||
out << "\n";
|
||||
|
||||
if (_constructor != (DCField *)NULL) {
|
||||
_constructor->write(out, brief, indent_level + 2);
|
||||
}
|
||||
|
||||
Fields::const_iterator fi;
|
||||
for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
|
||||
(*fi)->write(out, brief, indent_level + 2);
|
||||
@ -733,6 +776,11 @@ output_instance(ostream &out, bool brief, const string &prename,
|
||||
|
||||
out << " {";
|
||||
|
||||
if (_constructor != (DCField *)NULL) {
|
||||
_constructor->output(out, brief);
|
||||
out << "; ";
|
||||
}
|
||||
|
||||
Fields::const_iterator fi;
|
||||
for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
|
||||
(*fi)->output(out, brief);
|
||||
@ -761,6 +809,10 @@ generate_hash(HashGenerator &hashgen) const {
|
||||
hashgen.add_int((*pi)->get_number());
|
||||
}
|
||||
|
||||
if (_constructor != (DCField *)NULL) {
|
||||
_constructor->generate_hash(hashgen);
|
||||
}
|
||||
|
||||
hashgen.add_int(_fields.size());
|
||||
Fields::const_iterator fi;
|
||||
for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
|
||||
@ -779,6 +831,22 @@ generate_hash(HashGenerator &hashgen) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool DCClass::
|
||||
add_field(DCField *field) {
|
||||
if (!_name.empty() && field->get_name() == _name) {
|
||||
// This field is a constructor.
|
||||
if (_constructor != (DCField *)NULL) {
|
||||
// We already have a constructor.
|
||||
return false;
|
||||
}
|
||||
if (field->as_atomic_field() == (DCAtomicField *)NULL) {
|
||||
// The constructor must be an atomic field.
|
||||
return false;
|
||||
}
|
||||
_constructor = field;
|
||||
_fields_by_name.insert
|
||||
(FieldsByName::value_type(field->get_name(), field));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool inserted = _fields_by_name.insert
|
||||
(FieldsByName::value_type(field->get_name(), field)).second;
|
||||
|
||||
|
@ -45,6 +45,9 @@ PUBLISHED:
|
||||
|
||||
bool has_parent() const;
|
||||
DCClass *get_parent() const;
|
||||
|
||||
bool has_constructor() const;
|
||||
DCField *get_constructor() const;
|
||||
|
||||
int get_num_fields() const;
|
||||
DCField *get_field(int n) const;
|
||||
@ -102,6 +105,8 @@ private:
|
||||
typedef pvector<DCClass *> Parents;
|
||||
Parents _parents;
|
||||
|
||||
DCField *_constructor;
|
||||
|
||||
typedef pvector<DCField *> Fields;
|
||||
Fields _fields;
|
||||
|
||||
|
@ -31,10 +31,23 @@ DCClassParameter(DCClass *dclass) :
|
||||
{
|
||||
set_name(dclass->get_name());
|
||||
|
||||
int num_fields = _dclass->get_num_inherited_fields();
|
||||
|
||||
_has_nested_fields = true;
|
||||
_num_nested_fields = _dclass->get_num_inherited_fields();
|
||||
_num_nested_fields = num_fields;
|
||||
if (_dclass->has_constructor()) {
|
||||
_num_nested_fields++;
|
||||
}
|
||||
_pack_type = PT_class;
|
||||
|
||||
_nested_fields.reserve(_num_nested_fields);
|
||||
if (_dclass->has_constructor()) {
|
||||
_nested_fields.push_back(_dclass->get_constructor());
|
||||
}
|
||||
for (int i = 0 ; i < num_fields; i++) {
|
||||
_nested_fields.push_back(_dclass->get_inherited_field(i));
|
||||
}
|
||||
|
||||
// If all of the nested fields have a fixed byte size, then so does
|
||||
// the class (and its byte size is the sum of all of the nested
|
||||
// fields).
|
||||
@ -57,6 +70,7 @@ DCClassParameter(DCClass *dclass) :
|
||||
DCClassParameter::
|
||||
DCClassParameter(const DCClassParameter ©) :
|
||||
DCParameter(copy),
|
||||
_nested_fields(copy._nested_fields),
|
||||
_dclass(copy._dclass)
|
||||
{
|
||||
}
|
||||
@ -113,7 +127,8 @@ get_class() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DCPackerInterface *DCClassParameter::
|
||||
get_nested_field(int n) const {
|
||||
return _dclass->get_inherited_field(n);
|
||||
nassertr(n >= 0 && n < (int)_nested_fields.size(), NULL);
|
||||
return _nested_fields[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -50,6 +50,9 @@ public:
|
||||
virtual void generate_hash(HashGenerator &hashgen) const;
|
||||
|
||||
private:
|
||||
typedef pvector<DCPackerInterface *> Fields;
|
||||
Fields _nested_fields;
|
||||
|
||||
DCClass *_dclass;
|
||||
};
|
||||
|
||||
|
@ -1126,17 +1126,36 @@ unpack_class_object(DCClass *dclass) {
|
||||
PyObject *class_def = dclass->get_class_def();
|
||||
nassertr(class_def != (PyObject *)NULL, NULL);
|
||||
|
||||
PyObject *object = PyObject_CallObject(class_def, NULL);
|
||||
if (object == (PyObject *)NULL) {
|
||||
return NULL;
|
||||
PyObject *object = NULL;
|
||||
|
||||
if (!dclass->has_constructor()) {
|
||||
// If the class uses a default constructor, go ahead and create
|
||||
// the Python object for it now.
|
||||
object = PyObject_CallObject(class_def, NULL);
|
||||
if (object == (PyObject *)NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
push();
|
||||
if (object == (PyObject *)NULL && more_nested_fields()) {
|
||||
// The first nested field will be the constructor.
|
||||
const DCField *field = ((DCPackerInterface *)get_current_field())->as_field();
|
||||
nassertr(field != (DCField *)NULL, object);
|
||||
nassertr(field == dclass->get_constructor(), object);
|
||||
|
||||
set_class_element(class_def, object, field);
|
||||
|
||||
// By now, the object should have been constructed.
|
||||
if (object == (PyObject *)NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
while (more_nested_fields()) {
|
||||
const DCField *field = ((DCPackerInterface *)get_current_field())->as_field();
|
||||
nassertr(field != (DCField *)NULL, object);
|
||||
|
||||
set_class_element(object, field);
|
||||
set_class_element(class_def, object, field);
|
||||
}
|
||||
pop();
|
||||
|
||||
@ -1150,10 +1169,11 @@ unpack_class_object(DCClass *dclass) {
|
||||
// Function: DCPacker::set_class_element
|
||||
// Access: Private
|
||||
// Description: Unpacks the current element and stuffs it on the
|
||||
// Python class object in whatever way is appopriate.
|
||||
// Python class object in whatever way is appropriate.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DCPacker::
|
||||
set_class_element(PyObject *object, const DCField *field) {
|
||||
set_class_element(PyObject *class_def, PyObject *&object,
|
||||
const DCField *field) {
|
||||
string field_name = field->get_name();
|
||||
DCPackType pack_type = get_pack_type();
|
||||
|
||||
@ -1168,7 +1188,8 @@ set_class_element(PyObject *object, const DCField *field) {
|
||||
while (more_nested_fields()) {
|
||||
const DCField *field = ((DCPackerInterface *)get_current_field())->as_field();
|
||||
nassertv(field != (DCField *)NULL);
|
||||
set_class_element(object, field);
|
||||
nassertv(object != (PyObject *)NULL);
|
||||
set_class_element(class_def, object, field);
|
||||
}
|
||||
pop();
|
||||
break;
|
||||
@ -1186,14 +1207,24 @@ set_class_element(PyObject *object, const DCField *field) {
|
||||
PyObject *element = unpack_object();
|
||||
|
||||
if (pack_type == PT_field) {
|
||||
PyObject *func = PyObject_GetAttrString(object, (char *)field_name.c_str());
|
||||
if (func != (PyObject *)NULL) {
|
||||
PyObject *result = PyObject_CallObject(func, element);
|
||||
Py_XDECREF(result);
|
||||
if (object == (PyObject *)NULL) {
|
||||
// If the object hasn't been constructed yet, assume this is
|
||||
// the constructor.
|
||||
object = PyObject_CallObject(class_def, element);
|
||||
|
||||
} else {
|
||||
if (PyObject_HasAttrString(object, (char *)field_name.c_str())) {
|
||||
PyObject *func = PyObject_GetAttrString(object, (char *)field_name.c_str());
|
||||
if (func != (PyObject *)NULL) {
|
||||
PyObject *result = PyObject_CallObject(func, element);
|
||||
Py_XDECREF(result);
|
||||
Py_DECREF(func);
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_DECREF(func);
|
||||
|
||||
} else {
|
||||
nassertv(object != (PyObject *)NULL);
|
||||
PyObject_SetAttrString(object, (char *)field_name.c_str(), element);
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "dcPython.h"
|
||||
|
||||
class DCClass;
|
||||
class DCSwitchParametera;
|
||||
class DCSwitchParameter;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : DCPacker
|
||||
@ -180,7 +180,8 @@ private:
|
||||
#ifdef HAVE_PYTHON
|
||||
void pack_class_object(DCClass *dclass, PyObject *object);
|
||||
PyObject *unpack_class_object(DCClass *dclass);
|
||||
void set_class_element(PyObject *object, const DCField *field);
|
||||
void set_class_element(PyObject *class_def, PyObject *&object,
|
||||
const DCField *field);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
Loading…
x
Reference in New Issue
Block a user