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  */
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  */
102 int DCSwitch::
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  */
111 int DCSwitch::
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  */
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  */
152 int DCSwitch::
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  */
190 bool DCSwitch::
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  */
200 int DCSwitch::
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  */
220 void DCSwitch::
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  */
230 bool DCSwitch::
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  */
249 bool DCSwitch::
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  */
272 void DCSwitch::
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  */
304 void DCSwitch::
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  */
313 void DCSwitch::
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  */
322 void DCSwitch::
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  */
366 void DCSwitch::
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  */
415 void DCSwitch::
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  */
451 bool DCSwitch::
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  */
498 bool DCSwitch::
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  */
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 }
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 get_case_by_value(const vector_uchar &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
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 is a block of data that receives the results of DCPacker.
Definition: dcPackData.h:22
int add_case(const vector_uchar &value)
Adds a new case to the switch with the indicated value, and returns the new case_index.
Definition: dcSwitch.cxx:201
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
Definition: dcPackData.I:47
DCField * get_key_parameter() const
Returns the key parameter on which the switch is based.
Definition: dcSwitch.cxx:94
const std::string & get_name() const
Returns the name of this field, or empty string if the field is unnamed.
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.
A single field of a Distributed Class, either atomic or molecular.
Definition: dcField.h:37
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
vector_uchar get_value(int case_index) const
Returns the packed value associated with the indicated case.
Definition: dcSwitch.cxx:144
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
void add_invalid_case()
Adds a new case to the switch that will never be matched.
Definition: dcSwitch.cxx:221
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:30
void output(std::ostream &out) const
Write a string representation of this instance to <out>.
Definition: dcField.I:141
int get_num_cases() const
Returns the number of different cases within the switch.
Definition: dcSwitch.cxx:103
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 do_check_match_switch_case(const SwitchFields *other) const
Returns true if this case matches the indicated case, false otherwise.
Definition: dcSwitch.cxx:641
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPacker.I:583
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this field into the hash.
Definition: dcField.cxx:467
void add_break()
Adds a break statement to the switch.
Definition: dcSwitch.cxx:273
DCField * get_field(int case_index, int n) const
Returns the nth field in the indicated case.
Definition: dcSwitch.cxx:162
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.
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
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...
void add_blob(const vector_uchar &bytes)
Adds a blob to the hash, by breaking it down into a sequence of integers.
bool add_default()
Adds a default case to the switch.
Definition: dcSwitch.cxx:231
virtual void output(std::ostream &out, bool brief) const
Write a string representation of this instance to <out>.
Definition: dcSwitch.cxx:305
void pack_default_value()
Adds the default value for the current element into the stream.
Definition: dcPacker.cxx:552
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:604
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
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
const std::string & get_name() const
Returns the name of this switch.
Definition: dcSwitch.cxx:84
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this switch into the hash.
Definition: dcSwitch.cxx:416
bool has_default_value() const
Returns true if a default value has been explicitly established for this field, false otherwise.
Definition: dcField.I:36
const char * get_data() const
Returns the beginning of the data buffer.
Definition: dcPacker.I:641
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
This class generates an arbitrary hash number from a sequence of ints.
Definition: hashGenerator.h:24
void pack_literal_value(const vector_uchar &value)
Adds the indicated string value into the stream, representing a single pre- packed field element,...
Definition: dcPacker.I:238
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:73
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
std::string format_data(const vector_uchar &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
int get_num_fields(int case_index) const
Returns the number of fields in the indicated case.
Definition: dcSwitch.cxx:153
void output_instance(std::ostream &out, bool brief, const std::string &prename, const std::string &name, const std::string &postname) const
Generates a parseable description of the object to the indicated output stream.
Definition: dcSwitch.cxx:323
This class can be used for packing a series of numeric and string data into a binary stream,...
Definition: dcPacker.h:34
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
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 DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
Definition: dcSwitch.cxx:593
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:98
This defines the internal interface for packing values into a DCField.