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