29 using std::ostringstream;
36 PStatCollector DCClass::_update_pcollector(
"App:Show code:readerPollTask:Update");
37 PStatCollector DCClass::_generate_pcollector(
"App:Show code:readerPollTask:Generate");
41 (
"dc-multiple-inheritance",
true,
42 PRC_DESC(
"Set this true to support multiple inheritance in the dc file. "
43 "If this is false, the old way, multiple inheritance is not "
44 "supported, but field numbers will be numbered sequentially, "
45 "which may be required to support old code that assumed this."));
48 (
"dc-virtual-inheritance",
true,
49 PRC_DESC(
"Set this true to support proper virtual inheritance in the "
50 "dc file, so that diamond-of-death type constructs can be used. "
51 "This also enables shadowing (overloading) of inherited method "
52 "names from a base class."));
55 (
"dc-sort-inheritance-by-file",
true,
56 PRC_DESC(
"This is a temporary hack. This should be true if you are using "
57 "version 1.42 of the otp_server.exe binary, which sorted inherited "
58 "fields based on the order of the classes within the DC file, "
59 "rather than based on the order in which the references are made "
60 "within the class."));
63 #endif // WITHIN_PANDA
65 class SortFieldsByIndex {
67 inline bool operator ()(
const DCField *a,
const DCField *b)
const {
76 DCClass(
DCFile *dc_file,
const string &name,
bool is_struct,
bool bogus_class) :
78 _class_update_pcollector(_update_pcollector, name),
79 _class_generate_pcollector(_generate_pcollector, name),
83 _is_struct(is_struct),
84 _bogus_class(bogus_class)
87 _constructor =
nullptr;
91 _owner_class_def =
nullptr;
100 if (_constructor !=
nullptr) {
105 for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
110 Py_XDECREF(_class_def);
111 Py_XDECREF(_owner_class_def);
136 return _parents.size();
144 nassertr(n >= 0 && n < (
int)_parents.size(),
nullptr);
154 return (_constructor !=
nullptr);
172 return _fields.size();
183 if (n < 0 || n >= (
int)_fields.size()) {
184 std::cerr << *
this <<
" "
185 <<
"n:" << n <<
" _fields.size():"
186 << (int)_fields.size() << std::endl;
190 nassertr_always(n >= 0 && n < (
int)_fields.size(),
nullptr);
202 FieldsByName::const_iterator ni;
203 ni = _fields_by_name.find(name);
204 if (ni != _fields_by_name.end()) {
209 Parents::const_iterator pi;
210 for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
211 DCField *result = (*pi)->get_field_by_name(name);
212 if (result !=
nullptr) {
229 FieldsByIndex::const_iterator ni;
230 ni = _fields_by_index.find(index_number);
231 if (ni != _fields_by_index.end()) {
236 Parents::const_iterator pi;
237 for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
238 DCField *result = (*pi)->get_field_by_index(index_number);
239 if (result !=
nullptr) {
241 ((
DCClass *)
this)->_fields_by_index[index_number] = result;
256 if (dc_multiple_inheritance && dc_virtual_inheritance &&
257 _dc_file !=
nullptr) {
259 if (_inherited_fields.empty()) {
260 ((
DCClass *)
this)->rebuild_inherited_fields();
265 return (
int)_inherited_fields.size();
270 Parents::const_iterator pi;
271 for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
272 num_fields += (*pi)->get_num_inherited_fields();
289 if (dc_multiple_inheritance && dc_virtual_inheritance &&
290 _dc_file !=
nullptr) {
292 if (_inherited_fields.empty()) {
293 ((
DCClass *)
this)->rebuild_inherited_fields();
295 nassertr(n >= 0 && n < (
int)_inherited_fields.size(),
nullptr);
296 return _inherited_fields[n];
299 Parents::const_iterator pi;
300 for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
301 int psize = (*pi)->get_num_inherited_fields();
303 return (*pi)->get_inherited_field(n);
324 Parents::const_iterator pi;
325 for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
326 if ((*pi)->inherits_from_bogus_class()) {
338 output(ostream &out)
const {
344 if (!_name.empty()) {
355 has_class_def()
const {
356 return (_class_def !=
nullptr);
358 #endif // HAVE_PYTHON
366 set_class_def(PyObject *class_def) {
367 Py_XINCREF(class_def);
368 Py_XDECREF(_class_def);
369 _class_def = class_def;
371 #endif // HAVE_PYTHON
379 get_class_def()
const {
380 if (_class_def ==
nullptr) {
385 Py_INCREF(_class_def);
388 #endif // HAVE_PYTHON
396 has_owner_class_def()
const {
397 return (_owner_class_def !=
nullptr);
399 #endif // HAVE_PYTHON
407 set_owner_class_def(PyObject *owner_class_def) {
408 Py_XINCREF(owner_class_def);
409 Py_XDECREF(_owner_class_def);
410 _owner_class_def = owner_class_def;
412 #endif // HAVE_PYTHON
420 get_owner_class_def()
const {
421 if (_owner_class_def ==
nullptr) {
426 Py_INCREF(_owner_class_def);
427 return _owner_class_def;
429 #endif // HAVE_PYTHON
448 if (field ==
nullptr) {
451 <<
"Received update for field " << field_id <<
", not in class "
453 nassert_raise(strm.str());
458 field->receive_update(packer, distobj);
464 #endif // HAVE_PYTHON
473 receive_update_broadcast_required(PyObject *distobj,
DatagramIterator &di)
const {
483 for (
int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
488 field->receive_update(packer, distobj);
497 #endif // HAVE_PYTHON
507 receive_update_broadcast_required_owner(PyObject *distobj,
518 for (
int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
523 field->receive_update(packer, distobj);
532 #endif // HAVE_PYTHON
541 receive_update_all_required(PyObject *distobj,
DatagramIterator &di)
const {
551 for (
int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
556 field->receive_update(packer, distobj);
565 #endif // HAVE_PYTHON
578 for (
int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
579 receive_update(distobj, di);
582 #endif // HAVE_PYTHON
589 direct_update(PyObject *distobj,
const string &field_name,
590 const vector_uchar &value_blob) {
592 nassertv_always(field !=
nullptr);
597 field->receive_update(packer, distobj);
600 #endif // HAVE_PYTHON
607 direct_update(PyObject *distobj,
const string &field_name,
610 nassertv_always(field !=
nullptr);
615 field->receive_update(packer, distobj);
618 #endif // HAVE_PYTHON
630 pack_required_field(
Datagram &datagram, PyObject *distobj,
634 if (!pack_required_field(packer, distobj, field)) {
644 #endif // HAVE_PYTHON
656 pack_required_field(
DCPacker &packer, PyObject *distobj,
658 const DCParameter *parameter = field->as_parameter();
659 if (parameter !=
nullptr) {
662 string field_name = field->
get_name();
664 if (!PyObject_HasAttrString(distobj, (
char *)field_name.c_str())) {
674 strm <<
"Data element " << field_name
675 <<
", required by dc file for dclass " <<
get_name()
676 <<
", not defined on object";
677 nassert_raise(strm.str());
681 PyObject_GetAttrString(distobj, (
char *)field_name.c_str());
682 nassertr(result !=
nullptr,
false);
685 bool pack_ok = parameter->pack_args(packer, result);
693 strm <<
"Cannot pack molecular field " << field->
get_name()
695 nassert_raise(strm.str());
700 nassertr(atom !=
nullptr,
false);
705 string setter_name = atom->
get_name();
707 if (setter_name.empty()) {
709 strm <<
"Required field is unnamed!";
710 nassert_raise(strm.str());
718 strm <<
"Required field " << setter_name <<
" has no parameters!";
719 nassert_raise(strm.str());
723 string getter_name = setter_name;
724 if (setter_name.substr(0, 3) ==
"set") {
727 getter_name[0] =
'g';
731 getter_name =
"get" + setter_name;
732 getter_name[3] = toupper(getter_name[3]);
736 if (!PyObject_HasAttrString(distobj, (
char *)getter_name.c_str())) {
746 strm <<
"Distributed class " <<
get_name()
747 <<
" doesn't have getter named " << getter_name
748 <<
" to match required field " << setter_name;
749 nassert_raise(strm.str());
753 PyObject_GetAttrString(distobj, (
char *)getter_name.c_str());
754 nassertr(func !=
nullptr,
false);
756 PyObject *empty_args = PyTuple_New(0);
757 PyObject *result = PyObject_CallObject(func, empty_args);
758 Py_DECREF(empty_args);
760 if (result ==
nullptr) {
763 std::cerr <<
"Error when calling " << getter_name <<
"\n";
770 PyObject *tuple = PyTuple_New(1);
771 PyTuple_SET_ITEM(tuple, 0, result);
776 if (!PySequence_Check(result)) {
778 strm <<
"Since dclass " <<
get_name() <<
" method " << setter_name
779 <<
" is declared to have multiple parameters, Python function "
780 << getter_name <<
" must return a list or tuple.\n";
781 nassert_raise(strm.str());
787 bool pack_ok = atom->pack_args(packer, result);
792 #endif // HAVE_PYTHON
800 client_format_update(
const string &field_name, DOID_TYPE do_id,
801 PyObject *args)
const {
803 if (field ==
nullptr) {
805 strm <<
"No field named " << field_name <<
" in class " <<
get_name()
807 nassert_raise(strm.str());
811 return field->client_format_update(do_id, args);
813 #endif // HAVE_PYTHON
821 ai_format_update(
const string &field_name, DOID_TYPE do_id,
822 CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, PyObject *args)
const {
824 if (field ==
nullptr) {
826 strm <<
"No field named " << field_name <<
" in class " <<
get_name()
828 nassert_raise(strm.str());
832 return field->ai_format_update(do_id, to_id, from_id, args);
834 #endif // HAVE_PYTHON
843 ai_format_update_msg_type(
const string &field_name, DOID_TYPE do_id,
844 CHANNEL_TYPE to_id, CHANNEL_TYPE from_id,
int msg_type, PyObject *args)
const {
846 if (field ==
nullptr) {
848 strm <<
"No field named " << field_name <<
" in class " <<
get_name()
850 nassert_raise(strm.str());
854 return field->ai_format_update_msg_type(do_id, to_id, from_id, msg_type, args);
856 #endif // HAVE_PYTHON
870 client_format_generate_CMU(PyObject *distobj, DOID_TYPE do_id,
872 PyObject *optional_fields)
const {
883 for (
int i = 0; i < num_fields; ++i) {
887 if (!pack_required_field(packer, distobj, field)) {
895 int num_optional_fields = 0;
896 if (PyObject_IsTrue(optional_fields)) {
897 num_optional_fields = PySequence_Size(optional_fields);
901 for (
int i = 0; i < num_optional_fields; i++) {
902 PyObject *py_field_name = PySequence_GetItem(optional_fields, i);
903 #if PY_MAJOR_VERSION >= 3
904 string field_name = PyUnicode_AsUTF8(py_field_name);
906 string field_name = PyString_AsString(py_field_name);
908 Py_XDECREF(py_field_name);
911 if (field ==
nullptr) {
913 strm <<
"No field named " << field_name <<
" in class " <<
get_name()
915 nassert_raise(strm.str());
920 if (!pack_required_field(packer, distobj, field)) {
928 #endif // HAVE_PYTHON
940 ai_format_generate(PyObject *distobj, DOID_TYPE do_id,
941 DOID_TYPE parent_id, ZONEID_TYPE zone_id,
942 CHANNEL_TYPE district_channel_id, CHANNEL_TYPE from_channel_id,
943 PyObject *optional_fields)
const {
947 packer.RAW_PACK_CHANNEL(district_channel_id);
948 packer.RAW_PACK_CHANNEL(from_channel_id);
951 bool has_optional_fields = (PyObject_IsTrue(optional_fields) != 0);
953 if (has_optional_fields) {
968 for (
int i = 0; i < num_fields; ++i) {
972 if (!pack_required_field(packer, distobj, field)) {
980 if (has_optional_fields) {
981 int num_optional_fields = PySequence_Size(optional_fields);
984 for (
int i = 0; i < num_optional_fields; ++i) {
985 PyObject *py_field_name = PySequence_GetItem(optional_fields, i);
986 #if PY_MAJOR_VERSION >= 3
987 string field_name = PyUnicode_AsUTF8(py_field_name);
989 string field_name = PyString_AsString(py_field_name);
991 Py_XDECREF(py_field_name);
994 if (field ==
nullptr) {
996 strm <<
"No field named " << field_name <<
" in class " <<
get_name()
998 nassert_raise(strm.str());
1005 if (!pack_required_field(packer, distobj, field)) {
1014 #endif // HAVE_PYTHON
1020 output(ostream &out,
bool brief)
const {
1029 write(ostream &out,
bool brief,
int indent_level)
const {
1030 indent(out, indent_level);
1036 if (!_name.empty()) {
1037 out <<
" " << _name;
1040 if (!_parents.empty()) {
1041 Parents::const_iterator pi = _parents.begin();
1042 out <<
" : " << (*pi)->_name;
1044 while (pi != _parents.end()) {
1045 out <<
", " << (*pi)->_name;
1051 if (!brief && _number >= 0) {
1052 out <<
" // index " << _number;
1056 if (_constructor !=
nullptr) {
1057 _constructor->
write(out, brief, indent_level + 2);
1060 Fields::const_iterator fi;
1061 for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
1062 if (!(*fi)->is_bogus_field()) {
1063 (*fi)->write(out, brief, indent_level + 2);
1081 indent(out, indent_level) <<
"};\n";
1090 const string &name,
const string &postname)
const {
1096 if (!_name.empty()) {
1097 out <<
" " << _name;
1100 if (!_parents.empty()) {
1101 Parents::const_iterator pi = _parents.begin();
1102 out <<
" : " << (*pi)->_name;
1104 while (pi != _parents.end()) {
1105 out <<
", " << (*pi)->_name;
1112 if (_constructor !=
nullptr) {
1113 _constructor->
output(out, brief);
1117 Fields::const_iterator fi;
1118 for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
1119 if (!(*fi)->is_bogus_field()) {
1120 (*fi)->output(out, brief);
1126 if (!prename.empty() || !name.empty() || !postname.empty()) {
1127 out <<
" " << prename << name << postname;
1142 hashgen.
add_int(_parents.size());
1143 Parents::const_iterator pi;
1144 for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
1145 hashgen.
add_int((*pi)->get_number());
1148 if (_constructor !=
nullptr) {
1152 hashgen.
add_int(_fields.size());
1153 Fields::const_iterator fi;
1154 for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
1155 (*fi)->generate_hash(hashgen);
1166 _inherited_fields.clear();
1177 _inherited_fields.clear();
1181 Parents::const_iterator pi;
1182 for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
1183 const DCClass *parent = (*pi);
1185 for (
int i = 0; i < num_inherited_fields; ++i) {
1189 if (!dc_sort_inheritance_by_file) {
1190 _inherited_fields.push_back(field);
1194 bool inserted = names.insert(field->
get_name()).second;
1197 _inherited_fields.push_back(field);
1207 Fields::const_iterator fi;
1208 for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
1212 _inherited_fields.push_back(field);
1215 bool inserted = names.insert(field->
get_name()).second;
1219 shadow_inherited_field(field->
get_name());
1223 _inherited_fields.push_back(field);
1227 if (dc_sort_inheritance_by_file) {
1229 sort(_inherited_fields.begin(), _inherited_fields.end(), SortFieldsByIndex());
1239 shadow_inherited_field(
const string &name) {
1240 Fields::iterator fi;
1241 for (fi = _inherited_fields.begin(); fi != _inherited_fields.end(); ++fi) {
1244 _inherited_fields.erase(fi);
1250 nassert_raise(
"named field not in list");
1263 if (_dc_file !=
nullptr) {
1270 if (_constructor !=
nullptr) {
1278 _constructor = field;
1279 _fields_by_name.insert
1280 (FieldsByName::value_type(field->
get_name(), field));
1284 bool inserted = _fields_by_name.insert
1285 (FieldsByName::value_type(field->
get_name(), field)).second;
1292 if (_dc_file !=
nullptr &&
1293 ((dc_virtual_inheritance && dc_sort_inheritance_by_file) || !
is_struct())) {
1294 if (dc_multiple_inheritance) {
1300 bool inserted = _fields_by_index.insert
1301 (FieldsByIndex::value_type(field->
get_number(), field)).second;
1304 nassertr(inserted,
false);
1307 _fields.push_back(field);
1317 _parents.push_back(parent);