struct constructors

This commit is contained in:
David Rose 2004-06-30 21:01:56 +00:00
parent fab56fbd65
commit 3f96b1adf9
6 changed files with 154 additions and 31 deletions

View File

@ -34,6 +34,7 @@ DCClass(const string &name, bool is_struct, bool bogus_class) :
_bogus_class(bogus_class) _bogus_class(bogus_class)
{ {
_number = -1; _number = -1;
_constructor = NULL;
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON
_class_def = NULL; _class_def = NULL;
@ -47,6 +48,10 @@ DCClass(const string &name, bool is_struct, bool bogus_class) :
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
DCClass:: DCClass::
~DCClass() { ~DCClass() {
if (_constructor != (DCField *)NULL) {
delete _constructor;
}
Fields::iterator fi; Fields::iterator fi;
for (fi = _fields.begin(); fi != _fields.end(); ++fi) { for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
delete (*fi); delete (*fi);
@ -113,6 +118,29 @@ get_parent() const {
return _parents.front(); 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 // Function: DCClass::get_num_fields
// Access: Published // Access: Published
@ -473,38 +501,49 @@ pack_required_field(DCPacker &packer, PyObject *distobj,
// good, robust way to get this; presently, we just mangle the // good, robust way to get this; presently, we just mangle the
// "setFoo()" name of the required field into "getFoo()" and call // "setFoo()" name of the required field into "getFoo()" and call
// that. // 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) { if (atom->get_num_elements() == 0) {
// It sure doesn't make sense to have a required field with no // It sure doesn't make sense to have a required field with no
// parameters. What data, exactly, is required? // parameters. What data, exactly, is required?
ostringstream strm; ostringstream strm;
strm << "Required field " << set_name << " has no parameters!"; strm << "Required field " << setter_name << " has no parameters!";
nassert_raise(strm.str()); nassert_raise(strm.str());
return false; return false;
} }
if (set_name.substr(0, 3) != string("set")) { string getter_name = setter_name;
// This is required to suit our set/get mangling convention. if (setter_name.substr(0, 3) == "set") {
ostringstream strm; // If the original method started with "set", we mangle this
strm << "Required field " << set_name << " does not begin with 'set'"; // directly to "get".
nassert_raise(strm.str()); getter_name[0] = 'g';
return false;
} 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 // Now we have to look up the getter on the distributed object
// and call it. // and call it.
if (!PyObject_HasAttrString(distobj, (char *)get_name.c_str())) { if (!PyObject_HasAttrString(distobj, (char *)getter_name.c_str())) {
ostringstream strm; ostringstream strm;
strm << "Required field " << set_name strm << "Distributed class " << get_name()
<< " doesn't have matching field named " << get_name; << " doesn't have getter named " << getter_name
<< " to match required field " << setter_name;
nassert_raise(strm.str()); nassert_raise(strm.str());
return false; return false;
} }
PyObject *func = PyObject *func =
PyObject_GetAttrString(distobj, (char *)get_name.c_str()); PyObject_GetAttrString(distobj, (char *)getter_name.c_str());
nassertr(func != (PyObject *)NULL, false); nassertr(func != (PyObject *)NULL, false);
PyObject *empty_args = PyTuple_New(0); PyObject *empty_args = PyTuple_New(0);
@ -514,7 +553,7 @@ pack_required_field(DCPacker &packer, PyObject *distobj,
if (result == (PyObject *)NULL) { if (result == (PyObject *)NULL) {
// We don't set this as an exception, since presumably the Python // We don't set this as an exception, since presumably the Python
// method itself has already triggered a Python exception. // method itself has already triggered a Python exception.
cerr << "Error when calling " << get_name << "\n"; cerr << "Error when calling " << getter_name << "\n";
return false; return false;
} }
@ -695,6 +734,10 @@ write(ostream &out, bool brief, int indent_level) const {
} }
out << "\n"; out << "\n";
if (_constructor != (DCField *)NULL) {
_constructor->write(out, brief, indent_level + 2);
}
Fields::const_iterator fi; Fields::const_iterator fi;
for (fi = _fields.begin(); fi != _fields.end(); ++fi) { for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
(*fi)->write(out, brief, indent_level + 2); (*fi)->write(out, brief, indent_level + 2);
@ -733,6 +776,11 @@ output_instance(ostream &out, bool brief, const string &prename,
out << " {"; out << " {";
if (_constructor != (DCField *)NULL) {
_constructor->output(out, brief);
out << "; ";
}
Fields::const_iterator fi; Fields::const_iterator fi;
for (fi = _fields.begin(); fi != _fields.end(); ++fi) { for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
(*fi)->output(out, brief); (*fi)->output(out, brief);
@ -761,6 +809,10 @@ generate_hash(HashGenerator &hashgen) const {
hashgen.add_int((*pi)->get_number()); hashgen.add_int((*pi)->get_number());
} }
if (_constructor != (DCField *)NULL) {
_constructor->generate_hash(hashgen);
}
hashgen.add_int(_fields.size()); hashgen.add_int(_fields.size());
Fields::const_iterator fi; Fields::const_iterator fi;
for (fi = _fields.begin(); fi != _fields.end(); ++fi) { for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
@ -779,6 +831,22 @@ generate_hash(HashGenerator &hashgen) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool DCClass:: bool DCClass::
add_field(DCField *field) { 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 bool inserted = _fields_by_name.insert
(FieldsByName::value_type(field->get_name(), field)).second; (FieldsByName::value_type(field->get_name(), field)).second;

View File

@ -46,6 +46,9 @@ PUBLISHED:
bool has_parent() const; bool has_parent() const;
DCClass *get_parent() const; DCClass *get_parent() const;
bool has_constructor() const;
DCField *get_constructor() const;
int get_num_fields() const; int get_num_fields() const;
DCField *get_field(int n) const; DCField *get_field(int n) const;
DCField *get_field_by_name(const string &name) const; DCField *get_field_by_name(const string &name) const;
@ -102,6 +105,8 @@ private:
typedef pvector<DCClass *> Parents; typedef pvector<DCClass *> Parents;
Parents _parents; Parents _parents;
DCField *_constructor;
typedef pvector<DCField *> Fields; typedef pvector<DCField *> Fields;
Fields _fields; Fields _fields;

View File

@ -31,10 +31,23 @@ DCClassParameter(DCClass *dclass) :
{ {
set_name(dclass->get_name()); set_name(dclass->get_name());
int num_fields = _dclass->get_num_inherited_fields();
_has_nested_fields = true; _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; _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 // 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 // the class (and its byte size is the sum of all of the nested
// fields). // fields).
@ -57,6 +70,7 @@ DCClassParameter(DCClass *dclass) :
DCClassParameter:: DCClassParameter::
DCClassParameter(const DCClassParameter &copy) : DCClassParameter(const DCClassParameter &copy) :
DCParameter(copy), DCParameter(copy),
_nested_fields(copy._nested_fields),
_dclass(copy._dclass) _dclass(copy._dclass)
{ {
} }
@ -113,7 +127,8 @@ get_class() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
DCPackerInterface *DCClassParameter:: DCPackerInterface *DCClassParameter::
get_nested_field(int n) const { 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];
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -50,6 +50,9 @@ public:
virtual void generate_hash(HashGenerator &hashgen) const; virtual void generate_hash(HashGenerator &hashgen) const;
private: private:
typedef pvector<DCPackerInterface *> Fields;
Fields _nested_fields;
DCClass *_dclass; DCClass *_dclass;
}; };

View File

@ -1126,17 +1126,36 @@ unpack_class_object(DCClass *dclass) {
PyObject *class_def = dclass->get_class_def(); PyObject *class_def = dclass->get_class_def();
nassertr(class_def != (PyObject *)NULL, NULL); nassertr(class_def != (PyObject *)NULL, NULL);
PyObject *object = PyObject_CallObject(class_def, NULL); PyObject *object = NULL;
if (object == (PyObject *)NULL) {
return 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(); 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()) { while (more_nested_fields()) {
const DCField *field = ((DCPackerInterface *)get_current_field())->as_field(); const DCField *field = ((DCPackerInterface *)get_current_field())->as_field();
nassertr(field != (DCField *)NULL, object); nassertr(field != (DCField *)NULL, object);
set_class_element(object, field); set_class_element(class_def, object, field);
} }
pop(); pop();
@ -1150,10 +1169,11 @@ unpack_class_object(DCClass *dclass) {
// Function: DCPacker::set_class_element // Function: DCPacker::set_class_element
// Access: Private // Access: Private
// Description: Unpacks the current element and stuffs it on the // 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:: 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(); string field_name = field->get_name();
DCPackType pack_type = get_pack_type(); DCPackType pack_type = get_pack_type();
@ -1168,7 +1188,8 @@ set_class_element(PyObject *object, const DCField *field) {
while (more_nested_fields()) { while (more_nested_fields()) {
const DCField *field = ((DCPackerInterface *)get_current_field())->as_field(); const DCField *field = ((DCPackerInterface *)get_current_field())->as_field();
nassertv(field != (DCField *)NULL); nassertv(field != (DCField *)NULL);
set_class_element(object, field); nassertv(object != (PyObject *)NULL);
set_class_element(class_def, object, field);
} }
pop(); pop();
break; break;
@ -1186,14 +1207,24 @@ set_class_element(PyObject *object, const DCField *field) {
PyObject *element = unpack_object(); PyObject *element = unpack_object();
if (pack_type == PT_field) { if (pack_type == PT_field) {
PyObject *func = PyObject_GetAttrString(object, (char *)field_name.c_str()); if (object == (PyObject *)NULL) {
if (func != (PyObject *)NULL) { // If the object hasn't been constructed yet, assume this is
PyObject *result = PyObject_CallObject(func, element); // the constructor.
Py_XDECREF(result); 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 { } else {
nassertv(object != (PyObject *)NULL);
PyObject_SetAttrString(object, (char *)field_name.c_str(), element); PyObject_SetAttrString(object, (char *)field_name.c_str(), element);
} }

View File

@ -27,7 +27,7 @@
#include "dcPython.h" #include "dcPython.h"
class DCClass; class DCClass;
class DCSwitchParametera; class DCSwitchParameter;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : DCPacker // Class : DCPacker
@ -180,7 +180,8 @@ private:
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON
void pack_class_object(DCClass *dclass, PyObject *object); void pack_class_object(DCClass *dclass, PyObject *object);
PyObject *unpack_class_object(DCClass *dclass); 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 #endif
private: private: