9
9
#include < boost/tokenizer.hpp>
10
10
#include " mfast/field_instructions.h"
11
11
12
+ #ifdef XETRA_FAST_SPECIFICATION
13
+ #include < boost/optional.hpp>
14
+ #endif
15
+
12
16
using namespace tinyxml2 ;
13
17
14
18
namespace mfast {
@@ -520,6 +524,31 @@ void field_builder::add_template(const char *, template_instruction *inst) {
520
524
<< referenced_by_info (parent_->name ()));
521
525
}
522
526
527
+ #if defined(XETRA_FAST_SPECIFICATION)
528
+ bool parse_enum_value (const char **enum_element_names,
529
+ const uint64_t *enum_element_values,
530
+ uint64_t num_elements, const char *value_name,
531
+ uint64_t &result) {
532
+ boost::optional<std::uint64_t > value_int;
533
+ try {
534
+ value_int = std::stoul (value_name);
535
+ } catch (...) {}
536
+ for (uint64_t i = 0 ; i < num_elements; ++i) {
537
+ // FAST 1.2 does not cleary specify what a default enum value refers to,
538
+ // search for a match in either name or value/deduce_value
539
+ if (std::strcmp (enum_element_names[i], value_name) == 0 ||
540
+ (value_int.has_value () && enum_element_values[i] == *value_int)) {
541
+ if (enum_element_values)
542
+ result = enum_element_values[i];
543
+ else
544
+ result = i;
545
+ return true ;
546
+ }
547
+ }
548
+
549
+ return false ;
550
+ }
551
+ #else
523
552
bool parse_enum_value (const char **enum_element_names,
524
553
const uint64_t *enum_element_values,
525
554
uint64_t num_elements, const char *value_name,
@@ -537,6 +566,7 @@ bool parse_enum_value(const char **enum_element_names,
537
566
538
567
return false ;
539
568
}
569
+ #endif
540
570
541
571
bool parse_enum_value (const enum_field_instruction *inst,
542
572
const char *value_name, uint64_t &result) {
@@ -547,6 +577,117 @@ bool parse_enum_value(const enum_field_instruction *inst,
547
577
struct tag_value ;
548
578
typedef boost::error_info<tag_value, std::string> value_info;
549
579
580
+
581
+ #if defined(XETRA_FAST_SPECIFICATION)
582
+ void field_builder::visit (const enum_field_instruction *inst, void *) {
583
+
584
+ const XMLElement *element = &this ->element_ ;
585
+ if (!field_op::find_field_op_element (*element))
586
+ element = content_element_;
587
+ field_op fop (inst, element, alloc ());
588
+
589
+ const char **enum_element_names = inst->elements ();
590
+ uint64_t num_elements = inst->num_elements ();
591
+ const uint64_t *enum_element_values = inst->element_values ();
592
+
593
+ const char *init_value_str = nullptr ;
594
+ if (!fop.initial_value_ .is_defined ()) {
595
+ // if the defined flag is false, the content value is parsed string from
596
+ // XML
597
+ init_value_str = fop.initial_value_ .get <const char *>();
598
+ }
599
+
600
+ if (enum_element_names == nullptr ) {
601
+
602
+ std::deque<const char *> names;
603
+ std::deque<uint64_t > values;
604
+
605
+ const XMLElement *xml_element =
606
+ content_element_->FirstChildElement (" element" );
607
+ for (; xml_element != nullptr ;
608
+ xml_element = xml_element->NextSiblingElement (" element" )) {
609
+ // Use fancier identifier if available (Eurex style)
610
+ const char *name_attr = xml_element->Attribute (" id" );
611
+ // Otherwise revert to the specified name attribute
612
+ if (name_attr == nullptr )
613
+ name_attr = xml_element->Attribute (" name" );
614
+ if (name_attr != nullptr ) {
615
+ if (init_value_str && std::strcmp (name_attr, init_value_str) == 0 ) {
616
+ fop.initial_value_ .set <uint64_t >(names.size ());
617
+ }
618
+ names.push_back (string_dup (name_attr, alloc ()));
619
+
620
+ const char *value_str = xml_element->Attribute (" value" );
621
+ if (value_str) {
622
+ uint64_t v = boost::lexical_cast<uint64_t >(value_str);
623
+ if (values.empty () || v > values.back ()) {
624
+ values.push_back (v);
625
+ }
626
+ } else {
627
+ // FAST 1.2 specification does not require a value attribute
628
+ if (values.empty ())
629
+ values.push_back (0 );
630
+ else
631
+ values.push_back (values.back () + 1 );
632
+ }
633
+ }
634
+ }
635
+
636
+ if (values.size () != names.size ()) {
637
+ throw std::runtime_error (" Invalid value specification for enum elements" );
638
+ }
639
+
640
+ num_elements = names.size ();
641
+ enum_element_names = static_cast <const char **>(
642
+ alloc ().allocate (names.size () * sizeof (const char *)));
643
+ std::copy (names.begin (), names.end (), enum_element_names);
644
+
645
+ if (values.size ()) {
646
+ uint64_t *values_array = static_cast <uint64_t *>(
647
+ alloc ().allocate (values.size () * sizeof (uint64_t )));
648
+ std::copy (values.begin (), values.end (), values_array);
649
+ enum_element_values = values_array;
650
+ }
651
+ } else if (init_value_str) {
652
+ // In this case, the element names are already defined, but we haven't
653
+ // decide what the specified
654
+ // initial value is.
655
+
656
+ uint64_t init_value;
657
+ if (parse_enum_value (enum_element_names, enum_element_values, num_elements,
658
+ init_value_str, init_value)) {
659
+ fop.initial_value_ =
660
+ value_storage (0 ); // reset the storage to defined value
661
+ fop.initial_value_ .set <uint64_t >(init_value);
662
+ } else {
663
+ BOOST_THROW_EXCEPTION (
664
+ fast_static_error (" Unrecognized enum initial value : " )
665
+ << value_info (init_value_str));
666
+ }
667
+ }
668
+
669
+ if (!fop.initial_value_ .is_defined ()) {
670
+ if (fop.initial_value_ .get <const char *>() != nullptr ) {
671
+ std::string msg = " Invalid initial value for enum : " ;
672
+ throw std::runtime_error (msg + init_value_str);
673
+ } else {
674
+ // at this point if initial_value_ is still undefined, we should reset it
675
+ // to zero
676
+ fop.initial_value_ .set <uint64_t >(0 );
677
+ }
678
+ }
679
+
680
+ auto instruction = new (alloc ()) enum_field_instruction (
681
+ fop.op_ , get_presence (inst), get_id (inst), get_name (alloc ()),
682
+ get_ns (inst, alloc ()), fop.context_ ,
683
+ int_value_storage<uint64_t >(fop.initial_value_ ), enum_element_names,
684
+ enum_element_values, num_elements,
685
+ inst->elements_ == nullptr ? nullptr : inst, inst->cpp_ns (),
686
+ parse_tag (inst));
687
+
688
+ parent_->add_instruction (instruction);
689
+ }
690
+ #else
550
691
void field_builder::visit (const enum_field_instruction *inst, void *) {
551
692
552
693
const XMLElement *element = &this ->element_ ;
@@ -647,6 +788,7 @@ void field_builder::visit(const enum_field_instruction *inst, void *) {
647
788
648
789
parent_->add_instruction (instruction);
649
790
}
791
+ #endif
650
792
651
793
instruction_tag field_builder::parse_tag (const field_instruction *inst) {
652
794
uint64_t value = inst->tag ().to_uint64 ();
0 commit comments