Skip to content

Commit 571d22e

Browse files
committed
Add Xetra enum case
1 parent cbad7d6 commit 571d22e

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

src/mfast/xml_parser/field_builder.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
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+
1216
using namespace tinyxml2;
1317

1418
namespace 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
523552
bool 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

541571
bool 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,
547577
struct tag_value;
548578
typedef 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
550691
void 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

651793
instruction_tag field_builder::parse_tag(const field_instruction *inst) {
652794
uint64_t value = inst->tag().to_uint64();

0 commit comments

Comments
 (0)