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();
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) {
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;
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;
293 if (_default_case !=
nullptr) {
294 return _default_case;
305output(ostream &out,
bool brief)
const {
314write(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;
562DCSwitch::SwitchFields::
563SwitchFields(
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;
580DCSwitch::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])) {
657void DCSwitch::SwitchFields::
658output(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);
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();
681 while (fi != _fields.end()) {
682 (*fi)->write(out, brief, indent_level);
695bool DCSwitch::SwitchFields::
698 nassertr(
false,
false);
705DCSwitch::SwitchCase::
715DCSwitch::SwitchCase::
726 return _fields->do_check_match_switch_case(other->_fields);
A single field of a Distributed Class, either atomic or molecular.
bool has_default_value() const
Returns true if a default value has been explicitly established for this field, false otherwise.
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...
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this field into the hash.
void output(std::ostream &out) const
Write a string representation of this instance to <out>.
This is a block of data that receives the results of DCPacker.
void append_data(const char *buffer, size_t size)
Adds the indicated bytes to the end of the data.
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,...
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
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,...
bool end_pack()
Finishes a packing session.
const char * get_data() const
Returns the beginning of the data buffer.
void pack_default_value()
Adds the default value for the current element into the stream.
size_t get_length() const
Returns the current length of the buffer.
bool do_check_match_switch_case(const SwitchCase *other) const
Returns true if this case matches the indicated case, false otherwise.
bool add_field(DCField *field)
Adds a field to this case.
bool do_check_match_switch_case(const SwitchFields *other) const
Returns true if this case matches the indicated case, false otherwise.
virtual DCPackerInterface * get_nested_field(int n) const
Returns the DCPackerInterface object that represents the nth nested field.
This represents a switch statement, which can appear inside a class body and represents two or more a...
const std::string & get_name() const
Returns the name of this switch.
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.
int get_num_fields(int case_index) const
Returns the number of fields in the indicated case.
bool add_default()
Adds a default case to the switch.
DCField * get_field(int case_index, int n) const
Returns the nth field in the indicated case.
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...
std::vector< unsigned char > get_value(int case_index) const
Returns the packed value associated with the indicated case.
bool add_field(DCField *field)
Adds a field to the currently active cases (those that have been added via add_case() or add_default(...
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...
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...
void add_break()
Adds a break statement to the switch.
int get_num_cases() const
Returns the number of different cases within the switch.
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.
void add_invalid_case()
Adds a new case to the switch that will never be matched.
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...
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.
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this switch into the hash.
DCField * get_key_parameter() const
Returns the key parameter on which the switch is based.
DCPackerInterface * get_default_case() const
Returns the DCPackerInterface that packs the default case, or NULL if there is no default case.
virtual void output(std::ostream &out, bool brief) const
Write a string representation of this instance to <out>.
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 ...
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 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.
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 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.