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)
{
_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;

View File

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

View File

@ -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 &copy) :
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];
}
////////////////////////////////////////////////////////////////////

View File

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

View File

@ -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);
}

View File

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