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