mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 01:44:06 -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)
|
_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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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 ©) :
|
DCClassParameter(const DCClassParameter ©) :
|
||||||
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user