Panda3D
Loading...
Searching...
No Matches
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
21using std::ostream;
22using 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 */
29DCSwitch(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 */
40DCSwitch::
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 */
67DCSwitch *DCSwitch::
68as_switch() {
69 return this;
70}
71
72/**
73 *
74 */
75const DCSwitch *DCSwitch::
76as_switch() const {
77 return this;
78}
79
80/**
81 * Returns the name of this switch.
82 */
83const string &DCSwitch::
84get_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 */
94get_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 */
103get_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 */
112get_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 */
126get_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 */
136get_default_case() const {
137 return _default_case;
138}
139
140/**
141 * Returns the packed value associated with the indicated case.
142 */
143vector_uchar DCSwitch::
144get_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 */
153get_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 */
162get_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 */
173get_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 */
191is_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 */
201add_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 */
231add_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 */
250add_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 */
273add_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 */
284apply_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 */
305output(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 */
314write(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 */
323output_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 */
367write_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 */
416generate_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 */
452pack_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 */
499do_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 */
533DCSwitch::SwitchFields *DCSwitch::
534start_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 */
562DCSwitch::SwitchFields::
563SwitchFields(const string &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 */
580DCSwitch::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 */
593get_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 */
604add_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 */
657void DCSwitch::SwitchFields::
658output(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 */
675void DCSwitch::SwitchFields::
676write(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 */
695bool DCSwitch::SwitchFields::
696do_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 */
705DCSwitch::SwitchCase::
706SwitchCase(const vector_uchar &value, DCSwitch::SwitchFields *fields) :
707 _value(value),
708 _fields(fields)
709{
710}
711
712/**
713 *
714 */
715DCSwitch::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.
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