00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "dcSwitch.h"
00016 #include "dcField.h"
00017 #include "dcParameter.h"
00018 #include "hashGenerator.h"
00019 #include "dcindent.h"
00020 #include "dcPacker.h"
00021
00022
00023
00024
00025
00026
00027
00028
00029 DCSwitch::
00030 DCSwitch(const string &name, DCField *key_parameter) :
00031 _name(name),
00032 _key_parameter(key_parameter)
00033 {
00034 _default_case = NULL;
00035 _fields_added = false;
00036 }
00037
00038
00039
00040
00041
00042
00043 DCSwitch::
00044 ~DCSwitch() {
00045 nassertv(_key_parameter != (DCField *)NULL);
00046 delete _key_parameter;
00047
00048 Cases::iterator ci;
00049 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
00050 SwitchCase *dcase = (*ci);
00051 delete dcase;
00052 }
00053
00054 CaseFields::iterator fi;
00055 for (fi = _case_fields.begin(); fi != _case_fields.end(); ++fi) {
00056 SwitchFields *fields = (*fi);
00057 delete fields;
00058 }
00059
00060 Fields::iterator ni;
00061 for (ni = _nested_fields.begin(); ni != _nested_fields.end(); ++ni) {
00062 DCField *field = (*ni);
00063 delete field;
00064 }
00065 }
00066
00067
00068
00069
00070
00071
00072 DCSwitch *DCSwitch::
00073 as_switch() {
00074 return this;
00075 }
00076
00077
00078
00079
00080
00081
00082 const DCSwitch *DCSwitch::
00083 as_switch() const {
00084 return this;
00085 }
00086
00087
00088
00089
00090
00091
00092 const string &DCSwitch::
00093 get_name() const {
00094 return _name;
00095 }
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 DCField *DCSwitch::
00106 get_key_parameter() const {
00107 return _key_parameter;
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117 int DCSwitch::
00118 get_num_cases() const {
00119 return _cases.size();
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129 int DCSwitch::
00130 get_case_by_value(const string &case_value) const {
00131 CasesByValue::const_iterator vi;
00132 vi = _cases_by_value.find(case_value);
00133 if (vi != _cases_by_value.end()) {
00134 return (*vi).second;
00135 }
00136
00137 return -1;
00138 }
00139
00140
00141
00142
00143
00144
00145 DCPackerInterface *DCSwitch::
00146 get_case(int n) const {
00147 nassertr(n >= 0 && n < (int)_cases.size(), NULL);
00148 return _cases[n]->_fields;
00149 }
00150
00151
00152
00153
00154
00155
00156
00157 DCPackerInterface *DCSwitch::
00158 get_default_case() const {
00159 return _default_case;
00160 }
00161
00162
00163
00164
00165
00166
00167
00168 string DCSwitch::
00169 get_value(int case_index) const {
00170 nassertr(case_index >= 0 && case_index < (int)_cases.size(), string());
00171 return _cases[case_index]->_value;
00172 }
00173
00174
00175
00176
00177
00178
00179 int DCSwitch::
00180 get_num_fields(int case_index) const {
00181 nassertr(case_index >= 0 && case_index < (int)_cases.size(), 0);
00182 return _cases[case_index]->_fields->_fields.size();
00183 }
00184
00185
00186
00187
00188
00189
00190 DCField *DCSwitch::
00191 get_field(int case_index, int n) const {
00192 nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);
00193 nassertr(n >= 0 && n < (int)_cases[case_index]->_fields->_fields.size(), NULL);
00194 return _cases[case_index]->_fields->_fields[n];
00195 }
00196
00197
00198
00199
00200
00201
00202
00203 DCField *DCSwitch::
00204 get_field_by_name(int case_index, const string &name) const {
00205 nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);
00206
00207 const FieldsByName &fields_by_name = _cases[case_index]->_fields->_fields_by_name;
00208 FieldsByName::const_iterator ni;
00209 ni = fields_by_name.find(name);
00210 if (ni != fields_by_name.end()) {
00211 return (*ni).second;
00212 }
00213
00214 return NULL;
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224 bool DCSwitch::
00225 is_field_valid() const {
00226 return !_current_fields.empty();
00227 }
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 int DCSwitch::
00238 add_case(const string &value) {
00239 int case_index = (int)_cases.size();
00240 if (!_cases_by_value.insert(CasesByValue::value_type(value, case_index)).second) {
00241 add_invalid_case();
00242 return -1;
00243 }
00244
00245 SwitchFields *fields = start_new_case();
00246 SwitchCase *dcase = new SwitchCase(value, fields);
00247 _cases.push_back(dcase);
00248 return case_index;
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 void DCSwitch::
00261 add_invalid_case() {
00262 start_new_case();
00263 }
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 bool DCSwitch::
00274 add_default() {
00275 if (_default_case != (SwitchFields *)NULL) {
00276 add_invalid_case();
00277 return false;
00278 }
00279
00280 SwitchFields *fields = start_new_case();
00281 _default_case = fields;
00282 return true;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 bool DCSwitch::
00297 add_field(DCField *field) {
00298 nassertr(!_current_fields.empty(), false);
00299
00300 bool all_ok = true;
00301
00302 CaseFields::iterator fi;
00303 for (fi = _current_fields.begin(); fi != _current_fields.end(); ++fi) {
00304 SwitchFields *fields = (*fi);
00305 if (!fields->add_field(field)) {
00306 all_ok = false;
00307 }
00308 }
00309 _nested_fields.push_back(field);
00310 _fields_added = true;
00311
00312 return all_ok;
00313 }
00314
00315
00316
00317
00318
00319
00320
00321
00322 void DCSwitch::
00323 add_break() {
00324 _current_fields.clear();
00325 _fields_added = false;
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 const DCPackerInterface *DCSwitch::
00337 apply_switch(const char *value_data, size_t length) const {
00338 CasesByValue::const_iterator vi;
00339 vi = _cases_by_value.find(string(value_data, length));
00340 if (vi != _cases_by_value.end()) {
00341 return _cases[(*vi).second]->_fields;
00342 }
00343
00344
00345 if (_default_case != (SwitchFields *)NULL) {
00346 return _default_case;
00347 }
00348
00349
00350 return NULL;
00351 }
00352
00353
00354
00355
00356
00357
00358
00359 void DCSwitch::
00360 output(ostream &out, bool brief) const {
00361 output_instance(out, brief, "", "", "");
00362 }
00363
00364
00365
00366
00367
00368
00369
00370 void DCSwitch::
00371 write(ostream &out, bool brief, int indent_level) const {
00372 write_instance(out, brief, indent_level, "", "", "");
00373 }
00374
00375
00376
00377
00378
00379
00380
00381 void DCSwitch::
00382 output_instance(ostream &out, bool brief, const string &prename,
00383 const string &name, const string &postname) const {
00384 out << "switch";
00385 if (!_name.empty()) {
00386 out << " " << _name;
00387 }
00388 out << " (";
00389 _key_parameter->output(out, brief);
00390 out << ") {";
00391
00392 const SwitchFields *last_fields = NULL;
00393
00394 Cases::const_iterator ci;
00395 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
00396 const SwitchCase *dcase = (*ci);
00397 if (dcase->_fields != last_fields && last_fields != (SwitchFields *)NULL) {
00398 last_fields->output(out, brief);
00399 }
00400 last_fields = dcase->_fields;
00401 out << "case " << _key_parameter->format_data(dcase->_value, false) << ": ";
00402 }
00403
00404 if (_default_case != (SwitchFields *)NULL) {
00405 if (_default_case != last_fields && last_fields != (SwitchFields *)NULL) {
00406 last_fields->output(out, brief);
00407 }
00408 last_fields = _default_case;
00409 out << "default: ";
00410 }
00411 if (last_fields != (SwitchFields *)NULL) {
00412 last_fields->output(out, brief);
00413 }
00414
00415 out << "}";
00416 if (!prename.empty() || !name.empty() || !postname.empty()) {
00417 out << " " << prename << name << postname;
00418 }
00419 }
00420
00421
00422
00423
00424
00425
00426
00427 void DCSwitch::
00428 write_instance(ostream &out, bool brief, int indent_level,
00429 const string &prename, const string &name,
00430 const string &postname) const {
00431 indent(out, indent_level)
00432 << "switch";
00433 if (!_name.empty()) {
00434 out << " " << _name;
00435 }
00436 out << " (";
00437 _key_parameter->output(out, brief);
00438 out << ") {\n";
00439
00440 const SwitchFields *last_fields = NULL;
00441
00442 Cases::const_iterator ci;
00443 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
00444 const SwitchCase *dcase = (*ci);
00445 if (dcase->_fields != last_fields && last_fields != (SwitchFields *)NULL) {
00446 last_fields->write(out, brief, indent_level + 2);
00447 }
00448 last_fields = dcase->_fields;
00449 indent(out, indent_level)
00450 << "case " << _key_parameter->format_data(dcase->_value, false) << ":\n";
00451 }
00452
00453 if (_default_case != (SwitchFields *)NULL) {
00454 if (_default_case != last_fields && last_fields != (SwitchFields *)NULL) {
00455 last_fields->write(out, brief, indent_level + 2);
00456 }
00457 last_fields = _default_case;
00458 indent(out, indent_level)
00459 << "default:\n";
00460 }
00461 if (last_fields != (SwitchFields *)NULL) {
00462 last_fields->write(out, brief, indent_level + 2);
00463 }
00464
00465 indent(out, indent_level)
00466 << "}";
00467 if (!prename.empty() || !name.empty() || !postname.empty()) {
00468 out << " " << prename << name << postname;
00469 }
00470 out << ";\n";
00471 }
00472
00473
00474
00475
00476
00477
00478
00479 void DCSwitch::
00480 generate_hash(HashGenerator &hashgen) const {
00481 hashgen.add_string(_name);
00482
00483 _key_parameter->generate_hash(hashgen);
00484
00485 hashgen.add_int(_cases.size());
00486 Cases::const_iterator ci;
00487 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
00488 const SwitchCase *dcase = (*ci);
00489 hashgen.add_string(dcase->_value);
00490
00491 const SwitchFields *fields = dcase->_fields;
00492 hashgen.add_int(fields->_fields.size());
00493 Fields::const_iterator fi;
00494 for (fi = fields->_fields.begin(); fi != fields->_fields.end(); ++fi) {
00495 (*fi)->generate_hash(hashgen);
00496 }
00497 }
00498
00499 if (_default_case != (SwitchFields *)NULL) {
00500 const SwitchFields *fields = _default_case;
00501 hashgen.add_int(fields->_fields.size());
00502 Fields::const_iterator fi;
00503 for (fi = fields->_fields.begin(); fi != fields->_fields.end(); ++fi) {
00504 (*fi)->generate_hash(hashgen);
00505 }
00506 }
00507 }
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 bool DCSwitch::
00519 pack_default_value(DCPackData &pack_data, bool &pack_error) const {
00520 SwitchFields *fields = NULL;
00521 DCPacker packer;
00522 packer.begin_pack(_key_parameter);
00523 if (!_cases.empty()) {
00524
00525
00526
00527 packer.pack_literal_value(_cases[0]->_value);
00528 fields = _cases[0]->_fields;
00529
00530 } else {
00531
00532
00533 packer.pack_default_value();
00534 fields = _default_case;
00535 }
00536
00537 if (!packer.end_pack()) {
00538 pack_error = true;
00539 }
00540
00541 if (fields == (SwitchFields *)NULL) {
00542 pack_error = true;
00543
00544 } else {
00545
00546 for (size_t i = 1; i < fields->_fields.size(); i++) {
00547 packer.begin_pack(fields->_fields[i]);
00548 packer.pack_default_value();
00549 if (!packer.end_pack()) {
00550 pack_error = true;
00551 }
00552 }
00553 }
00554
00555 pack_data.append_data(packer.get_data(), packer.get_length());
00556
00557 return true;
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569 bool DCSwitch::
00570 do_check_match_switch(const DCSwitch *other) const {
00571 if (!_key_parameter->check_match(other->_key_parameter)) {
00572 return false;
00573 }
00574
00575 if (_cases.size() != other->_cases.size()) {
00576 return false;
00577 }
00578
00579 Cases::const_iterator ci;
00580 for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
00581 const SwitchCase *c1 = (*ci);
00582 CasesByValue::const_iterator vi;
00583 vi = other->_cases_by_value.find(c1->_value);
00584 if (vi == other->_cases_by_value.end()) {
00585
00586 return false;
00587 }
00588 int c2_index = (*vi).second;
00589 nassertr(c2_index >= 0 && c2_index < (int)other->_cases.size(), false);
00590 const SwitchCase *c2 = other->_cases[c2_index];
00591
00592 if (!c1->do_check_match_switch_case(c2)) {
00593 return false;
00594 }
00595 }
00596
00597 return true;
00598 }
00599
00600
00601
00602
00603
00604
00605
00606
00607 DCSwitch::SwitchFields *DCSwitch::
00608 start_new_case() {
00609 SwitchFields *fields = NULL;
00610
00611 if (_current_fields.empty() || _fields_added) {
00612
00613
00614
00615
00616
00617 fields = new SwitchFields(_name);
00618 fields->add_field(_key_parameter);
00619
00620 _case_fields.push_back(fields);
00621 _current_fields.push_back(fields);
00622
00623 } else {
00624
00625 fields = _current_fields.back();
00626 }
00627
00628 _fields_added = false;
00629
00630 return fields;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639 DCSwitch::SwitchFields::
00640 SwitchFields(const string &name) :
00641 DCPackerInterface(name)
00642 {
00643 _has_nested_fields = true;
00644 _num_nested_fields = 0;
00645 _pack_type = PT_switch;
00646
00647 _has_fixed_byte_size = true;
00648 _fixed_byte_size = 0;
00649 _has_fixed_structure = true;
00650 _has_range_limits = false;
00651 _has_default_value = false;
00652 }
00653
00654
00655
00656
00657
00658
00659 DCSwitch::SwitchFields::
00660 ~SwitchFields() {
00661
00662
00663
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 DCPackerInterface *DCSwitch::SwitchFields::
00675 get_nested_field(int n) const {
00676 nassertr(n >= 0 && n < (int)_fields.size(), NULL);
00677 return _fields[n];
00678 }
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688 bool DCSwitch::SwitchFields::
00689 add_field(DCField *field) {
00690 if (!field->get_name().empty()) {
00691 bool inserted = _fields_by_name.insert
00692 (FieldsByName::value_type(field->get_name(), field)).second;
00693
00694 if (!inserted) {
00695 return false;
00696 }
00697 }
00698
00699 _fields.push_back(field);
00700
00701 _num_nested_fields = (int)_fields.size();
00702
00703
00704 if (_has_fixed_byte_size) {
00705 _has_fixed_byte_size = field->has_fixed_byte_size();
00706 _fixed_byte_size += field->get_fixed_byte_size();
00707 }
00708 if (_has_fixed_structure) {
00709 _has_fixed_structure = field->has_fixed_structure();
00710 }
00711 if (!_has_range_limits) {
00712 _has_range_limits = field->has_range_limits();
00713 }
00714 if (!_has_default_value) {
00715 _has_default_value = field->has_default_value();
00716 }
00717 return true;
00718 }
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728 bool DCSwitch::SwitchFields::
00729 do_check_match_switch_case(const DCSwitch::SwitchFields *other) const {
00730 if (_fields.size() != other->_fields.size()) {
00731 return false;
00732 }
00733 for (size_t i = 0; i < _fields.size(); i++) {
00734 if (!_fields[i]->check_match(other->_fields[i])) {
00735 return false;
00736 }
00737 }
00738
00739 return true;
00740 }
00741
00742
00743
00744
00745
00746
00747 void DCSwitch::SwitchFields::
00748 output(ostream &out, bool brief) const {
00749 Fields::const_iterator fi;
00750 if (!_fields.empty()) {
00751 fi = _fields.begin();
00752 ++fi;
00753 while (fi != _fields.end()) {
00754 (*fi)->output(out, brief);
00755 out << "; ";
00756 ++fi;
00757 }
00758 }
00759 out << "break; ";
00760 }
00761
00762
00763
00764
00765
00766
00767 void DCSwitch::SwitchFields::
00768 write(ostream &out, bool brief, int indent_level) const {
00769 Fields::const_iterator fi;
00770 if (!_fields.empty()) {
00771 fi = _fields.begin();
00772 ++fi;
00773 while (fi != _fields.end()) {
00774 (*fi)->write(out, brief, indent_level);
00775 ++fi;
00776 }
00777 }
00778 indent(out, indent_level)
00779 << "break;\n";
00780 }
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790 bool DCSwitch::SwitchFields::
00791 do_check_match(const DCPackerInterface *) const {
00792
00793 nassertr(false, false);
00794 return false;
00795 }
00796
00797
00798
00799
00800
00801
00802 DCSwitch::SwitchCase::
00803 SwitchCase(const string &value, DCSwitch::SwitchFields *fields) :
00804 _value(value),
00805 _fields(fields)
00806 {
00807 }
00808
00809
00810
00811
00812
00813
00814 DCSwitch::SwitchCase::
00815 ~SwitchCase() {
00816 }
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826 bool DCSwitch::SwitchCase::
00827 do_check_match_switch_case(const DCSwitch::SwitchCase *other) const {
00828 return _fields->do_check_match_switch_case(other->_fields);
00829 }