Panda3D
dcClass.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file dcClass.cxx
10  * @author drose
11  * @date 2000-10-05
12  */
13 
14 #include "dcClass.h"
15 #include "dcFile.h"
16 #include "dcAtomicField.h"
17 #include "hashGenerator.h"
18 #include "dcindent.h"
19 #include "dcmsgtypes.h"
20 
21 #include "dcClassParameter.h"
22 #include <algorithm>
23 
24 #ifdef HAVE_PYTHON
25 #include "py_panda.h"
26 #endif
27 
28 using std::ostream;
29 using std::ostringstream;
30 using std::string;
31 
32 #ifdef WITHIN_PANDA
33 #include "pStatTimer.h"
34 
35 #ifndef CPPPARSER
36 PStatCollector DCClass::_update_pcollector("App:Show code:readerPollTask:Update");
37 PStatCollector DCClass::_generate_pcollector("App:Show code:readerPollTask:Generate");
38 #endif // CPPPARSER
39 
40 ConfigVariableBool dc_multiple_inheritance
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."));
46 
47 ConfigVariableBool dc_virtual_inheritance
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."));
53 
54 ConfigVariableBool dc_sort_inheritance_by_file
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."));
61 
62 
63 #endif // WITHIN_PANDA
64 
65 class SortFieldsByIndex {
66 public:
67  inline bool operator ()(const DCField *a, const DCField *b) const {
68  return a->get_number() < b->get_number();
69  }
70 };
71 
72 /**
73  *
74  */
75 DCClass::
76 DCClass(DCFile *dc_file, const string &name, bool is_struct, bool bogus_class) :
77 #ifdef WITHIN_PANDA
78  _class_update_pcollector(_update_pcollector, name),
79  _class_generate_pcollector(_generate_pcollector, name),
80 #endif
81  _dc_file(dc_file),
82  _name(name),
83  _is_struct(is_struct),
84  _bogus_class(bogus_class)
85 {
86  _number = -1;
87  _constructor = nullptr;
88 
89 #ifdef HAVE_PYTHON
90  _class_def = nullptr;
91  _owner_class_def = nullptr;
92 #endif
93 }
94 
95 /**
96  *
97  */
98 DCClass::
99 ~DCClass() {
100  if (_constructor != nullptr) {
101  delete _constructor;
102  }
103 
104  Fields::iterator fi;
105  for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
106  delete (*fi);
107  }
108 
109 #ifdef HAVE_PYTHON
110  Py_XDECREF(_class_def);
111  Py_XDECREF(_owner_class_def);
112 #endif
113 }
114 
115 /**
116  *
117  */
118 DCClass *DCClass::
119 as_class() {
120  return this;
121 }
122 
123 /**
124  *
125  */
126 const DCClass *DCClass::
127 as_class() const {
128  return this;
129 }
130 
131 /**
132  * Returns the number of base classes this class inherits from.
133  */
135 get_num_parents() const {
136  return _parents.size();
137 }
138 
139 /**
140  * Returns the nth parent class this class inherits from.
141  */
143 get_parent(int n) const {
144  nassertr(n >= 0 && n < (int)_parents.size(), nullptr);
145  return _parents[n];
146 }
147 
148 /**
149  * Returns true if this class has a constructor method, false if it just uses
150  * the default constructor.
151  */
153 has_constructor() const {
154  return (_constructor != nullptr);
155 }
156 
157 /**
158  * Returns the constructor method for this class if it is defined, or NULL if
159  * the class uses the default constructor.
160  */
162 get_constructor() const {
163  return _constructor;
164 }
165 
166 /**
167  * Returns the number of fields defined directly in this class, ignoring
168  * inheritance.
169  */
171 get_num_fields() const {
172  return _fields.size();
173 }
174 
175 /**
176  * Returns the nth field in the class. This is not necessarily the field with
177  * index n; this is the nth field defined in the class directly, ignoring
178  * inheritance.
179  */
181 get_field(int n) const {
182  #ifndef NDEBUG //[
183  if (n < 0 || n >= (int)_fields.size()) {
184  std::cerr << *this << " "
185  << "n:" << n << " _fields.size():"
186  << (int)_fields.size() << std::endl;
187  // __asm { int 3 }
188  }
189  #endif //]
190  nassertr_always(n >= 0 && n < (int)_fields.size(), nullptr);
191  return _fields[n];
192 }
193 
194 /**
195  * Returns a pointer to the DCField that shares the indicated name. If the
196  * named field is not found in the current class, the parent classes will be
197  * searched, so the value returned may not actually be a field within this
198  * class. Returns NULL if there is no such field defined.
199  */
201 get_field_by_name(const string &name) const {
202  FieldsByName::const_iterator ni;
203  ni = _fields_by_name.find(name);
204  if (ni != _fields_by_name.end()) {
205  return (*ni).second;
206  }
207 
208  // We didn't have such a field, so check our parents.
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) {
213  return result;
214  }
215  }
216 
217  // Nobody knew what this field is.
218  return nullptr;
219 }
220 
221 /**
222  * Returns a pointer to the DCField that has the indicated index number. If
223  * the numbered field is not found in the current class, the parent classes
224  * will be searched, so the value returned may not actually be a field within
225  * this class. Returns NULL if there is no such field defined.
226  */
228 get_field_by_index(int index_number) const {
229  FieldsByIndex::const_iterator ni;
230  ni = _fields_by_index.find(index_number);
231  if (ni != _fields_by_index.end()) {
232  return (*ni).second;
233  }
234 
235  // We didn't have such a field, so check our parents.
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) {
240  // Cache this result for future lookups.
241  ((DCClass *)this)->_fields_by_index[index_number] = result;
242  return result;
243  }
244  }
245 
246  // Nobody knew what this field is.
247  return nullptr;
248 }
249 
250 /**
251  * Returns the total number of field fields defined in this class and all
252  * ancestor classes.
253  */
255 get_num_inherited_fields() const {
256  if (dc_multiple_inheritance && dc_virtual_inheritance &&
257  _dc_file != nullptr) {
258  _dc_file->check_inherited_fields();
259  if (_inherited_fields.empty()) {
260  ((DCClass *)this)->rebuild_inherited_fields();
261  }
262 
263  // This assertion causes trouble when we are only parsing an incomplete DC
264  // file. nassertr(is_bogus_class() || !_inherited_fields.empty(), 0);
265  return (int)_inherited_fields.size();
266 
267  } else {
268  int num_fields = get_num_fields();
269 
270  Parents::const_iterator pi;
271  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
272  num_fields += (*pi)->get_num_inherited_fields();
273  }
274 
275  return num_fields;
276  }
277 }
278 
279 /**
280  * Returns the nth field field in the class and all of its ancestors.
281  *
282  * This *used* to be the same thing as get_field_by_index(), back when the
283  * fields were numbered sequentially within a class's inheritance hierarchy.
284  * Now that fields have a globally unique index number, this is no longer
285  * true.
286  */
288 get_inherited_field(int n) const {
289  if (dc_multiple_inheritance && dc_virtual_inheritance &&
290  _dc_file != nullptr) {
291  _dc_file->check_inherited_fields();
292  if (_inherited_fields.empty()) {
293  ((DCClass *)this)->rebuild_inherited_fields();
294  }
295  nassertr(n >= 0 && n < (int)_inherited_fields.size(), nullptr);
296  return _inherited_fields[n];
297 
298  } else {
299  Parents::const_iterator pi;
300  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
301  int psize = (*pi)->get_num_inherited_fields();
302  if (n < psize) {
303  return (*pi)->get_inherited_field(n);
304  }
305 
306  n -= psize;
307  }
308 
309  return get_field(n);
310  }
311 }
312 
313 /**
314  * Returns true if this class, or any class in the inheritance heirarchy for
315  * this class, is a "bogus" class--a forward reference to an as-yet-undefined
316  * class.
317  */
320  if (is_bogus_class()) {
321  return true;
322  }
323 
324  Parents::const_iterator pi;
325  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
326  if ((*pi)->inherits_from_bogus_class()) {
327  return true;
328  }
329  }
330 
331  return false;
332 }
333 
334 /**
335  * Write a string representation of this instance to <out>.
336  */
338 output(ostream &out) const {
339  if (_is_struct) {
340  out << "struct";
341  } else {
342  out << "dclass";
343  }
344  if (!_name.empty()) {
345  out << " " << _name;
346  }
347 }
348 
349 #ifdef HAVE_PYTHON
350 /**
351  * Returns true if the DCClass object has an associated Python class
352  * definition, false otherwise.
353  */
354 bool DCClass::
355 has_class_def() const {
356  return (_class_def != nullptr);
357 }
358 #endif // HAVE_PYTHON
359 
360 #ifdef HAVE_PYTHON
361 /**
362  * Sets the class object associated with this DistributedClass. This object
363  * will be used to construct new instances of the class.
364  */
365 void DCClass::
366 set_class_def(PyObject *class_def) {
367  Py_XINCREF(class_def);
368  Py_XDECREF(_class_def);
369  _class_def = class_def;
370 }
371 #endif // HAVE_PYTHON
372 
373 #ifdef HAVE_PYTHON
374 /**
375  * Returns the class object that was previously associated with this
376  * DistributedClass. This will return a new reference to the object.
377  */
378 PyObject *DCClass::
379 get_class_def() const {
380  if (_class_def == nullptr) {
381  Py_INCREF(Py_None);
382  return Py_None;
383  }
384 
385  Py_INCREF(_class_def);
386  return _class_def;
387 }
388 #endif // HAVE_PYTHON
389 
390 #ifdef HAVE_PYTHON
391 /**
392  * Returns true if the DCClass object has an associated Python owner class
393  * definition, false otherwise.
394  */
395 bool DCClass::
396 has_owner_class_def() const {
397  return (_owner_class_def != nullptr);
398 }
399 #endif // HAVE_PYTHON
400 
401 #ifdef HAVE_PYTHON
402 /**
403  * Sets the owner class object associated with this DistributedClass. This
404  * object will be used to construct new owner instances of the class.
405  */
406 void DCClass::
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;
411 }
412 #endif // HAVE_PYTHON
413 
414 #ifdef HAVE_PYTHON
415 /**
416  * Returns the owner class object that was previously associated with this
417  * DistributedClass. This will return a new reference to the object.
418  */
419 PyObject *DCClass::
420 get_owner_class_def() const {
421  if (_owner_class_def == nullptr) {
422  Py_INCREF(Py_None);
423  return Py_None;
424  }
425 
426  Py_INCREF(_owner_class_def);
427  return _owner_class_def;
428 }
429 #endif // HAVE_PYTHON
430 
431 #ifdef HAVE_PYTHON
432 /**
433  * Extracts the update message out of the packer and applies it to the
434  * indicated object by calling the appropriate method.
435  */
436 void DCClass::
437 receive_update(PyObject *distobj, DatagramIterator &di) const {
438 #ifdef WITHIN_PANDA
439  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
440 #endif
441  DCPacker packer;
442  const char *data = (const char *)di.get_datagram().get_data();
443  packer.set_unpack_data(data + di.get_current_index(),
444  di.get_remaining_size(), false);
445 
446  int field_id = packer.raw_unpack_uint16();
447  DCField *field = get_field_by_index(field_id);
448  if (field == nullptr) {
449  ostringstream strm;
450  strm
451  << "Received update for field " << field_id << ", not in class "
452  << get_name();
453  nassert_raise(strm.str());
454  return;
455  }
456 
457  packer.begin_unpack(field);
458  field->receive_update(packer, distobj);
459  packer.end_unpack();
460 
461  di.skip_bytes(packer.get_num_unpacked_bytes());
462 
463 }
464 #endif // HAVE_PYTHON
465 
466 #ifdef HAVE_PYTHON
467 /**
468  * Processes a big datagram that includes all of the "required" fields that
469  * are sent along with a normal "generate with required" message. This is all
470  * of the atomic fields that are marked "broadcast required".
471  */
472 void DCClass::
473 receive_update_broadcast_required(PyObject *distobj, DatagramIterator &di) const {
474 #ifdef WITHIN_PANDA
475  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
476 #endif
477  DCPacker packer;
478  const char *data = (const char *)di.get_datagram().get_data();
479  packer.set_unpack_data(data + di.get_current_index(),
480  di.get_remaining_size(), false);
481 
482  int num_fields = get_num_inherited_fields();
483  for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
484  DCField *field = get_inherited_field(i);
485  if (field->as_molecular_field() == nullptr &&
486  field->is_required() && field->is_broadcast()) {
487  packer.begin_unpack(field);
488  field->receive_update(packer, distobj);
489  if (!packer.end_unpack()) {
490  break;
491  }
492  }
493  }
494 
495  di.skip_bytes(packer.get_num_unpacked_bytes());
496 }
497 #endif // HAVE_PYTHON
498 
499 #ifdef HAVE_PYTHON
500 /**
501  * Processes a big datagram that includes all of the "required" fields that
502  * are sent along with a normal "generate with required" message. This is all
503  * of the atomic fields that are marked "broadcast ownrecv". Should be used
504  * for 'owner-view' objects.
505  */
506 void DCClass::
507 receive_update_broadcast_required_owner(PyObject *distobj,
508  DatagramIterator &di) const {
509 #ifdef WITHIN_PANDA
510  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
511 #endif
512  DCPacker packer;
513  const char *data = (const char *)di.get_datagram().get_data();
514  packer.set_unpack_data(data + di.get_current_index(),
515  di.get_remaining_size(), false);
516 
517  int num_fields = get_num_inherited_fields();
518  for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
519  DCField *field = get_inherited_field(i);
520  if (field->as_molecular_field() == nullptr &&
521  field->is_required() && (field->is_ownrecv() || field->is_broadcast())) {
522  packer.begin_unpack(field);
523  field->receive_update(packer, distobj);
524  if (!packer.end_unpack()) {
525  break;
526  }
527  }
528  }
529 
530  di.skip_bytes(packer.get_num_unpacked_bytes());
531 }
532 #endif // HAVE_PYTHON
533 
534 #ifdef HAVE_PYTHON
535 /**
536  * Processes a big datagram that includes all of the "required" fields that
537  * are sent when an avatar is created. This is all of the atomic fields that
538  * are marked "required", whether they are broadcast or not.
539  */
540 void DCClass::
541 receive_update_all_required(PyObject *distobj, DatagramIterator &di) const {
542 #ifdef WITHIN_PANDA
543  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
544 #endif
545  DCPacker packer;
546  const char *data = (const char *)di.get_datagram().get_data();
547  packer.set_unpack_data(data + di.get_current_index(),
548  di.get_remaining_size(), false);
549 
550  int num_fields = get_num_inherited_fields();
551  for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
552  DCField *field = get_inherited_field(i);
553  if (field->as_molecular_field() == nullptr &&
554  field->is_required()) {
555  packer.begin_unpack(field);
556  field->receive_update(packer, distobj);
557  if (!packer.end_unpack()) {
558  break;
559  }
560  }
561  }
562 
563  di.skip_bytes(packer.get_num_unpacked_bytes());
564 }
565 #endif // HAVE_PYTHON
566 
567 #ifdef HAVE_PYTHON
568 /**
569  * Processes a datagram that lists some additional fields that are broadcast
570  * in one chunk.
571  */
572 void DCClass::
573 receive_update_other(PyObject *distobj, DatagramIterator &di) const {
574 #ifdef WITHIN_PANDA
575  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
576 #endif
577  int num_fields = di.get_uint16();
578  for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
579  receive_update(distobj, di);
580  }
581 }
582 #endif // HAVE_PYTHON
583 
584 #ifdef HAVE_PYTHON
585 /**
586  * Processes an update for a named field from a packed value blob.
587  */
588 void DCClass::
589 direct_update(PyObject *distobj, const string &field_name,
590  const vector_uchar &value_blob) {
591  DCField *field = get_field_by_name(field_name);
592  nassertv_always(field != nullptr);
593 
594  DCPacker packer;
595  packer.set_unpack_data(value_blob);
596  packer.begin_unpack(field);
597  field->receive_update(packer, distobj);
598  packer.end_unpack();
599 }
600 #endif // HAVE_PYTHON
601 
602 #ifdef HAVE_PYTHON
603 /**
604  * Processes an update for a named field from a packed datagram.
605  */
606 void DCClass::
607 direct_update(PyObject *distobj, const string &field_name,
608  const Datagram &datagram) {
609  DCField *field = get_field_by_name(field_name);
610  nassertv_always(field != nullptr);
611 
612  DCPacker packer;
613  packer.set_unpack_data((const char *)datagram.get_data(), datagram.get_length(), false);
614  packer.begin_unpack(field);
615  field->receive_update(packer, distobj);
616  packer.end_unpack();
617 }
618 #endif // HAVE_PYTHON
619 
620 #ifdef HAVE_PYTHON
621 /**
622  * Looks up the current value of the indicated field by calling the
623  * appropriate get*() function, then packs that value into the datagram. This
624  * field is presumably either a required field or a specified optional field,
625  * and we are building up a datagram for the generate-with-required message.
626  *
627  * Returns true on success, false on failure.
628  */
629 bool DCClass::
630 pack_required_field(Datagram &datagram, PyObject *distobj,
631  const DCField *field) const {
632  DCPacker packer;
633  packer.begin_pack(field);
634  if (!pack_required_field(packer, distobj, field)) {
635  return false;
636  }
637  if (!packer.end_pack()) {
638  return false;
639  }
640 
641  datagram.append_data(packer.get_data(), packer.get_length());
642  return true;
643 }
644 #endif // HAVE_PYTHON
645 
646 #ifdef HAVE_PYTHON
647 /**
648  * Looks up the current value of the indicated field by calling the
649  * appropriate get*() function, then packs that value into the packer. This
650  * field is presumably either a required field or a specified optional field,
651  * and we are building up a datagram for the generate-with-required message.
652  *
653  * Returns true on success, false on failure.
654  */
655 bool DCClass::
656 pack_required_field(DCPacker &packer, PyObject *distobj,
657  const DCField *field) const {
658  const DCParameter *parameter = field->as_parameter();
659  if (parameter != nullptr) {
660  // This is the easy case: to pack a parameter, we just look on the class
661  // object for the data element.
662  string field_name = field->get_name();
663 
664  if (!PyObject_HasAttrString(distobj, (char *)field_name.c_str())) {
665  // If the attribute is not defined, but the field has a default value
666  // specified, quietly pack the default value.
667  if (field->has_default_value()) {
668  packer.pack_default_value();
669  return true;
670  }
671 
672  // If there is no default value specified, it's an error.
673  ostringstream strm;
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());
678  return false;
679  }
680  PyObject *result =
681  PyObject_GetAttrString(distobj, (char *)field_name.c_str());
682  nassertr(result != nullptr, false);
683 
684  // Now pack the value into the datagram.
685  bool pack_ok = parameter->pack_args(packer, result);
686  Py_DECREF(result);
687 
688  return pack_ok;
689  }
690 
691  if (field->as_molecular_field() != nullptr) {
692  ostringstream strm;
693  strm << "Cannot pack molecular field " << field->get_name()
694  << " for generate";
695  nassert_raise(strm.str());
696  return false;
697  }
698 
699  const DCAtomicField *atom = field->as_atomic_field();
700  nassertr(atom != nullptr, false);
701 
702  // We need to get the initial value of this field. There isn't a good,
703  // robust way to get this; presently, we just mangle the "setFoo()" name of
704  // the required field into "getFoo()" and call that.
705  string setter_name = atom->get_name();
706 
707  if (setter_name.empty()) {
708  ostringstream strm;
709  strm << "Required field is unnamed!";
710  nassert_raise(strm.str());
711  return false;
712  }
713 
714  if (atom->get_num_elements() == 0) {
715  // It sure doesn't make sense to have a required field with no parameters.
716  // What data, exactly, is required?
717  ostringstream strm;
718  strm << "Required field " << setter_name << " has no parameters!";
719  nassert_raise(strm.str());
720  return false;
721  }
722 
723  string getter_name = setter_name;
724  if (setter_name.substr(0, 3) == "set") {
725  // If the original method started with "set", we mangle this directly to
726  // "get".
727  getter_name[0] = 'g';
728 
729  } else {
730  // Otherwise, we add a "get" prefix, and capitalize the next letter.
731  getter_name = "get" + setter_name;
732  getter_name[3] = toupper(getter_name[3]);
733  }
734 
735  // Now we have to look up the getter on the distributed object and call it.
736  if (!PyObject_HasAttrString(distobj, (char *)getter_name.c_str())) {
737  // As above, if there's no getter but the field has a default value
738  // specified, quietly pack the default value.
739  if (field->has_default_value()) {
740  packer.pack_default_value();
741  return true;
742  }
743 
744  // Otherwise, with no default value it's an error.
745  ostringstream strm;
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());
750  return false;
751  }
752  PyObject *func =
753  PyObject_GetAttrString(distobj, (char *)getter_name.c_str());
754  nassertr(func != nullptr, false);
755 
756  PyObject *empty_args = PyTuple_New(0);
757  PyObject *result = PyObject_CallObject(func, empty_args);
758  Py_DECREF(empty_args);
759  Py_DECREF(func);
760  if (result == nullptr) {
761  // We don't set this as an exception, since presumably the Python method
762  // itself has already triggered a Python exception.
763  std::cerr << "Error when calling " << getter_name << "\n";
764  return false;
765  }
766 
767  if (atom->get_num_elements() == 1) {
768  // In this case, we expect the getter to return one object, which we wrap
769  // up in a tuple.
770  PyObject *tuple = PyTuple_New(1);
771  PyTuple_SET_ITEM(tuple, 0, result);
772  result = tuple;
773 
774  } else {
775  // Otherwise, it had better already be a sequence or tuple of some sort.
776  if (!PySequence_Check(result)) {
777  ostringstream strm;
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());
782  return false;
783  }
784  }
785 
786  // Now pack the arguments into the datagram.
787  bool pack_ok = atom->pack_args(packer, result);
788  Py_DECREF(result);
789 
790  return pack_ok;
791 }
792 #endif // HAVE_PYTHON
793 
794 #ifdef HAVE_PYTHON
795 /**
796  * Generates a datagram containing the message necessary to send an update for
797  * the indicated distributed object from the client.
798  */
799 Datagram DCClass::
800 client_format_update(const string &field_name, DOID_TYPE do_id,
801  PyObject *args) const {
802  DCField *field = get_field_by_name(field_name);
803  if (field == nullptr) {
804  ostringstream strm;
805  strm << "No field named " << field_name << " in class " << get_name()
806  << "\n";
807  nassert_raise(strm.str());
808  return Datagram();
809  }
810 
811  return field->client_format_update(do_id, args);
812 }
813 #endif // HAVE_PYTHON
814 
815 #ifdef HAVE_PYTHON
816 /**
817  * Generates a datagram containing the message necessary to send an update for
818  * the indicated distributed object from the AI.
819  */
820 Datagram DCClass::
821 ai_format_update(const string &field_name, DOID_TYPE do_id,
822  CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, PyObject *args) const {
823  DCField *field = get_field_by_name(field_name);
824  if (field == nullptr) {
825  ostringstream strm;
826  strm << "No field named " << field_name << " in class " << get_name()
827  << "\n";
828  nassert_raise(strm.str());
829  return Datagram();
830  }
831 
832  return field->ai_format_update(do_id, to_id, from_id, args);
833 }
834 #endif // HAVE_PYTHON
835 
836 #ifdef HAVE_PYTHON
837 /**
838  * Generates a datagram containing the message necessary to send an update,
839  * using the indicated msg type for the indicated distributed object from the
840  * AI.
841  */
842 Datagram DCClass::
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 {
845  DCField *field = get_field_by_name(field_name);
846  if (field == nullptr) {
847  ostringstream strm;
848  strm << "No field named " << field_name << " in class " << get_name()
849  << "\n";
850  nassert_raise(strm.str());
851  return Datagram();
852  }
853 
854  return field->ai_format_update_msg_type(do_id, to_id, from_id, msg_type, args);
855 }
856 #endif // HAVE_PYTHON
857 
858 #ifdef HAVE_PYTHON
859 /**
860  * Generates a datagram containing the message necessary to generate a new
861  * distributed object from the client. This requires querying the object for
862  * the initial value of its required fields.
863  *
864  * optional_fields is a list of fieldNames to generate in addition to the
865  * normal required fields.
866  *
867  * This method is only called by the CMU implementation.
868  */
869 Datagram DCClass::
870 client_format_generate_CMU(PyObject *distobj, DOID_TYPE do_id,
871  ZONEID_TYPE zone_id,
872  PyObject *optional_fields) const {
873  DCPacker packer;
874 
875  packer.raw_pack_uint16(CLIENT_OBJECT_GENERATE_CMU);
876 
877  packer.raw_pack_uint32(zone_id);
878  packer.raw_pack_uint16(_number);
879  packer.raw_pack_uint32(do_id);
880 
881  // Specify all of the required fields.
882  int num_fields = get_num_inherited_fields();
883  for (int i = 0; i < num_fields; ++i) {
884  DCField *field = get_inherited_field(i);
885  if (field->is_required() && field->as_molecular_field() == nullptr) {
886  packer.begin_pack(field);
887  if (!pack_required_field(packer, distobj, field)) {
888  return Datagram();
889  }
890  packer.end_pack();
891  }
892  }
893 
894  // Also specify the optional fields.
895  int num_optional_fields = 0;
896  if (PyObject_IsTrue(optional_fields)) {
897  num_optional_fields = PySequence_Size(optional_fields);
898  }
899  packer.raw_pack_uint16(num_optional_fields);
900 
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);
905 #else
906  string field_name = PyString_AsString(py_field_name);
907 #endif
908  Py_XDECREF(py_field_name);
909 
910  DCField *field = get_field_by_name(field_name);
911  if (field == nullptr) {
912  ostringstream strm;
913  strm << "No field named " << field_name << " in class " << get_name()
914  << "\n";
915  nassert_raise(strm.str());
916  return Datagram();
917  }
918  packer.raw_pack_uint16(field->get_number());
919  packer.begin_pack(field);
920  if (!pack_required_field(packer, distobj, field)) {
921  return Datagram();
922  }
923  packer.end_pack();
924  }
925 
926  return Datagram(packer.get_data(), packer.get_length());
927 }
928 #endif // HAVE_PYTHON
929 
930 #ifdef HAVE_PYTHON
931 /**
932  * Generates a datagram containing the message necessary to generate a new
933  * distributed object from the AI. This requires querying the object for the
934  * initial value of its required fields.
935  *
936  * optional_fields is a list of fieldNames to generate in addition to the
937  * normal required fields.
938  */
939 Datagram DCClass::
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 {
944  DCPacker packer;
945 
946  packer.raw_pack_uint8(1);
947  packer.RAW_PACK_CHANNEL(district_channel_id);
948  packer.RAW_PACK_CHANNEL(from_channel_id);
949  // packer.raw_pack_uint8('A');
950 
951  bool has_optional_fields = (PyObject_IsTrue(optional_fields) != 0);
952 
953  if (has_optional_fields) {
954  packer.raw_pack_uint16(STATESERVER_CREATE_OBJECT_WITH_REQUIRED_OTHER);
955  } else {
956  packer.raw_pack_uint16(STATESERVER_CREATE_OBJECT_WITH_REQUIRED);
957  }
958 
959  packer.raw_pack_uint32(do_id);
960  // Parent is a bit overloaded; this parent is not about inheritance, this
961  // one is about the visibility container parent, i.e. the zone parent:
962  packer.raw_pack_uint32(parent_id);
963  packer.raw_pack_uint32(zone_id);
964  packer.raw_pack_uint16(_number);
965 
966  // Specify all of the required fields.
967  int num_fields = get_num_inherited_fields();
968  for (int i = 0; i < num_fields; ++i) {
969  DCField *field = get_inherited_field(i);
970  if (field->is_required() && field->as_molecular_field() == nullptr) {
971  packer.begin_pack(field);
972  if (!pack_required_field(packer, distobj, field)) {
973  return Datagram();
974  }
975  packer.end_pack();
976  }
977  }
978 
979  // Also specify the optional fields.
980  if (has_optional_fields) {
981  int num_optional_fields = PySequence_Size(optional_fields);
982  packer.raw_pack_uint16(num_optional_fields);
983 
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);
988 #else
989  string field_name = PyString_AsString(py_field_name);
990 #endif
991  Py_XDECREF(py_field_name);
992 
993  DCField *field = get_field_by_name(field_name);
994  if (field == nullptr) {
995  ostringstream strm;
996  strm << "No field named " << field_name << " in class " << get_name()
997  << "\n";
998  nassert_raise(strm.str());
999  return Datagram();
1000  }
1001 
1002  packer.raw_pack_uint16(field->get_number());
1003 
1004  packer.begin_pack(field);
1005  if (!pack_required_field(packer, distobj, field)) {
1006  return Datagram();
1007  }
1008  packer.end_pack();
1009  }
1010  }
1011 
1012  return Datagram(packer.get_data(), packer.get_length());
1013 }
1014 #endif // HAVE_PYTHON
1015 
1016 /**
1017  * Write a string representation of this instance to <out>.
1018  */
1020 output(ostream &out, bool brief) const {
1021  output_instance(out, brief, "", "", "");
1022 }
1023 
1024 /**
1025  * Generates a parseable description of the object to the indicated output
1026  * stream.
1027  */
1029 write(ostream &out, bool brief, int indent_level) const {
1030  indent(out, indent_level);
1031  if (_is_struct) {
1032  out << "struct";
1033  } else {
1034  out << "dclass";
1035  }
1036  if (!_name.empty()) {
1037  out << " " << _name;
1038  }
1039 
1040  if (!_parents.empty()) {
1041  Parents::const_iterator pi = _parents.begin();
1042  out << " : " << (*pi)->_name;
1043  ++pi;
1044  while (pi != _parents.end()) {
1045  out << ", " << (*pi)->_name;
1046  ++pi;
1047  }
1048  }
1049 
1050  out << " {";
1051  if (!brief && _number >= 0) {
1052  out << " // index " << _number;
1053  }
1054  out << "\n";
1055 
1056  if (_constructor != nullptr) {
1057  _constructor->write(out, brief, indent_level + 2);
1058  }
1059 
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);
1064 
1065  /*
1066  if (true || (*fi)->has_default_value()) {
1067  indent(out, indent_level + 2) << "// = ";
1068  DCPacker packer;
1069  packer.set_unpack_data((*fi)->get_default_value());
1070  packer.begin_unpack(*fi);
1071  packer.unpack_and_format(out, false);
1072  if (!packer.end_unpack()) {
1073  out << "<error>";
1074  }
1075  out << "\n";
1076  }
1077  */
1078  }
1079  }
1080 
1081  indent(out, indent_level) << "};\n";
1082 }
1083 
1084 /**
1085  * Generates a parseable description of the object to the indicated output
1086  * stream.
1087  */
1089 output_instance(ostream &out, bool brief, const string &prename,
1090  const string &name, const string &postname) const {
1091  if (_is_struct) {
1092  out << "struct";
1093  } else {
1094  out << "dclass";
1095  }
1096  if (!_name.empty()) {
1097  out << " " << _name;
1098  }
1099 
1100  if (!_parents.empty()) {
1101  Parents::const_iterator pi = _parents.begin();
1102  out << " : " << (*pi)->_name;
1103  ++pi;
1104  while (pi != _parents.end()) {
1105  out << ", " << (*pi)->_name;
1106  ++pi;
1107  }
1108  }
1109 
1110  out << " {";
1111 
1112  if (_constructor != nullptr) {
1113  _constructor->output(out, brief);
1114  out << "; ";
1115  }
1116 
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);
1121  out << "; ";
1122  }
1123  }
1124 
1125  out << "}";
1126  if (!prename.empty() || !name.empty() || !postname.empty()) {
1127  out << " " << prename << name << postname;
1128  }
1129 }
1130 
1131 /**
1132  * Accumulates the properties of this class into the hash.
1133  */
1135 generate_hash(HashGenerator &hashgen) const {
1136  hashgen.add_string(_name);
1137 
1138  if (is_struct()) {
1139  hashgen.add_int(1);
1140  }
1141 
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());
1146  }
1147 
1148  if (_constructor != nullptr) {
1149  _constructor->generate_hash(hashgen);
1150  }
1151 
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);
1156  }
1157 }
1158 
1159 /**
1160  * Empties the list of inherited fields for the class, so that it may be
1161  * rebuilt. This is normally only called by
1162  * DCFile::rebuild_inherited_fields().
1163  */
1166  _inherited_fields.clear();
1167 }
1168 
1169 /**
1170  * Recomputes the list of inherited fields for the class.
1171  */
1174  typedef pset<string> Names;
1175  Names names;
1176 
1177  _inherited_fields.clear();
1178 
1179  // First, all of the inherited fields from our parent are at the top of the
1180  // list.
1181  Parents::const_iterator pi;
1182  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
1183  const DCClass *parent = (*pi);
1184  int num_inherited_fields = parent->get_num_inherited_fields();
1185  for (int i = 0; i < num_inherited_fields; ++i) {
1186  DCField *field = parent->get_inherited_field(i);
1187  if (field->get_name().empty()) {
1188  // Unnamed fields are always inherited. Except in the hack case.
1189  if (!dc_sort_inheritance_by_file) {
1190  _inherited_fields.push_back(field);
1191  }
1192 
1193  } else {
1194  bool inserted = names.insert(field->get_name()).second;
1195  if (inserted) {
1196  // The earlier parent shadows the later parent.
1197  _inherited_fields.push_back(field);
1198  }
1199  }
1200  }
1201  }
1202 
1203  // Now add the local fields at the end of the list. If any fields in this
1204  // list were already defined by a parent, we will shadow the parent
1205  // definition (that is, remove the parent's field from our list of inherited
1206  // fields).
1207  Fields::const_iterator fi;
1208  for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
1209  DCField *field = (*fi);
1210  if (field->get_name().empty()) {
1211  // Unnamed fields are always added.
1212  _inherited_fields.push_back(field);
1213 
1214  } else {
1215  bool inserted = names.insert(field->get_name()).second;
1216  if (!inserted) {
1217  // This local field shadows an inherited field. Remove the parent's
1218  // field from our list.
1219  shadow_inherited_field(field->get_name());
1220  }
1221 
1222  // Now add the local field.
1223  _inherited_fields.push_back(field);
1224  }
1225  }
1226 
1227  if (dc_sort_inheritance_by_file) {
1228  // Temporary hack.
1229  sort(_inherited_fields.begin(), _inherited_fields.end(), SortFieldsByIndex());
1230  }
1231 }
1232 
1233 /**
1234  * This is called only by rebuild_inherited_fields(). It removes the named
1235  * field from the list of _inherited_fields, presumably in preparation for
1236  * adding a new definition below.
1237  */
1238 void DCClass::
1239 shadow_inherited_field(const string &name) {
1240  Fields::iterator fi;
1241  for (fi = _inherited_fields.begin(); fi != _inherited_fields.end(); ++fi) {
1242  DCField *field = (*fi);
1243  if (field->get_name() == name) {
1244  _inherited_fields.erase(fi);
1245  return;
1246  }
1247  }
1248 
1249  // If we get here, the named field wasn't in the list. Huh.
1250  nassert_raise("named field not in list");
1251 }
1252 
1253 /**
1254  * Adds the newly-allocated field to the class. The class becomes the owner
1255  * of the pointer and will delete it when it destructs. Returns true if the
1256  * field is successfully added, or false if there was a name conflict or some
1257  * other problem.
1258  */
1260 add_field(DCField *field) {
1261  nassertr(field->get_class() == this || field->get_class() == nullptr, false);
1262  field->set_class(this);
1263  if (_dc_file != nullptr) {
1264  _dc_file->mark_inherited_fields_stale();
1265  }
1266 
1267  if (!field->get_name().empty()) {
1268  if (field->get_name() == _name) {
1269  // This field is a constructor.
1270  if (_constructor != nullptr) {
1271  // We already have a constructor.
1272  return false;
1273  }
1274  if (field->as_atomic_field() == nullptr) {
1275  // The constructor must be an atomic field.
1276  return false;
1277  }
1278  _constructor = field;
1279  _fields_by_name.insert
1280  (FieldsByName::value_type(field->get_name(), field));
1281  return true;
1282  }
1283 
1284  bool inserted = _fields_by_name.insert
1285  (FieldsByName::value_type(field->get_name(), field)).second;
1286 
1287  if (!inserted) {
1288  return false;
1289  }
1290  }
1291 
1292  if (_dc_file != nullptr &&
1293  ((dc_virtual_inheritance && dc_sort_inheritance_by_file) || !is_struct())) {
1294  if (dc_multiple_inheritance) {
1295  _dc_file->set_new_index_number(field);
1296  } else {
1298  }
1299 
1300  bool inserted = _fields_by_index.insert
1301  (FieldsByIndex::value_type(field->get_number(), field)).second;
1302 
1303  // It shouldn't be possible for that to fail.
1304  nassertr(inserted, false);
1305  }
1306 
1307  _fields.push_back(field);
1308  return true;
1309 }
1310 
1311 /**
1312  * Adds a new parent to the inheritance hierarchy of the class. This is
1313  * normally called only during parsing.
1314  */
1316 add_parent(DCClass *parent) {
1317  _parents.push_back(parent);
1318  _dc_file->mark_inherited_fields_stale();
1319 }
1320 
1321 /**
1322  * Assigns the unique number to this class. This is normally called only by
1323  * the DCFile interface as the class is added.
1324  */
1326 set_number(int number) {
1327  _number = number;
1328 }
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.
Definition: dcAtomicField.h:30
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.
Definition: dcClass.h:44
virtual void output(std::ostream &out) const
Write a string representation of this instance to <out>.
Definition: dcClass.cxx:338
virtual void write(std::ostream &out, bool brief, int indent_level) const
Generates a parseable description of the object to the indicated output stream.
Definition: dcClass.cxx:1029
int get_num_fields() const
Returns the number of fields defined directly in this class, ignoring inheritance.
Definition: dcClass.cxx:171
DCField * get_field(int n) const
Returns the nth field in the class.
Definition: dcClass.cxx:181
void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this class into the hash.
Definition: dcClass.cxx:1135
bool is_struct() const
Returns true if the class has been identified with the "struct" keyword in the dc file,...
Definition: dcClass.I:44
DCField * get_inherited_field(int n) const
Returns the nth field field in the class and all of its ancestors.
Definition: dcClass.cxx:288
DCClass * get_parent(int n) const
Returns the nth parent class this class inherits from.
Definition: dcClass.cxx:143
DCField * get_constructor() const
Returns the constructor method for this class if it is defined, or NULL if the class uses the default...
Definition: dcClass.cxx:162
void set_number(int number)
Assigns the unique number to this class.
Definition: dcClass.cxx:1326
void add_parent(DCClass *parent)
Adds a new parent to the inheritance hierarchy of the class.
Definition: dcClass.cxx:1316
bool add_field(DCField *field)
Adds the newly-allocated field to the class.
Definition: dcClass.cxx:1260
bool has_constructor() const
Returns true if this class has a constructor method, false if it just uses the default constructor.
Definition: dcClass.cxx:153
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.
Definition: dcClass.cxx:1089
bool is_bogus_class() const
Returns true if the class has been flagged as a bogus class.
Definition: dcClass.I:55
int get_num_inherited_fields() const
Returns the total number of field fields defined in this class and all ancestor classes.
Definition: dcClass.cxx:255
void rebuild_inherited_fields()
Recomputes the list of inherited fields for the class.
Definition: dcClass.cxx:1173
void clear_inherited_fields()
Empties the list of inherited fields for the class, so that it may be rebuilt.
Definition: dcClass.cxx:1165
const std::string & get_name() const
Returns the name of this class.
Definition: dcClass.I:26
int get_num_parents() const
Returns the number of base classes this class inherits from.
Definition: dcClass.cxx:135
DCField * get_field_by_index(int index_number) const
Returns a pointer to the DCField that has the indicated index number.
Definition: dcClass.cxx:228
bool inherits_from_bogus_class() const
Returns true if this class, or any class in the inheritance heirarchy for this class,...
Definition: dcClass.cxx:319
DCField * get_field_by_name(const std::string &name) const
Returns a pointer to the DCField that shares the indicated name.
Definition: dcClass.cxx:201
A single field of a Distributed Class, either atomic or molecular.
Definition: dcField.h:37
bool has_default_value() const
Returns true if a default value has been explicitly established for this field, false otherwise.
Definition: dcField.I:36
void set_number(int number)
Assigns the unique number to this field.
Definition: dcField.I:158
DCClass * get_class() const
Returns the DCClass pointer for the class that contains this field.
Definition: dcField.I:27
bool is_broadcast() const
Returns true if the "broadcast" flag is set for this field, false otherwise.
Definition: dcField.I:77
int get_number() const
Returns a unique index number associated with this field.
Definition: dcField.I:19
bool is_required() const
Returns true if the "required" flag is set for this field, false otherwise.
Definition: dcField.I:68
void write(std::ostream &out, int indent_level) const
Write a string representation of this instance to <out>.
Definition: dcField.I:149
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this field into the hash.
Definition: dcField.cxx:467
virtual DCAtomicField * as_atomic_field()
Returns the same field pointer converted to an atomic field pointer, if this is in fact an atomic fie...
Definition: dcField.cxx:112
void output(std::ostream &out) const
Write a string representation of this instance to <out>.
Definition: dcField.I:141
void set_class(DCClass *dclass)
Assigns the class pointer to this field.
Definition: dcField.I:167
virtual DCMolecularField * as_molecular_field()
Returns the same field pointer converted to a molecular field pointer, if this is in fact a molecular...
Definition: dcField.cxx:130
bool is_ownrecv() const
Returns true if the "ownrecv" flag is set for this field, false otherwise.
Definition: dcField.I:125
Represents the complete list of Distributed Class descriptions as read from a .dc file.
Definition: dcFile.h:32
void mark_inherited_fields_stale()
Indicates that something has changed in one or more of the inheritance chains or the set of fields; t...
Definition: dcFile.I:40
void set_new_index_number(DCField *field)
Sets the next sequential available index number on the indicated field.
Definition: dcFile.cxx:593
void check_inherited_fields()
Rebuilds all of the inherited fields tables, if necessary.
Definition: dcFile.I:28
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,...
Definition: dcPacker.h:34
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:73
void begin_unpack(const DCPackerInterface *root)
Begins an unpacking session.
Definition: dcPacker.cxx:153
bool end_unpack()
Finishes the unpacking session.
Definition: dcPacker.cxx:179
void raw_pack_uint32(unsigned int value)
Packs the data into the buffer between packing sessions.
Definition: dcPacker.I:758
void raw_pack_uint16(unsigned int value)
Packs the data into the buffer between packing sessions.
Definition: dcPacker.I:749
void raw_pack_uint8(unsigned int value)
Packs the data into the buffer between packing sessions.
Definition: dcPacker.I:740
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:98
const char * get_data() const
Returns the beginning of the data buffer.
Definition: dcPacker.I:641
void set_unpack_data(const std::vector< unsigned char > &data)
Sets up the unpack_data pointer.
Definition: dcPacker.cxx:117
void pack_default_value()
Adds the default value for the current element into the stream.
Definition: dcPacker.cxx:552
size_t get_num_unpacked_bytes() const
Returns the number of bytes that have been unpacked so far, or after unpack_end(),...
Definition: dcPacker.I:574
unsigned int raw_unpack_uint16()
Unpacks the data from the buffer between unpacking sessions.
Definition: dcPacker.I:897
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPacker.I:583
Represents the type specification for a single parameter within a field specification.
Definition: dcParameter.h:35
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 ...
Definition: datagram.h:38
size_t get_length() const
Returns the number of bytes in the datagram.
Definition: datagram.I:335
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
Definition: datagram.cxx:129
const void * get_data() const
Returns a pointer to the beginning of the datagram's data.
Definition: datagram.I:327
This class generates an arbitrary hash number from a sequence of ints.
Definition: hashGenerator.h:23
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...
Definition: pStatTimer.h:30
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
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.
Definition: indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.