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()) {
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 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);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_number() const
Returns a unique index number associated with this field.
const std::string & get_name() const
Returns the name of this field, or empty string if the field is unnamed.
void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this class into the hash.
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
DCClass * get_class() const
Returns the DCClass pointer for the class that contains this field.
virtual void output(std::ostream &out) const
Write a string representation of this instance to <out>.
void clear_inherited_fields()
Empties the list of inherited fields for the class, so that it may be rebuilt.
void add_int(int num)
Adds another integer to the hash so far.
DCClass * get_parent(int n) const
Returns the nth parent class this class inherits from.
size_t get_num_unpacked_bytes() const
Returns the number of bytes that have been unpacked so far, or after unpack_end(),...
A single field of a Distributed Class, either atomic or molecular.
This is a convenience class to specialize ConfigVariable as a boolean type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const Datagram & get_datagram() const
Return the datagram of this iterator.
void add_string(const std::string &str)
Adds a string to the hash, by breaking it down into a sequence of integers.
unsigned int raw_unpack_uint16()
Unpacks the data from the buffer between unpacking sessions.
void raw_pack_uint8(unsigned int value)
Packs the data into the buffer between packing sessions.
void set_class(DCClass *dclass)
Assigns the class pointer to this field.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void check_inherited_fields()
Rebuilds all of the inherited fields tables, if necessary.
void set_number(int number)
Assigns the unique number to this field.
virtual DCAtomicField * as_atomic_field()
Returns the same field pointer converted to an atomic field pointer, if this is in fact an atomic fie...
bool is_broadcast() const
Returns true if the "broadcast" flag is set for this field, false otherwise.
Defines a particular DistributedClass as read from an input .dc file.
bool is_struct() const
Returns true if the class has been identified with the "struct" keyword in the dc file,...
void output(std::ostream &out) const
Write a string representation of this instance to <out>.
void set_new_index_number(DCField *field)
Sets the next sequential available index number on the indicated field.
virtual void write(std::ostream &out, bool brief, int indent_level) const
Generates a parseable description of the object to the indicated output stream.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool inherits_from_bogus_class() const
Returns true if this class, or any class in the inheritance heirarchy for this class,...
bool is_required() const
Returns true if the "required" flag is set for this field, false otherwise.
size_t get_length() const
Returns the current length of the buffer.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
size_t get_remaining_size() const
Return the bytes left in the datagram.
A single atomic field of a Distributed Class, as read from a .dc file.
virtual DCMolecularField * as_molecular_field()
Returns the same field pointer converted to a molecular field pointer, if this is in fact a molecular...
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this field into the hash.
Represents the complete list of Distributed Class descriptions as read from a .dc file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void raw_pack_uint32(unsigned int value)
Packs the data into the buffer between packing sessions.
DCField * get_field_by_index(int index_number) const
Returns a pointer to the DCField that has the indicated index number.
DCField * get_field_by_name(const std::string &name) const
Returns a pointer to the DCField that shares the indicated name.
void output_instance(std::ostream &out, bool brief, const std::string &prename, const std::string &name, const std::string &postname) const
Generates a parseable description of the object to the indicated output stream.
int get_num_elements() const
Returns the number of elements (parameters) of the atomic field.
DCField * get_inherited_field(int n) const
Returns the nth field field in the class and all of its ancestors.
A lightweight class that represents a single element that may be timed and/or counted via stats.
Represents the type specification for a single parameter within a field specification.
void set_unpack_data(const vector_uchar &data)
Sets up the unpack_data pointer.
void pack_default_value()
Adds the default value for the current element into the stream.
size_t get_current_index() const
Returns the current position within the datagram of the next piece of data to extract.
void raw_pack_uint16(unsigned int value)
Packs the data into the buffer between packing sessions.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
void skip_bytes(size_t size)
Skips over the indicated number of bytes in the datagram.
void add_parent(DCClass *parent)
Adds a new parent to the inheritance hierarchy of the class.
bool has_default_value() const
Returns true if a default value has been explicitly established for this field, false otherwise.
const char * get_data() const
Returns the beginning of the data buffer.
int get_num_parents() const
Returns the number of base classes this class inherits from.
void write(std::ostream &out, int indent_level) const
Write a string representation of this instance to <out>.
This class generates an arbitrary hash number from a sequence of ints.
bool is_ownrecv() const
Returns true if the "ownrecv" flag is set for this field, false otherwise.
DCField * get_constructor() const
Returns the constructor method for this class if it is defined, or NULL if the class uses the default...
void mark_inherited_fields_stale()
Indicates that something has changed in one or more of the inheritance chains or the set of fields; t...
int get_num_inherited_fields() const
Returns the total number of field fields defined in this class and all ancestor classes.
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
const std::string & get_name() const
Returns the name of this class.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
This class can be used for packing a series of numeric and string data into a binary stream,...
bool has_constructor() const
Returns true if this class has a constructor method, false if it just uses the default constructor.
This is our own Panda specialization on the default STL set.
A class to retrieve the individual data elements previously stored in a Datagram.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool add_field(DCField *field)
Adds the newly-allocated field to the class.
bool end_pack()
Finishes a packing session.
int get_num_fields() const
Returns the number of fields defined directly in this class, ignoring inheritance.
void rebuild_inherited_fields()
Recomputes the list of inherited fields for the class.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
bool is_bogus_class() const
Returns true if the class has been flagged as a bogus class.
DCField * get_field(int n) const
Returns the nth field in the class.
void begin_unpack(const DCPackerInterface *root)
Begins an unpacking session.
bool end_unpack()
Finishes the unpacking session.
size_t get_length() const
Returns the number of bytes in the datagram.
const void * get_data() const
Returns a pointer to the beginning of the datagram's data.
void set_number(int number)
Assigns the unique number to this class.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.