99#include < boost/tokenizer.hpp>
1010#include " mfast/field_instructions.h"
1111
12+ #ifdef XETRA_FAST_SPECIFICATION
13+ #include < boost/optional.hpp>
14+ #endif
15+
1216using namespace tinyxml2 ;
1317
1418namespace mfast {
@@ -520,6 +524,31 @@ void field_builder::add_template(const char *, template_instruction *inst) {
520524 << referenced_by_info (parent_->name ()));
521525}
522526
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
523552bool parse_enum_value (const char **enum_element_names,
524553 const uint64_t *enum_element_values,
525554 uint64_t num_elements, const char *value_name,
@@ -537,6 +566,7 @@ bool parse_enum_value(const char **enum_element_names,
537566
538567 return false ;
539568}
569+ #endif
540570
541571bool parse_enum_value (const enum_field_instruction *inst,
542572 const char *value_name, uint64_t &result) {
@@ -547,6 +577,117 @@ bool parse_enum_value(const enum_field_instruction *inst,
547577struct tag_value ;
548578typedef boost::error_info<tag_value, std::string> value_info;
549579
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
550691void field_builder::visit (const enum_field_instruction *inst, void *) {
551692
552693 const XMLElement *element = &this ->element_ ;
@@ -647,6 +788,7 @@ void field_builder::visit(const enum_field_instruction *inst, void *) {
647788
648789 parent_->add_instruction (instruction);
649790}
791+ #endif
650792
651793instruction_tag field_builder::parse_tag (const field_instruction *inst) {
652794 uint64_t value = inst->tag ().to_uint64 ();
0 commit comments