31 _key_parameter(key_parameter)
33 _default_case =
nullptr;
34 _fields_added =
false;
42 nassertv(_key_parameter !=
nullptr);
43 delete _key_parameter;
46 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
47 SwitchCase *dcase = (*ci);
51 CaseFields::iterator fi;
52 for (fi = _case_fields.begin(); fi != _case_fields.end(); ++fi) {
53 SwitchFields *fields = (*fi);
58 for (ni = _nested_fields.begin(); ni != _nested_fields.end(); ++ni) {
95 return _key_parameter;
104 return _cases.size();
113 CasesByValue::const_iterator vi;
114 vi = _cases_by_value.find(case_value);
115 if (vi != _cases_by_value.end()) {
127 nassertr(n >= 0 && n < (
int)_cases.size(),
nullptr);
128 return _cases[n]->_fields;
137 return _default_case;
145 nassertr(case_index >= 0 && case_index < (
int)_cases.size(), vector_uchar());
146 return _cases[case_index]->_value;
154 nassertr(case_index >= 0 && case_index < (
int)_cases.size(), 0);
155 return _cases[case_index]->_fields->_fields.size();
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];
174 nassertr(case_index >= 0 && case_index < (
int)_cases.size(),
nullptr);
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()) {
192 return !_current_fields.empty();
202 int case_index = (int)_cases.size();
203 if (!_cases_by_value.insert(CasesByValue::value_type(value, case_index)).second) {
210 _cases.push_back(dcase);
232 if (_default_case !=
nullptr) {
238 _default_case = fields;
251 nassertr(!_current_fields.empty(),
false);
255 CaseFields::iterator fi;
256 for (fi = _current_fields.begin(); fi != _current_fields.end(); ++fi) {
262 _nested_fields.push_back(field);
263 _fields_added =
true;
274 _current_fields.clear();
275 _fields_added =
false;
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;
293 if (_default_case !=
nullptr) {
294 return _default_case;
314 write(ostream &out,
bool brief,
int indent_level)
const {
324 const string &name,
const string &postname)
const {
326 if (!_name.empty()) {
330 _key_parameter->
output(out, brief);
335 Cases::const_iterator ci;
336 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
338 if (dcase->_fields != last_fields && last_fields !=
nullptr) {
339 last_fields->output(out, brief);
341 last_fields = dcase->_fields;
342 out <<
"case " << _key_parameter->
format_data(dcase->_value,
false) <<
": ";
345 if (_default_case !=
nullptr) {
346 if (_default_case != last_fields && last_fields !=
nullptr) {
347 last_fields->output(out, brief);
349 last_fields = _default_case;
352 if (last_fields !=
nullptr) {
353 last_fields->output(out, brief);
357 if (!prename.empty() || !name.empty() || !postname.empty()) {
358 out <<
" " << prename << name << postname;
368 const string &prename,
const string &name,
369 const string &postname)
const {
372 if (!_name.empty()) {
376 _key_parameter->
output(out, brief);
381 Cases::const_iterator ci;
382 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
384 if (dcase->_fields != last_fields && last_fields !=
nullptr) {
385 last_fields->write(out, brief, indent_level + 2);
387 last_fields = dcase->_fields;
389 <<
"case " << _key_parameter->
format_data(dcase->_value,
false) <<
":\n";
392 if (_default_case !=
nullptr) {
393 if (_default_case != last_fields && last_fields !=
nullptr) {
394 last_fields->write(out, brief, indent_level + 2);
396 last_fields = _default_case;
400 if (last_fields !=
nullptr) {
401 last_fields->write(out, brief, indent_level + 2);
406 if (!prename.empty() || !name.empty() || !postname.empty()) {
407 out <<
" " << prename << name << postname;
421 hashgen.
add_int(_cases.size());
422 Cases::const_iterator ci;
423 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
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);
435 if (_default_case !=
nullptr) {
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);
456 if (!_cases.empty()) {
461 fields = _cases[0]->_fields;
466 fields = _default_case;
473 if (fields ==
nullptr) {
478 for (
size_t i = 1; i < fields->_fields.size(); i++) {
500 if (!_key_parameter->
check_match(other->_key_parameter)) {
504 if (_cases.size() != other->_cases.size()) {
508 Cases::const_iterator ci;
509 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
511 CasesByValue::const_iterator vi;
512 vi = other->_cases_by_value.find(c1->_value);
513 if (vi == other->_cases_by_value.end()) {
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];
535 SwitchFields *fields =
nullptr;
537 if (_current_fields.empty() || _fields_added) {
542 fields =
new SwitchFields(_name);
543 fields->add_field(_key_parameter);
545 _case_fields.push_back(fields);
546 _current_fields.push_back(fields);
550 fields = _current_fields.back();
553 _fields_added =
false;
562 DCSwitch::SwitchFields::
563 SwitchFields(
const string &name) :
566 _has_nested_fields =
true;
567 _num_nested_fields = 0;
568 _pack_type = PT_switch;
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;
580 DCSwitch::SwitchFields::
594 nassertr(n >= 0 && n < (
int)_fields.size(),
nullptr);
606 bool inserted = _fields_by_name.insert
607 (FieldsByName::value_type(field->
get_name(), field)).second;
614 _fields.push_back(field);
616 _num_nested_fields = (int)_fields.size();
619 if (_has_fixed_byte_size) {
623 if (_has_fixed_structure) {
626 if (!_has_range_limits) {
629 if (!_has_default_value) {
642 if (_fields.size() != other->_fields.size()) {
645 for (
size_t i = 0; i < _fields.size(); i++) {
646 if (!_fields[i]->check_match(other->_fields[i])) {
657 void DCSwitch::SwitchFields::
658 output(ostream &out,
bool brief)
const {
659 Fields::const_iterator fi;
660 if (!_fields.empty()) {
661 fi = _fields.begin();
663 while (fi != _fields.end()) {
664 (*fi)->output(out, brief);
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();
681 while (fi != _fields.end()) {
682 (*fi)->write(out, brief, indent_level);
695 bool DCSwitch::SwitchFields::
698 nassertr(
false,
false);
705 DCSwitch::SwitchCase::
715 DCSwitch::SwitchCase::
726 return _fields->do_check_match_switch_case(other->_fields);
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.
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) ...
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...
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.
This is a block of data that receives the results of DCPacker.
int add_case(const vector_uchar &value)
Adds a new case to the switch with the indicated value, and returns the new case_index.
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
DCField * get_key_parameter() const
Returns the key parameter on which the switch is based.
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.
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.
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.
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...
void output(std::ostream &out) const
Write a string representation of this instance to <out>.
int get_num_cases() const
Returns the number of different cases within the switch.
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.
bool do_check_match_switch_case(const SwitchFields *other) const
Returns true if this case matches the indicated case, false otherwise.
size_t get_length() const
Returns the current length of the buffer.
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this field into the hash.
void add_break()
Adds a break statement to the switch.
DCField * get_field(int case_index, int n) const
Returns the nth field in the indicated case.
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...
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.
virtual void output(std::ostream &out, bool brief) const
Write a string representation of this instance to <out>.
void pack_default_value()
Adds the default value for the current element into the stream.
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.
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...
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
const std::string & get_name() const
Returns the name of this switch.
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this switch into the hash.
bool has_default_value() const
Returns true if a default value has been explicitly established for this field, false otherwise.
const char * get_data() const
Returns the beginning of the data buffer.
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 ...
This class generates an arbitrary hash number from a sequence of ints.
void pack_literal_value(const vector_uchar &value)
Adds the indicated string value into the stream, representing a single pre- packed field element,...
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
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...
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...
int get_num_fields(int case_index) const
Returns the number of fields in the indicated case.
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.
This class can be used for packing a series of numeric and string data into a binary stream,...
bool add_field(DCField *field)
Adds a field to the currently active cases (those that have been added via add_case() or add_default(...
DCPackerInterface * get_default_case() const
Returns the DCPackerInterface that packs the default case, or NULL if there is no default case.
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
DCPackerInterface * get_case(int n) const
Returns the DCPackerInterface that packs the nth case.
virtual void write(std::ostream &out, bool brief, int indent_level) const
Generates a parseable description of the object to the indicated output stream.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool end_pack()
Finishes a packing session.
This defines the internal interface for packing values into a DCField.