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 */
28 DCSwitch::
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 */
93 DCField *DCSwitch::
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 */
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 */
125 DCPackerInterface *DCSwitch::
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 */
135 DCPackerInterface *DCSwitch::
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 */
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 */
161 DCField *DCSwitch::
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 */
172 DCField *DCSwitch::
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) {
204 add_invalid_case();
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::
221 add_invalid_case() {
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::
231 add_default() {
232 if (_default_case != nullptr) {
233 add_invalid_case();
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::
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 */
272 void DCSwitch::
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 */
283 const DCPackerInterface *DCSwitch::
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 */
592 DCPackerInterface *DCSwitch::SwitchFields::
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 */
603 bool DCSwitch::SwitchFields::
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 */
640 bool DCSwitch::SwitchFields::
641 do_check_match_switch_case(const DCSwitch::SwitchFields *other) const {
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 */
724 bool DCSwitch::SwitchCase::
725 do_check_match_switch_case(const DCSwitch::SwitchCase *other) const {
726 return _fields->do_check_match_switch_case(other->_fields);
727 }
DCField
A single field of a Distributed Class, either atomic or molecular.
Definition: dcField.h:37
DCField::has_default_value
bool has_default_value() const
Returns true if a default value has been explicitly established for this field, false otherwise.
Definition: dcField.I:36
DCField::format_data
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
DCField::generate_hash
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this field into the hash.
Definition: dcField.cxx:467
DCField::output
void output(std::ostream &out) const
Write a string representation of this instance to <out>.
Definition: dcField.I:141
DCPackData
This is a block of data that receives the results of DCPacker.
Definition: dcPackData.h:22
DCPackData::append_data
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
Definition: dcPackData.I:47
DCPackerInterface
This defines the internal interface for packing values into a DCField.
Definition: dcPackerInterface.h:67
DCPackerInterface::has_fixed_structure
bool has_fixed_structure() const
Returns true if this field type always has the same structure regardless of the data in the stream,...
Definition: dcPackerInterface.I:59
DCPackerInterface::get_name
const std::string & get_name() const
Returns the name of this field, or empty string if the field is unnamed.
Definition: dcPackerInterface.I:18
DCPackerInterface::get_fixed_byte_size
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.
Definition: dcPackerInterface.I:46
DCPackerInterface::has_fixed_byte_size
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.
Definition: dcPackerInterface.I:37
DCPackerInterface::check_match
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 ...
Definition: dcPackerInterface.I:28
DCPackerInterface::has_range_limits
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...
Definition: dcPackerInterface.I:69
DCPacker
This class can be used for packing a series of numeric and string data into a binary stream,...
Definition: dcPacker.h:34
DCPacker::begin_pack
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:73
DCPacker::pack_literal_value
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
DCPacker::end_pack
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:98
DCPacker::get_data
const char * get_data() const
Returns the beginning of the data buffer.
Definition: dcPacker.I:641
DCPacker::pack_default_value
void pack_default_value()
Adds the default value for the current element into the stream.
Definition: dcPacker.cxx:552
DCPacker::get_length
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPacker.I:583
DCSwitch::SwitchCase
Definition: dcSwitch.h:99
DCSwitch::SwitchCase::do_check_match_switch_case
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
DCSwitch::SwitchFields
Definition: dcSwitch.h:78
DCSwitch::SwitchFields::add_field
bool add_field(DCField *field)
Adds a field to this case.
Definition: dcSwitch.cxx:604
DCSwitch::SwitchFields::do_check_match_switch_case
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
DCSwitch::SwitchFields::get_nested_field
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
Definition: dcSwitch.cxx:593
DCSwitch
This represents a switch statement, which can appear inside a class body and represents two or more a...
Definition: dcSwitch.h:30
DCSwitch::get_name
const std::string & get_name() const
Returns the name of this switch.
Definition: dcSwitch.cxx:84
DCSwitch::get_case
DCPackerInterface * get_case(int n) const
Returns the DCPackerInterface that packs the nth case.
Definition: dcSwitch.cxx:126
DCSwitch::write
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
DCSwitch::get_num_fields
int get_num_fields(int case_index) const
Returns the number of fields in the indicated case.
Definition: dcSwitch.cxx:153
DCSwitch::add_default
bool add_default()
Adds a default case to the switch.
Definition: dcSwitch.cxx:231
DCSwitch::get_field
DCField * get_field(int case_index, int n) const
Returns the nth field in the indicated case.
Definition: dcSwitch.cxx:162
DCSwitch::get_case_by_value
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
DCSwitch::get_value
std::vector< unsigned char > get_value(int case_index) const
Returns the packed value associated with the indicated case.
Definition: dcSwitch.cxx:144
DCSwitch::add_field
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
DCSwitch::is_field_valid
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::DCSwitch
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
DCSwitch::add_break
void add_break()
Adds a break statement to the switch.
Definition: dcSwitch.cxx:273
DCSwitch::get_num_cases
int get_num_cases() const
Returns the number of different cases within the switch.
Definition: dcSwitch.cxx:103
DCSwitch::write_instance
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
DCSwitch::add_invalid_case
void add_invalid_case()
Adds a new case to the switch that will never be matched.
Definition: dcSwitch.cxx:221
DCSwitch::apply_switch
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
DCSwitch::output_instance
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
DCSwitch::generate_hash
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this switch into the hash.
Definition: dcSwitch.cxx:416
DCSwitch::get_key_parameter
DCField * get_key_parameter() const
Returns the key parameter on which the switch is based.
Definition: dcSwitch.cxx:94
DCSwitch::get_default_case
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
DCSwitch::output
virtual void output(std::ostream &out, bool brief) const
Write a string representation of this instance to <out>.
Definition: dcSwitch.cxx:305
DCSwitch::do_check_match_switch
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
DCSwitch::pack_default_value
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
DCSwitch::add_case
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
DCSwitch::get_field_by_name
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
HashGenerator
This class generates an arbitrary hash number from a sequence of ints.
Definition: hashGenerator.h:23
HashGenerator::add_blob
void add_blob(const std::vector< unsigned char > &bytes)
Adds a blob to the hash, by breaking it down into a sequence of integers.
Definition: hashGenerator.cxx:63
HashGenerator::add_int
void add_int(int num)
Adds another integer to the hash so far.
Definition: hashGenerator.cxx:41
HashGenerator::add_string
void add_string(const std::string &str)
Adds a string to the hash, by breaking it down into a sequence of integers.
Definition: hashGenerator.cxx:51
dcField.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcPacker.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcParameter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcSwitch.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcindent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
hashGenerator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20