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