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