Panda3D
dcSwitch.cxx
1 // Filename: dcSwitch.cxx
2 // Created by: drose (23Jun04)
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 "dcSwitch.h"
16 #include "dcField.h"
17 #include "dcParameter.h"
18 #include "hashGenerator.h"
19 #include "dcindent.h"
20 #include "dcPacker.h"
21 
22 ////////////////////////////////////////////////////////////////////
23 // Function: DCSwitch::Constructor
24 // Access: Public
25 // Description: The key_parameter must be recently allocated via
26 // new; it will be deleted via delete when the switch
27 // destructs.
28 ////////////////////////////////////////////////////////////////////
30 DCSwitch(const string &name, DCField *key_parameter) :
31  _name(name),
32  _key_parameter(key_parameter)
33 {
34  _default_case = NULL;
35  _fields_added = false;
36 }
37 
38 ////////////////////////////////////////////////////////////////////
39 // Function: DCSwitch::Destructor
40 // Access: Public, Virtual
41 // Description:
42 ////////////////////////////////////////////////////////////////////
43 DCSwitch::
44 ~DCSwitch() {
45  nassertv(_key_parameter != (DCField *)NULL);
46  delete _key_parameter;
47 
48  Cases::iterator ci;
49  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
50  SwitchCase *dcase = (*ci);
51  delete dcase;
52  }
53 
54  CaseFields::iterator fi;
55  for (fi = _case_fields.begin(); fi != _case_fields.end(); ++fi) {
56  SwitchFields *fields = (*fi);
57  delete fields;
58  }
59 
60  Fields::iterator ni;
61  for (ni = _nested_fields.begin(); ni != _nested_fields.end(); ++ni) {
62  DCField *field = (*ni);
63  delete field;
64  }
65 }
66 
67 ////////////////////////////////////////////////////////////////////
68 // Function: DCSwitch::as_switch
69 // Access: Published, Virtual
70 // Description:
71 ////////////////////////////////////////////////////////////////////
72 DCSwitch *DCSwitch::
73 as_switch() {
74  return this;
75 }
76 
77 ////////////////////////////////////////////////////////////////////
78 // Function: DCSwitch::as_switch
79 // Access: Published, Virtual
80 // Description:
81 ////////////////////////////////////////////////////////////////////
82 const DCSwitch *DCSwitch::
83 as_switch() const {
84  return this;
85 }
86 
87 ////////////////////////////////////////////////////////////////////
88 // Function: DCSwitch::get_name
89 // Access: Published
90 // Description: Returns the name of this switch.
91 ////////////////////////////////////////////////////////////////////
92 const string &DCSwitch::
93 get_name() const {
94  return _name;
95 }
96 
97 ////////////////////////////////////////////////////////////////////
98 // Function: DCSwitch::get_key_parameter
99 // Access: Published
100 // Description: Returns the key parameter on which the switch is
101 // based. The value of this parameter in the record
102 // determines which one of the several cases within the
103 // switch will be used.
104 ////////////////////////////////////////////////////////////////////
107  return _key_parameter;
108 }
109 
110 ////////////////////////////////////////////////////////////////////
111 // Function: DCSwitch::get_num_cases
112 // Access: Published
113 // Description: Returns the number of different cases within the
114 // switch. The legal values for case_index range from 0
115 // to get_num_cases() - 1.
116 ////////////////////////////////////////////////////////////////////
117 int DCSwitch::
118 get_num_cases() const {
119  return _cases.size();
120 }
121 
122 ////////////////////////////////////////////////////////////////////
123 // Function: DCSwitch::get_case_by_value
124 // Access: Published
125 // Description: Returns the index number of the case with the
126 // indicated packed value, or -1 if no case has this
127 // value.
128 ////////////////////////////////////////////////////////////////////
129 int DCSwitch::
130 get_case_by_value(const string &case_value) const {
131  CasesByValue::const_iterator vi;
132  vi = _cases_by_value.find(case_value);
133  if (vi != _cases_by_value.end()) {
134  return (*vi).second;
135  }
136 
137  return -1;
138 }
139 
140 ////////////////////////////////////////////////////////////////////
141 // Function: DCSwitch::get_case
142 // Access: Published
143 // Description: Returns the DCPackerInterface that packs the nth case.
144 ////////////////////////////////////////////////////////////////////
146 get_case(int n) const {
147  nassertr(n >= 0 && n < (int)_cases.size(), NULL);
148  return _cases[n]->_fields;
149 }
150 
151 ////////////////////////////////////////////////////////////////////
152 // Function: DCSwitch::get_default_case
153 // Access: Published
154 // Description: Returns the DCPackerInterface that packs the default
155 // case, or NULL if there is no default case.
156 ////////////////////////////////////////////////////////////////////
159  return _default_case;
160 }
161 
162 ////////////////////////////////////////////////////////////////////
163 // Function: DCSwitch::get_value
164 // Access: Published
165 // Description: Returns the packed value associated with the
166 // indicated case.
167 ////////////////////////////////////////////////////////////////////
168 string DCSwitch::
169 get_value(int case_index) const {
170  nassertr(case_index >= 0 && case_index < (int)_cases.size(), string());
171  return _cases[case_index]->_value;
172 }
173 
174 ////////////////////////////////////////////////////////////////////
175 // Function: DCSwitch::get_num_fields
176 // Access: Published
177 // Description: Returns the number of fields in the indicated case.
178 ////////////////////////////////////////////////////////////////////
179 int DCSwitch::
180 get_num_fields(int case_index) const {
181  nassertr(case_index >= 0 && case_index < (int)_cases.size(), 0);
182  return _cases[case_index]->_fields->_fields.size();
183 }
184 
185 ////////////////////////////////////////////////////////////////////
186 // Function: DCSwitch::get_num_fields
187 // Access: Published
188 // Description: Returns the nth field in the indicated case.
189 ////////////////////////////////////////////////////////////////////
191 get_field(int case_index, int n) const {
192  nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);
193  nassertr(n >= 0 && n < (int)_cases[case_index]->_fields->_fields.size(), NULL);
194  return _cases[case_index]->_fields->_fields[n];
195 }
196 
197 ////////////////////////////////////////////////////////////////////
198 // Function: DCSwitch::get_field_by_name
199 // Access: Published
200 // Description: Returns the field with the given name from the
201 // indicated case, or NULL if no field has this name.
202 ////////////////////////////////////////////////////////////////////
204 get_field_by_name(int case_index, const string &name) const {
205  nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);
206 
207  const FieldsByName &fields_by_name = _cases[case_index]->_fields->_fields_by_name;
208  FieldsByName::const_iterator ni;
209  ni = fields_by_name.find(name);
210  if (ni != fields_by_name.end()) {
211  return (*ni).second;
212  }
213 
214  return NULL;
215 }
216 
217 ////////////////////////////////////////////////////////////////////
218 // Function: DCSwitch::is_field_valid
219 // Access: Public
220 // Description: Returns true if it is valid to add a new field at
221 // this point (implying that a case or default has been
222 // added already), or false if not.
223 ////////////////////////////////////////////////////////////////////
224 bool DCSwitch::
225 is_field_valid() const {
226  return !_current_fields.empty();
227 }
228 
229 ////////////////////////////////////////////////////////////////////
230 // Function: DCSwitch::add_case
231 // Access: Public
232 // Description: Adds a new case to the switch with the indicated
233 // value, and returns the new case_index. If the value
234 // has already been used for another case, returns -1.
235 // This is normally called only by the parser.
236 ////////////////////////////////////////////////////////////////////
237 int DCSwitch::
238 add_case(const string &value) {
239  int case_index = (int)_cases.size();
240  if (!_cases_by_value.insert(CasesByValue::value_type(value, case_index)).second) {
242  return -1;
243  }
244 
245  SwitchFields *fields = start_new_case();
246  SwitchCase *dcase = new SwitchCase(value, fields);
247  _cases.push_back(dcase);
248  return case_index;
249 }
250 
251 ////////////////////////////////////////////////////////////////////
252 // Function: DCSwitch::add_invalid_case
253 // Access: Public
254 // Description: Adds a new case to the switch that will never be
255 // matched. This is only used by the parser, to handle
256 // an error condition more gracefully without bitching
257 // the parsing (which behaves differently according to
258 // whether a case has been encountered or not).
259 ////////////////////////////////////////////////////////////////////
260 void DCSwitch::
262  start_new_case();
263 }
264 
265 ////////////////////////////////////////////////////////////////////
266 // Function: DCSwitch::add_default
267 // Access: Public
268 // Description: Adds a default case to the switch. Returns true if
269 // the case is successfully added, or false if it had
270 // already been added. This is normally called only by
271 // the parser.
272 ////////////////////////////////////////////////////////////////////
273 bool DCSwitch::
275  if (_default_case != (SwitchFields *)NULL) {
277  return false;
278  }
279 
280  SwitchFields *fields = start_new_case();
281  _default_case = fields;
282  return true;
283 }
284 
285 ////////////////////////////////////////////////////////////////////
286 // Function: DCSwitch::add_field
287 // Access: Public
288 // Description: Adds a field to the currently active cases (those
289 // that have been added via add_case() or add_default(),
290 // since the last call to add_break()). Returns true if
291 // successful, false if the field duplicates a field
292 // already named within this case. It is an error to
293 // call this before calling add_case() or add_default().
294 // This is normally called only by the parser.
295 ////////////////////////////////////////////////////////////////////
296 bool DCSwitch::
298  nassertr(!_current_fields.empty(), false);
299 
300  bool all_ok = true;
301 
302  CaseFields::iterator fi;
303  for (fi = _current_fields.begin(); fi != _current_fields.end(); ++fi) {
304  SwitchFields *fields = (*fi);
305  if (!fields->add_field(field)) {
306  all_ok = false;
307  }
308  }
309  _nested_fields.push_back(field);
310  _fields_added = true;
311 
312  return all_ok;
313 }
314 
315 ////////////////////////////////////////////////////////////////////
316 // Function: DCSwitch::add_break
317 // Access: Public
318 // Description: Adds a break statement to the switch. This closes
319 // the currently open cases and prepares for a new,
320 // unrelated case.
321 ////////////////////////////////////////////////////////////////////
322 void DCSwitch::
324  _current_fields.clear();
325  _fields_added = false;
326 }
327 
328 ////////////////////////////////////////////////////////////////////
329 // Function: DCSwitch::apply_switch
330 // Access: Public
331 // Description: Returns the DCPackerInterface that presents the
332 // alternative fields for the case indicated by the
333 // given packed value string, or NULL if the value
334 // string does not match one of the expected cases.
335 ////////////////////////////////////////////////////////////////////
337 apply_switch(const char *value_data, size_t length) const {
338  CasesByValue::const_iterator vi;
339  vi = _cases_by_value.find(string(value_data, length));
340  if (vi != _cases_by_value.end()) {
341  return _cases[(*vi).second]->_fields;
342  }
343 
344  // Unexpected value--use the default.
345  if (_default_case != (SwitchFields *)NULL) {
346  return _default_case;
347  }
348 
349  // No default.
350  return NULL;
351 }
352 
353 ////////////////////////////////////////////////////////////////////
354 // Function : DCSwitch::output
355 // Access : Public, Virtual
356 // Description : Write a string representation of this instance to
357 // <out>.
358 ////////////////////////////////////////////////////////////////////
359 void DCSwitch::
360 output(ostream &out, bool brief) const {
361  output_instance(out, brief, "", "", "");
362 }
363 
364 ////////////////////////////////////////////////////////////////////
365 // Function: DCSwitch::write
366 // Access: Public, Virtual
367 // Description: Generates a parseable description of the object to
368 // the indicated output stream.
369 ////////////////////////////////////////////////////////////////////
370 void DCSwitch::
371 write(ostream &out, bool brief, int indent_level) const {
372  write_instance(out, brief, indent_level, "", "", "");
373 }
374 
375 ////////////////////////////////////////////////////////////////////
376 // Function: DCSwitch::output_instance
377 // Access: Public
378 // Description: Generates a parseable description of the object to
379 // the indicated output stream.
380 ////////////////////////////////////////////////////////////////////
381 void DCSwitch::
382 output_instance(ostream &out, bool brief, const string &prename,
383  const string &name, const string &postname) const {
384  out << "switch";
385  if (!_name.empty()) {
386  out << " " << _name;
387  }
388  out << " (";
389  _key_parameter->output(out, brief);
390  out << ") {";
391 
392  const SwitchFields *last_fields = NULL;
393 
394  Cases::const_iterator ci;
395  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
396  const SwitchCase *dcase = (*ci);
397  if (dcase->_fields != last_fields && last_fields != (SwitchFields *)NULL) {
398  last_fields->output(out, brief);
399  }
400  last_fields = dcase->_fields;
401  out << "case " << _key_parameter->format_data(dcase->_value, false) << ": ";
402  }
403 
404  if (_default_case != (SwitchFields *)NULL) {
405  if (_default_case != last_fields && last_fields != (SwitchFields *)NULL) {
406  last_fields->output(out, brief);
407  }
408  last_fields = _default_case;
409  out << "default: ";
410  }
411  if (last_fields != (SwitchFields *)NULL) {
412  last_fields->output(out, brief);
413  }
414 
415  out << "}";
416  if (!prename.empty() || !name.empty() || !postname.empty()) {
417  out << " " << prename << name << postname;
418  }
419 }
420 
421 ////////////////////////////////////////////////////////////////////
422 // Function: DCSwitch::write_instance
423 // Access: Public, Virtual
424 // Description: Generates a parseable description of the object to
425 // the indicated output stream.
426 ////////////////////////////////////////////////////////////////////
427 void DCSwitch::
428 write_instance(ostream &out, bool brief, int indent_level,
429  const string &prename, const string &name,
430  const string &postname) const {
431  indent(out, indent_level)
432  << "switch";
433  if (!_name.empty()) {
434  out << " " << _name;
435  }
436  out << " (";
437  _key_parameter->output(out, brief);
438  out << ") {\n";
439 
440  const SwitchFields *last_fields = NULL;
441 
442  Cases::const_iterator ci;
443  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
444  const SwitchCase *dcase = (*ci);
445  if (dcase->_fields != last_fields && last_fields != (SwitchFields *)NULL) {
446  last_fields->write(out, brief, indent_level + 2);
447  }
448  last_fields = dcase->_fields;
449  indent(out, indent_level)
450  << "case " << _key_parameter->format_data(dcase->_value, false) << ":\n";
451  }
452 
453  if (_default_case != (SwitchFields *)NULL) {
454  if (_default_case != last_fields && last_fields != (SwitchFields *)NULL) {
455  last_fields->write(out, brief, indent_level + 2);
456  }
457  last_fields = _default_case;
458  indent(out, indent_level)
459  << "default:\n";
460  }
461  if (last_fields != (SwitchFields *)NULL) {
462  last_fields->write(out, brief, indent_level + 2);
463  }
464 
465  indent(out, indent_level)
466  << "}";
467  if (!prename.empty() || !name.empty() || !postname.empty()) {
468  out << " " << prename << name << postname;
469  }
470  out << ";\n";
471 }
472 
473 ////////////////////////////////////////////////////////////////////
474 // Function: DCSwitch::generate_hash
475 // Access: Public, Virtual
476 // Description: Accumulates the properties of this switch into the
477 // hash.
478 ////////////////////////////////////////////////////////////////////
479 void DCSwitch::
480 generate_hash(HashGenerator &hashgen) const {
481  hashgen.add_string(_name);
482 
483  _key_parameter->generate_hash(hashgen);
484 
485  hashgen.add_int(_cases.size());
486  Cases::const_iterator ci;
487  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
488  const SwitchCase *dcase = (*ci);
489  hashgen.add_string(dcase->_value);
490 
491  const SwitchFields *fields = dcase->_fields;
492  hashgen.add_int(fields->_fields.size());
493  Fields::const_iterator fi;
494  for (fi = fields->_fields.begin(); fi != fields->_fields.end(); ++fi) {
495  (*fi)->generate_hash(hashgen);
496  }
497  }
498 
499  if (_default_case != (SwitchFields *)NULL) {
500  const SwitchFields *fields = _default_case;
501  hashgen.add_int(fields->_fields.size());
502  Fields::const_iterator fi;
503  for (fi = fields->_fields.begin(); fi != fields->_fields.end(); ++fi) {
504  (*fi)->generate_hash(hashgen);
505  }
506  }
507 }
508 
509 ////////////////////////////////////////////////////////////////////
510 // Function: DCSwitch::pack_default_value
511 // Access: Public
512 // Description: Packs the switchParameter's specified default value
513 // (or a sensible default if no value is specified) into
514 // the stream. Returns true if the default value is
515 // packed, false if the switchParameter doesn't know how
516 // to pack its default value.
517 ////////////////////////////////////////////////////////////////////
518 bool DCSwitch::
519 pack_default_value(DCPackData &pack_data, bool &pack_error) const {
520  SwitchFields *fields = NULL;
521  DCPacker packer;
522  packer.begin_pack(_key_parameter);
523  if (!_cases.empty()) {
524  // If we have any cases, the first case is always the default
525  // case, regardless of the default value specified by the key
526  // parameter. That's just the easiest to code.
527  packer.pack_literal_value(_cases[0]->_value);
528  fields = _cases[0]->_fields;
529 
530  } else {
531  // If we don't have any cases, just pack the key parameter's
532  // default.
533  packer.pack_default_value();
534  fields = _default_case;
535  }
536 
537  if (!packer.end_pack()) {
538  pack_error = true;
539  }
540 
541  if (fields == (SwitchFields *)NULL) {
542  pack_error = true;
543 
544  } else {
545  // Then everything within the case gets its normal default.
546  for (size_t i = 1; i < fields->_fields.size(); i++) {
547  packer.begin_pack(fields->_fields[i]);
548  packer.pack_default_value();
549  if (!packer.end_pack()) {
550  pack_error = true;
551  }
552  }
553  }
554 
555  pack_data.append_data(packer.get_data(), packer.get_length());
556 
557  return true;
558 }
559 
560 ////////////////////////////////////////////////////////////////////
561 // Function: DCSwitch::do_check_match_switch
562 // Access: Public
563 // Description: Returns true if this switch matches the indicated
564 // other switch--that is, the two switches are bitwise
565 // equivalent--false otherwise. This is only intended
566 // to be called internally from
567 // DCSwitchParameter::do_check_match_switch_parameter().
568 ////////////////////////////////////////////////////////////////////
569 bool DCSwitch::
570 do_check_match_switch(const DCSwitch *other) const {
571  if (!_key_parameter->check_match(other->_key_parameter)) {
572  return false;
573  }
574 
575  if (_cases.size() != other->_cases.size()) {
576  return false;
577  }
578 
579  Cases::const_iterator ci;
580  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
581  const SwitchCase *c1 = (*ci);
582  CasesByValue::const_iterator vi;
583  vi = other->_cases_by_value.find(c1->_value);
584  if (vi == other->_cases_by_value.end()) {
585  // No matching value.
586  return false;
587  }
588  int c2_index = (*vi).second;
589  nassertr(c2_index >= 0 && c2_index < (int)other->_cases.size(), false);
590  const SwitchCase *c2 = other->_cases[c2_index];
591 
592  if (!c1->do_check_match_switch_case(c2)) {
593  return false;
594  }
595  }
596 
597  return true;
598 }
599 
600 ////////////////////////////////////////////////////////////////////
601 // Function: DCSwitch::start_new_case
602 // Access: Private
603 // Description: Creates a new field set for the new case, or shares
604 // the field set with the previous case, as appropriate.
605 // Returns the appropriate field set.
606 ////////////////////////////////////////////////////////////////////
607 DCSwitch::SwitchFields *DCSwitch::
608 start_new_case() {
609  SwitchFields *fields = NULL;
610 
611  if (_current_fields.empty() || _fields_added) {
612  // If we have recently encountered a break (which removes all of
613  // the current field sets) or if we have already added at least
614  // one field to the previous case without an intervening break,
615  // then we can't share the field set with the previous case.
616  // Create a new one.
617  fields = new SwitchFields(_name);
618  fields->add_field(_key_parameter);
619 
620  _case_fields.push_back(fields);
621  _current_fields.push_back(fields);
622 
623  } else {
624  // Otherwise, we can share the field set with the previous case.
625  fields = _current_fields.back();
626  }
627 
628  _fields_added = false;
629 
630  return fields;
631 }
632 
633 
634 ////////////////////////////////////////////////////////////////////
635 // Function: DCSwitch::SwitchFields::Constructor
636 // Access: Public
637 // Description:
638 ////////////////////////////////////////////////////////////////////
639 DCSwitch::SwitchFields::
640 SwitchFields(const string &name) :
641  DCPackerInterface(name)
642 {
643  _has_nested_fields = true;
644  _num_nested_fields = 0;
645  _pack_type = PT_switch;
646 
647  _has_fixed_byte_size = true;
648  _fixed_byte_size = 0;
649  _has_fixed_structure = true;
650  _has_range_limits = false;
651  _has_default_value = false;
652 }
653 
654 ////////////////////////////////////////////////////////////////////
655 // Function: DCSwitch::SwitchFields::Destructor
656 // Access: Public
657 // Description:
658 ////////////////////////////////////////////////////////////////////
659 DCSwitch::SwitchFields::
660 ~SwitchFields() {
661  // We don't delete any of the nested fields here, since they might
662  // be shared by multiple SwitchFields objects. Instead, we delete
663  // them in the DCSwitch destructor.
664 }
665 
666 ////////////////////////////////////////////////////////////////////
667 // Function: DCSwitch::SwitchFields::get_nested_field
668 // Access: Public, Virtual
669 // Description: Returns the DCPackerInterface object that represents
670 // the nth nested field. This may return NULL if there
671 // is no such field (but it shouldn't do this if n is in
672 // the range 0 <= n < get_num_nested_fields()).
673 ////////////////////////////////////////////////////////////////////
675 get_nested_field(int n) const {
676  nassertr(n >= 0 && n < (int)_fields.size(), NULL);
677  return _fields[n];
678 }
679 
680 ////////////////////////////////////////////////////////////////////
681 // Function: DCSwitch::SwitchFields::add_field
682 // Access: Public
683 // Description: Adds a field to this case. Returns true if
684 // successful, false if the field duplicates a field
685 // already named within this case. This is normally
686 // called only by the parser.
687 ////////////////////////////////////////////////////////////////////
690  if (!field->get_name().empty()) {
691  bool inserted = _fields_by_name.insert
692  (FieldsByName::value_type(field->get_name(), field)).second;
693 
694  if (!inserted) {
695  return false;
696  }
697  }
698 
699  _fields.push_back(field);
700 
701  _num_nested_fields = (int)_fields.size();
702 
703  // See if we still have a fixed byte size.
704  if (_has_fixed_byte_size) {
705  _has_fixed_byte_size = field->has_fixed_byte_size();
706  _fixed_byte_size += field->get_fixed_byte_size();
707  }
708  if (_has_fixed_structure) {
709  _has_fixed_structure = field->has_fixed_structure();
710  }
711  if (!_has_range_limits) {
712  _has_range_limits = field->has_range_limits();
713  }
714  if (!_has_default_value) {
715  _has_default_value = field->has_default_value();
716  }
717  return true;
718 }
719 
720 ////////////////////////////////////////////////////////////////////
721 // Function: DCSwitch::SwitchFields::do_check_match_switch_case
722 // Access: Public
723 // Description: Returns true if this case matches the indicated
724 // case, false otherwise. This is only intended to be
725 // called internally from
726 // DCSwitch::do_check_match_switch().
727 ////////////////////////////////////////////////////////////////////
730  if (_fields.size() != other->_fields.size()) {
731  return false;
732  }
733  for (size_t i = 0; i < _fields.size(); i++) {
734  if (!_fields[i]->check_match(other->_fields[i])) {
735  return false;
736  }
737  }
738 
739  return true;
740 }
741 
742 ////////////////////////////////////////////////////////////////////
743 // Function: DCSwitch::SwitchFields::output
744 // Access: Public
745 // Description:
746 ////////////////////////////////////////////////////////////////////
747 void DCSwitch::SwitchFields::
748 output(ostream &out, bool brief) const {
749  Fields::const_iterator fi;
750  if (!_fields.empty()) {
751  fi = _fields.begin();
752  ++fi;
753  while (fi != _fields.end()) {
754  (*fi)->output(out, brief);
755  out << "; ";
756  ++fi;
757  }
758  }
759  out << "break; ";
760 }
761 
762 ////////////////////////////////////////////////////////////////////
763 // Function: DCSwitch::SwitchFields::write
764 // Access: Public
765 // Description:
766 ////////////////////////////////////////////////////////////////////
767 void DCSwitch::SwitchFields::
768 write(ostream &out, bool brief, int indent_level) const {
769  Fields::const_iterator fi;
770  if (!_fields.empty()) {
771  fi = _fields.begin();
772  ++fi;
773  while (fi != _fields.end()) {
774  (*fi)->write(out, brief, indent_level);
775  ++fi;
776  }
777  }
778  indent(out, indent_level)
779  << "break;\n";
780 }
781 
782 ////////////////////////////////////////////////////////////////////
783 // Function: DCSwitch::SwitchFields::do_check_match
784 // Access: Protected, Virtual
785 // Description: Returns true if the other interface is bitwise the
786 // same as this one--that is, a uint32 only matches a
787 // uint32, etc. Names of components, and range limits,
788 // are not compared.
789 ////////////////////////////////////////////////////////////////////
790 bool DCSwitch::SwitchFields::
791 do_check_match(const DCPackerInterface *) const {
792  // This should never be called on a SwitchFields.
793  nassertr(false, false);
794  return false;
795 }
796 
797 ////////////////////////////////////////////////////////////////////
798 // Function: DCSwitch::SwitchCase::Constructor
799 // Access: Public
800 // Description:
801 ////////////////////////////////////////////////////////////////////
802 DCSwitch::SwitchCase::
803 SwitchCase(const string &value, DCSwitch::SwitchFields *fields) :
804  _value(value),
805  _fields(fields)
806 {
807 }
808 
809 ////////////////////////////////////////////////////////////////////
810 // Function: DCSwitch::SwitchCase::Destructor
811 // Access: Public
812 // Description:
813 ////////////////////////////////////////////////////////////////////
814 DCSwitch::SwitchCase::
815 ~SwitchCase() {
816 }
817 
818 ////////////////////////////////////////////////////////////////////
819 // Function: DCSwitch::SwitchCase::do_check_match_switch_case
820 // Access: Public
821 // Description: Returns true if this case matches the indicated
822 // case, false otherwise. This is only intended to be
823 // called internally from
824 // DCSwitch::do_check_match_switch().
825 ////////////////////////////////////////////////////////////////////
828  return _fields->do_check_match_switch_case(other->_fields);
829 }
void add_string(const string &str)
Adds a string to the hash, by breaking it down into a sequence of integers.
virtual bool pack_default_value(DCPackData &pack_data, bool &pack_error) const
Packs the switchParameter&#39;s specified default value (or a sensible default if no value is specified) ...
Definition: dcSwitch.cxx:519
This is a block of data that receives the results of DCPacker.
Definition: dcPackData.h:25
string get_value(int case_index) const
Returns the packed value associated with the indicated case.
Definition: dcSwitch.cxx:169
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
Definition: dcPackData.I:57
string format_data(const string &packed_data, bool show_field_names=true)
Given a blob that represents the packed data for this field, returns a string formatting it for human...
Definition: dcField.cxx:192
DCField * get_key_parameter() const
Returns the key parameter on which the switch is based.
Definition: dcSwitch.cxx:106
int add_case(const string &value)
Adds a new case to the switch with the indicated value, and returns the new case_index.
Definition: dcSwitch.cxx:238
void write_instance(ostream &out, bool brief, int indent_level, const string &prename, const string &name, const string &postname) const
Generates a parseable description of the object to the indicated output stream.
Definition: dcSwitch.cxx:428
bool has_fixed_structure() const
Returns true if this field type always has the same structure regardless of the data in the stream...
void add_int(int num)
Adds another integer to the hash so far.
int get_case_by_value(const string &case_value) const
Returns the index number of the case with the indicated packed value, or -1 if no case has this value...
Definition: dcSwitch.cxx:130
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: dcSwitch.cxx:382
A single field of a Distributed Class, either atomic or molecular.
Definition: dcField.h:40
const string & get_name() const
Returns the name of this field, or empty string if the field is unnamed.
void add_invalid_case()
Adds a new case to the switch that will never be matched.
Definition: dcSwitch.cxx:261
bool has_fixed_byte_size() const
Returns true if this field type always packs to the same number of bytes, false if it is variable...
This represents a switch statement, which can appear inside a class body and represents two or more a...
Definition: dcSwitch.h:33
int get_num_cases() const
Returns the number of different cases within the switch.
Definition: dcSwitch.cxx:118
virtual void output(ostream &out, bool brief) const
Write a string representation of this instance to <out>.
Definition: dcSwitch.cxx:360
bool do_check_match_switch_case(const SwitchCase *other) const
Returns true if this case matches the indicated case, false otherwise.
Definition: dcSwitch.cxx:827
bool do_check_match_switch_case(const SwitchFields *other) const
Returns true if this case matches the indicated case, false otherwise.
Definition: dcSwitch.cxx:729
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPacker.I:652
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this field into the hash.
Definition: dcField.cxx:528
void add_break()
Adds a break statement to the switch.
Definition: dcSwitch.cxx:323
DCField * get_field(int case_index, int n) const
Returns the nth field in the indicated case.
Definition: dcSwitch.cxx:191
size_t get_fixed_byte_size() const
If has_fixed_byte_size() returns true, this returns the number of bytes this field type will use...
bool has_range_limits() const
Returns true if this field, or any sub-field of this field, has a limit imposed in the DC file on its...
bool add_default()
Adds a default case to the switch.
Definition: dcSwitch.cxx:274
void pack_default_value()
Adds the default value for the current element into the stream.
Definition: dcPacker.cxx:597
bool check_match(const DCPackerInterface *other) const
Returns true if the other interface is bitwise the same as this one–that is, a uint32 only matches a...
bool add_field(DCField *field)
Adds a field to this case.
Definition: dcSwitch.cxx:689
const DCPackerInterface * apply_switch(const char *value_data, size_t length) const
Returns the DCPackerInterface that presents the alternative fields for the case indicated by the give...
Definition: dcSwitch.cxx:337
const string & get_name() const
Returns the name of this switch.
Definition: dcSwitch.cxx:93
void output(ostream &out) const
Write a string representation of this instance to <out>.
Definition: dcField.I:187
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this switch into the hash.
Definition: dcSwitch.cxx:480
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
bool do_check_match_switch(const DCSwitch *other) const
Returns true if this switch matches the indicated other switch–that is, the two switches are bitwise...
Definition: dcSwitch.cxx:570
This class generates an arbitrary hash number from a sequence of ints.
Definition: hashGenerator.h:26
void pack_literal_value(const string &value)
Adds the indicated string value into the stream, representing a single pre-packed field element...
Definition: dcPacker.I:279
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:76
bool is_field_valid() const
Returns true if it is valid to add a new field at this point (implying that a case or default has bee...
Definition: dcSwitch.cxx:225
int get_num_fields(int case_index) const
Returns the number of fields in the indicated case.
Definition: dcSwitch.cxx:180
DCSwitch(const string &name, DCField *key_parameter)
The key_parameter must be recently allocated via new; it will be deleted via delete when the switch d...
Definition: dcSwitch.cxx:30
This class can be used for packing a series of numeric and string data into a binary stream...
Definition: dcPacker.h:38
virtual void write(ostream &out, bool brief, int indent_level) const
Generates a parseable description of the object to the indicated output stream.
Definition: dcSwitch.cxx:371
bool add_field(DCField *field)
Adds a field to the currently active cases (those that have been added via add_case() or add_default(...
Definition: dcSwitch.cxx:297
DCPackerInterface * get_default_case() const
Returns the DCPackerInterface that packs the default case, or NULL if there is no default case...
Definition: dcSwitch.cxx:158
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
Definition: dcSwitch.cxx:675
DCPackerInterface * get_case(int n) const
Returns the DCPackerInterface that packs the nth case.
Definition: dcSwitch.cxx:146
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:103
This defines the internal interface for packing values into a DCField.
DCField * get_field_by_name(int case_index, const string &name) const
Returns the field with the given name from the indicated case, or NULL if no field has this name...
Definition: dcSwitch.cxx:204