From 3f96b1adf9402944a565c2b3d9627731614d85e2 Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 30 Jun 2004 21:01:56 +0000 Subject: [PATCH] struct constructors --- direct/src/dcparser/dcClass.cxx | 98 ++++++++++++++++++++---- direct/src/dcparser/dcClass.h | 5 ++ direct/src/dcparser/dcClassParameter.cxx | 19 ++++- direct/src/dcparser/dcClassParameter.h | 3 + direct/src/dcparser/dcPacker.cxx | 55 ++++++++++--- direct/src/dcparser/dcPacker.h | 5 +- 6 files changed, 154 insertions(+), 31 deletions(-) diff --git a/direct/src/dcparser/dcClass.cxx b/direct/src/dcparser/dcClass.cxx index da89d6b42b..926026131f 100644 --- a/direct/src/dcparser/dcClass.cxx +++ b/direct/src/dcparser/dcClass.cxx @@ -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; diff --git a/direct/src/dcparser/dcClass.h b/direct/src/dcparser/dcClass.h index 16f070c8bf..f737513a0e 100644 --- a/direct/src/dcparser/dcClass.h +++ b/direct/src/dcparser/dcClass.h @@ -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 Parents; Parents _parents; + DCField *_constructor; + typedef pvector Fields; Fields _fields; diff --git a/direct/src/dcparser/dcClassParameter.cxx b/direct/src/dcparser/dcClassParameter.cxx index 3d48652431..7fe5331cbe 100644 --- a/direct/src/dcparser/dcClassParameter.cxx +++ b/direct/src/dcparser/dcClassParameter.cxx @@ -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]; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/dcparser/dcClassParameter.h b/direct/src/dcparser/dcClassParameter.h index 25ad590523..4fac13642e 100644 --- a/direct/src/dcparser/dcClassParameter.h +++ b/direct/src/dcparser/dcClassParameter.h @@ -50,6 +50,9 @@ public: virtual void generate_hash(HashGenerator &hashgen) const; private: + typedef pvector Fields; + Fields _nested_fields; + DCClass *_dclass; }; diff --git a/direct/src/dcparser/dcPacker.cxx b/direct/src/dcparser/dcPacker.cxx index 597b8d6ec1..28675861ac 100755 --- a/direct/src/dcparser/dcPacker.cxx +++ b/direct/src/dcparser/dcPacker.cxx @@ -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); } diff --git a/direct/src/dcparser/dcPacker.h b/direct/src/dcparser/dcPacker.h index e665f3fc71..7df73daafa 100755 --- a/direct/src/dcparser/dcPacker.h +++ b/direct/src/dcparser/dcPacker.h @@ -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: