diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cf167187..2227ea86 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,8 +16,14 @@ jobs: run: curl -L https://archives.boost.io/release/1.72.0/source/boost_1_72_0.tar.gz | tar zx shell: bash - name: configure - run: cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DXETRA_FAST_SPECIFICATION=ON + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON + - name: configure xetra + run: cmake -B ${{github.workspace}}/build-xetra -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DXETRA_FAST_SPECIFICATION=ON - name: build - run: cmake --build build --parallel 2 + run: cmake --build ${{github.workspace}}/build --parallel 2 + - name: build xetra + run: cmake --build ${{github.workspace}}/build-xetra --parallel 2 - name: test - run: cd build && ctest -VV \ No newline at end of file + run: cd ${{github.workspace}}/build && ctest -VV + - name: test xetra + run: cd ${{github.workspace}}/build-xetra && ctest -VV diff --git a/examples/message_printer/message_printer.h b/examples/message_printer/message_printer.h index 4b82122a..7e5d84ce 100644 --- a/examples/message_printer/message_printer.h +++ b/examples/message_printer/message_printer.h @@ -3,6 +3,7 @@ #include #include #include +#include using namespace mfast; @@ -130,5 +131,10 @@ class message_printer } --indent_; } + + void visit(const set_cref& ref) + { + os_ << "0b" << std::bitset<16>{ref.value()}; + } }; diff --git a/src/fast_type_gen/CMakeLists.txt b/src/fast_type_gen/CMakeLists.txt index c6afee98..359b958a 100644 --- a/src/fast_type_gen/CMakeLists.txt +++ b/src/fast_type_gen/CMakeLists.txt @@ -10,6 +10,10 @@ else() add_executable (fast_type_gen) target_sources(fast_type_gen PRIVATE ${headers} ${sources}) + if(XETRA_FAST_SPECIFICATION) + target_compile_definitions(fast_type_gen PRIVATE XETRA_FAST_SPECIFICATION) + endif(XETRA_FAST_SPECIFICATION) + target_link_libraries (fast_type_gen PRIVATE mfast_xml_parser_static mfast_static diff --git a/src/fast_type_gen/codegen_base.cpp b/src/fast_type_gen/codegen_base.cpp index 23ce5eea..481031c8 100644 --- a/src/fast_type_gen/codegen_base.cpp +++ b/src/fast_type_gen/codegen_base.cpp @@ -216,6 +216,20 @@ class type_name_finder : public field_instruction_visitor { dependency_->insert(inst->cpp_ns()); } } + + virtual void visit(const set_field_instruction *inst, + void *pIndex) override { + if (inst->ref_instruction()) { + inst->ref_instruction()->accept(*this, pIndex); + } else if (inst->cpp_ns() == nullptr || inst->cpp_ns()[0] == 0 || + strcmp(caller_cpp_ns_, inst->cpp_ns()) == 0) { + name_ = inst->name(); + } else { + name_ = std::string(inst->cpp_ns()) + "::" + inst->name(); + if (dependency_) + dependency_->insert(inst->cpp_ns()); + } + } }; std::string codegen_base::cpp_type_of(const mfast::field_instruction *inst, diff --git a/src/fast_type_gen/cpp_gen.cpp b/src/fast_type_gen/cpp_gen.cpp index 4dcbf38e..25710211 100644 --- a/src/fast_type_gen/cpp_gen.cpp +++ b/src/fast_type_gen/cpp_gen.cpp @@ -658,6 +658,71 @@ void cpp_gen::visit(const mfast::enum_field_instruction *inst, void *pIndex) { } } +void cpp_gen::visit(const mfast::set_field_instruction *inst, void *pIndex) +{ + std::string name(cpp_name(inst)); + std::string qualified_name = name; + std::string instruction_variable_name; + std::stringstream elements_variable_name; + std::stringstream num_elements_name; + std::stringstream instruction_type; + if (inst->ref_instruction()) + qualified_name = cpp_type_of(inst); + if (pIndex == nullptr) + { + out_ << "const " << qualified_name << "::instruction_type*\n" << name + << "::instruction()\n" + << "{\n"; + instruction_variable_name = " the_instruction"; + instruction_type << qualified_name << "::instruction_type"; + } + else + { + add_to_instruction_list(name); + instruction_variable_name = prefix_string() + name + "_instruction"; + instruction_type << cref_scope() << name << "_cref::instruction_type"; + } + if (inst->ref_instruction()) + { + elements_variable_name << qualified_name << "::instruction()->elements()"; + num_elements_name << qualified_name << "::instruction()->num_elements()"; + instruction_type.str(qualified_name + "::instruction_type"); + } + else + { + elements_variable_name << "elements"; + num_elements_name << inst->num_elements(); + out_ << "static const char* elements[] = {\n"; + for (auto i = 0ul; i < inst->num_elements(); ++i) + { + if (i != 0) + out_ << ",\n"; + out_ << " \"" << inst->elements()[i] << "\""; + } + out_ << "};\n"; + } + std::string context = gen_op_context(inst->name(), inst->op_context()); + out_ << "const static " << instruction_type.str() << "\n" + << instruction_variable_name << "(\n" + << " " << get_operator_name(inst) << ",\n" + << " " << get_presence(inst) << ",\n" + << " " << inst->id() << ", // id\n" + << " \"" << inst->name() << "\", // name\n" + << " \"" << inst->ns() << "\", // ns\n" + << " " << context << ", // opContext\n" + << " int_value_storage(" + << inst->initial_value().get() << "), // initial_value\n" + << " " << elements_variable_name.str() << ", // element names\n" + << " " << num_elements_name.str() << ",// num elements\n" + << " nullptr, // ref_instruction\n" + << " nullptr, // cpp_ns\n" + << " " << inst->tag() << "); // tag\n\n"; + if (pIndex == nullptr) { + out_ << " return &the_instruction;\n" + << "}\n\n"; + } +} + void cpp_gen::generate(const mfast::aggregate_view_info &info) { std::string my_name = cpp_name(info.name_); diff --git a/src/fast_type_gen/cpp_gen.h b/src/fast_type_gen/cpp_gen.h index 00827f31..84ccc79e 100644 --- a/src/fast_type_gen/cpp_gen.h +++ b/src/fast_type_gen/cpp_gen.h @@ -38,6 +38,7 @@ class cpp_gen : public codegen_base { virtual void visit(const mfast::uint64_vector_field_instruction *, void *) override; virtual void visit(const mfast::enum_field_instruction *, void *) override; + virtual void visit(const mfast::set_field_instruction *, void *) override; private: virtual void generate(const mfast::aggregate_view_info &info); diff --git a/src/fast_type_gen/hpp_gen.cpp b/src/fast_type_gen/hpp_gen.cpp index fcb5ba14..362e795d 100644 --- a/src/fast_type_gen/hpp_gen.cpp +++ b/src/fast_type_gen/hpp_gen.cpp @@ -672,6 +672,88 @@ void hpp_gen::visit(const mfast::enum_field_instruction *inst, void *pIndex) { } } +void hpp_gen::visit(const mfast::set_field_instruction *inst, void *pIndex) +{ + std::string name(cpp_name(inst)); + if (inst->ref_instruction() == nullptr) + { + header_cref_ << indent << "struct " << export_symbol_uppercase_ << name + << "\n" << indent << "{\n" << indent << " enum element {\n"; + for (auto i = 0ul; i < inst->num_elements(); ++i) + { + header_cref_ << indent << " " << cpp_name(inst->elements()[i]); + if (i == 0) + header_cref_ << " = 1"; + else + header_cref_ << " = 1 << " << i; + if (i + 1 < inst->num_elements()) + header_cref_ << ",\n"; + } + header_cref_ << "\n" << indent << " };\n" << indent + << " using instruction_type = " + << "mfast::set_field_instruction_ex<" + << name << ">;\n" << indent + << " static const instruction_type* instruction();\n" + << indent << "};\n\n"; + header_cref_ << indent << "class " << name << "_cref\n" << indent + << " : public mfast::set_cref_ex<" << name << "_cref, " + << name << ">\n" << indent << "{\n" << indent << " public:\n" + << indent << " using base_type = mfast::set_cref_ex<" + << name << "_cref, " << name << ">;\n" << indent + << " using element_type = " << name << "::element;\n" + << indent << " using instruction_type = " << name + << "::instruction_type;\n" << indent << " " + << name << "_cref(\n" << indent + << " const mfast::value_storage* storage=nullptr,\n" << indent + << " instruction_cptr instruction=nullptr);\n\n" + << indent << " explicit " << name + << "_cref(const field_cref& other);\n\n" << indent + << " element_type value() const;\n\n"; + for (auto i = 0ul; i < inst->num_elements_; ++i) + { + std::string element_name = cpp_name(inst->elements_[i]); + header_cref_ << indent << " bool has_" << element_name << "() const;\n"; + } + header_cref_ << indent << "};\n\n"; + header_mref_ << indent << "class " << name << "_mref\n" << indent + << " : public mfast::set_mref_ex<" << name << "_mref, " + << name << "_cref>\n" << indent << "{\n" << indent + << " public:\n" << indent + << " using base_type = mfast::set_mref_ex<" << name + << "_mref, " << name << "_cref>;\n" << indent + << " using element_type = " << name << "::element;\n" + << indent << " " << name << "_mref(\n" << indent + << " mfast::allocator* alloc=nullptr,\n" << indent + << " mfast::value_storage* storage=nullptr,\n" << indent + << " instruction_cptr instruction=nullptr);\n" + << indent << " explicit " << name + << "_mref(const mfast::field_mref_base& other);\n\n"; + for (auto i = 0ul; i < inst->num_elements_; ++i) + { + std::string element_name = cpp_name(inst->elements_[i]); + header_mref_ << indent << " void set_" << element_name << "() const;\n"; + header_mref_ << indent << " void unset_" << element_name << "() const;\n"; + } + header_mref_ << indent << "};\n\n"; + } + if (pIndex) { + std::string ret_type = cpp_type_of(inst, &dependency_); + header_cref_ << indent << ret_type << "_cref get_" << name << "() const;\n"; + header_cref_ << indent << ret_type << "_cref try_get_" << name << "() const;\n"; + if (inst->field_operator() != mfast::operator_constant) + header_mref_ << indent << ret_type << "_mref set_" << name << "() const;\n"; + if (inst->optional()) { + header_mref_ << indent << "void omit_" << name << "() const;\n"; + } + } else { + content_ << header_cref_.str() << header_mref_.str(); + header_cref_.clear(); + header_cref_.str(""); + header_mref_.clear(); + header_mref_.str(""); + } +} + void hpp_gen::generate(const mfast::aggregate_view_info &info) { std::string ns_prefix; std::string my_name = cpp_name(info.name_); diff --git a/src/fast_type_gen/hpp_gen.h b/src/fast_type_gen/hpp_gen.h index e637acbb..056da0b4 100644 --- a/src/fast_type_gen/hpp_gen.h +++ b/src/fast_type_gen/hpp_gen.h @@ -40,6 +40,7 @@ class hpp_gen : public codegen_base { virtual void visit(const mfast::template_instruction *, void *) override; virtual void visit(const mfast::templateref_instruction *, void *) override; virtual void visit(const mfast::enum_field_instruction *, void *) override; + virtual void visit(const mfast::set_field_instruction *, void *) override; private: void gen_primitive(const char *cpp_type, diff --git a/src/fast_type_gen/inl_gen.cpp b/src/fast_type_gen/inl_gen.cpp index c19f19d1..6278598e 100644 --- a/src/fast_type_gen/inl_gen.cpp +++ b/src/fast_type_gen/inl_gen.cpp @@ -127,6 +127,11 @@ struct ext_cref_type_getter : mfast::field_instruction_visitor { out_ << "ext_cref"; } + + virtual void visit(const set_field_instruction *inst, void *) override { + out_ << "ext_cref"; + } }; std::string get_ext_cref_type(const field_instruction *inst) { @@ -260,6 +265,11 @@ struct ext_mref_type_getter : mfast::field_instruction_visitor { out_ << "ext_mref"; } + + virtual void visit(const set_field_instruction *inst, void *) override { + out_ << "ext_mref"; + } }; std::string get_ext_mref_type(const field_instruction *inst) { @@ -1045,6 +1055,76 @@ void inl_gen::visit(const mfast::enum_field_instruction *inst, void *pIndex) { gen_accessors(inst, name, cref_type_name, mref_type_name, pIndex); } +void inl_gen::visit(const mfast::set_field_instruction *inst, void *pIndex) +{ + std::string name(cpp_name(inst)); + std::string cref_type_name = cref_scope_.str() + name + "_cref"; + std::string mref_type_name = mref_scope_.str() + name + "_mref"; + if (inst->ref_instruction() == nullptr) + { + out_ << "inline\n" << cref_type_name << "::" << name << "_cref(\n" + << " const mfast::value_storage* storage,\n" + << " " << cref_type_name << "::instruction_cptr instruction)\n" + << " : base_type(storage, instruction)\n" + << "{\n" + << "}\n\n" + << "inline\n" << cref_type_name << "::" << name << "_cref(\n" + << " const mfast::field_cref& other)\n" + << " : base_type(other)\n" + << "{\n" + << "}\n\n" + << "inline\n" << mref_type_name << "::" << name << "_mref(\n" + << " mfast::allocator* alloc,\n" + << " mfast::value_storage* storage,\n" + << " " << mref_type_name << "::instruction_cptr instruction)\n" + << " : base_type(alloc, storage, instruction)\n" + << "{\n" + << "}\n\n" + << "inline\n" << mref_type_name << "::" << name << "_mref(\n" + << " const mfast::field_mref_base& other)\n" + << " : base_type(other)\n" + << "{\n" + << "}\n\n" + << "inline\n" << cref_type_name << "::element_type\n" << cref_type_name + << "::value() const\n" + << "{\n" + << " return static_cast<" << name + << "::element>(base_type::value());\n" + << "}\n\n"; + for (auto i = 0ul; i < inst->num_elements_; ++i) + { + std::string element_name = cpp_name(inst->elements_[i]); + out_ << "inline\n" + << "bool " << cref_type_name << "::has_" << element_name + << "() const\n" + << "{\n" + << " return this->value() & " << name << "::" << element_name + << ";\n" + << "}\n\n" + << "inline\n" + << "void " << mref_type_name << "::set_" << element_name + << "() const\n" + << "{\n" + << " auto tmp = this->value() | " + << name << "::" << element_name << ";\n" + << " return this->as(static_cast(tmp));\n" + << "}\n\n" + << "inline\n" + << "void " << mref_type_name << "::unset_" << element_name + << "() const\n" + << "{\n" + << " auto tmp = this->value() & ~" + << name << "::" << element_name << ";\n" + << " return this->as(static_cast(tmp));\n" + << "}\n\n"; + } + } + std::string ret_type = cpp_type_of(inst, nullptr); + auto ret_cref = ret_type + "_cref"; + auto ret_mref = ret_type + "_mref"; + gen_accessors(inst, name, ret_cref, ret_mref, pIndex); +} + void inl_gen::gen_accessors(const mfast::field_instruction *inst, const std::string &name, const std::string &cref_type_name, diff --git a/src/fast_type_gen/inl_gen.h b/src/fast_type_gen/inl_gen.h index ec850cc7..6505d30c 100644 --- a/src/fast_type_gen/inl_gen.h +++ b/src/fast_type_gen/inl_gen.h @@ -35,6 +35,7 @@ class inl_gen : public codegen_base { virtual void visit(const mfast::template_instruction *, void *) override; virtual void visit(const mfast::templateref_instruction *, void *) override; virtual void visit(const mfast::enum_field_instruction *, void *) override; + virtual void visit(const mfast::set_field_instruction *, void *) override; private: virtual void traverse(const mfast::group_field_instruction *inst, diff --git a/src/mfast/coder/common/dictionary_builder.cpp b/src/mfast/coder/common/dictionary_builder.cpp index 64159e2a..76125c78 100644 --- a/src/mfast/coder/common/dictionary_builder.cpp +++ b/src/mfast/coder/common/dictionary_builder.cpp @@ -385,4 +385,13 @@ void dictionary_builder::visit(const enum_field_instruction *src_inst, get_dictionary_storage(dest->name(), dest->ns(), dest->op_context_, field_type_uint64, &dest->prev_storage_, dest); } + +void dictionary_builder::visit(const set_field_instruction *src_inst, + void *dest_inst) { + auto& dest = *static_cast(dest_inst); + dest = src_inst->clone(alloc_); + dest->prev_value_ = + get_dictionary_storage(dest->name(), dest->ns(), dest->op_context_, + field_type_uint64, &dest->prev_storage_, dest); +} } diff --git a/src/mfast/coder/common/dictionary_builder.h b/src/mfast/coder/common/dictionary_builder.h index 9f8f9ffb..6b013343 100644 --- a/src/mfast/coder/common/dictionary_builder.h +++ b/src/mfast/coder/common/dictionary_builder.h @@ -120,6 +120,7 @@ class MFAST_CODER_EXPORT dictionary_builder virtual void visit(const templateref_instruction *, void *) override; virtual void visit(const enum_field_instruction *, void *) override; + virtual void visit(const set_field_instruction *, void *) override; template_instruction *clone_instruction(const template_instruction *); diff --git a/src/mfast/coder/decoder/fast_decoder.cpp b/src/mfast/coder/decoder/fast_decoder.cpp index d757e059..e08a3338 100644 --- a/src/mfast/coder/decoder/fast_decoder.cpp +++ b/src/mfast/coder/decoder/fast_decoder.cpp @@ -51,6 +51,10 @@ struct fast_decoder_impl { this->visit(reinterpret_cast(mref)); } + void visit(set_mref &mref) { + this->visit(reinterpret_cast(mref)); + } + template void visit(const SimpleMRef &mref); template void visit(const int_vector_mref &mref); diff --git a/src/mfast/coder/encoder/fast_encoder.cpp b/src/mfast/coder/encoder/fast_encoder.cpp index d5a5dfcd..1b35666a 100644 --- a/src/mfast/coder/encoder/fast_encoder.cpp +++ b/src/mfast/coder/encoder/fast_encoder.cpp @@ -54,6 +54,11 @@ struct fast_encoder_impl : simple_template_repo_t { this->visit(tmp); } + void visit(set_cref cref) { + uint64_cref tmp{cref}; + this->visit(tmp); + } + template void visit(SimpleCRef cref); template void visit(int_vector_cref cref); diff --git a/src/mfast/field_instructions.cpp b/src/mfast/field_instructions.cpp index b1a19cd7..4cbd1147 100644 --- a/src/mfast/field_instructions.cpp +++ b/src/mfast/field_instructions.cpp @@ -51,4 +51,9 @@ void templateref_instruction::accept(field_instruction_visitor &visitor, void *context) const { visitor.visit(this, context); } + +void set_field_instruction::accept(field_instruction_visitor &visitor, + void *context) const { + return visitor.visit(this, context); +} } diff --git a/src/mfast/field_instructions.h b/src/mfast/field_instructions.h index 29f8c723..a9e7373c 100644 --- a/src/mfast/field_instructions.h +++ b/src/mfast/field_instructions.h @@ -22,6 +22,7 @@ #include "instructions/template_instruction.h" #include "instructions/templateref_instruction.h" #include "instructions/templates_description.h" +#include "instructions/set_instruction.h" namespace mfast { class MFAST_EXPORT field_instruction_visitor { @@ -45,6 +46,7 @@ class MFAST_EXPORT field_instruction_visitor { virtual void visit(const uint64_vector_field_instruction *, void *) = 0; virtual void visit(const enum_field_instruction *inst, void *data) = 0; + virtual void visit(const set_field_instruction *inst, void *data) = 0; }; /////////////////////////////////////////////////////////////////////////////////// diff --git a/src/mfast/field_visitor.h b/src/mfast/field_visitor.h index f4a92967..c5cb5668 100644 --- a/src/mfast/field_visitor.h +++ b/src/mfast/field_visitor.h @@ -13,6 +13,8 @@ #include "sequence_ref.h" #include "message_ref.h" #include "nested_message_ref.h" +#include "set_ref.h" + namespace mfast { namespace detail { template struct result_holder { @@ -152,6 +154,12 @@ class field_accessor_adaptor : public field_instruction_visitor, this->apply_visitor(accessor_, ref); } + virtual void visit(const set_field_instruction *inst, + void *storage) override { + set_cref ref(static_cast(storage), inst); + this->apply_visitor(accessor_, ref); + } + using result_holder::get_result; }; @@ -270,6 +278,12 @@ class field_mutator_adaptor : public field_instruction_visitor, this->apply_visitor(mutator_, ref); } + virtual void visit(const set_field_instruction *inst, + void *storage) override { + set_mref ref(alloc_, static_cast(storage), inst); + this->apply_visitor(mutator_, ref); + } + using result_holder::get_result; }; diff --git a/src/mfast/instructions/field_instruction.cpp b/src/mfast/instructions/field_instruction.cpp index a0804557..37dcf05c 100644 --- a/src/mfast/instructions/field_instruction.cpp +++ b/src/mfast/instructions/field_instruction.cpp @@ -37,7 +37,9 @@ const char *field_instruction::field_type_name() const { "field_type_templateref", "field_type_ascii_string", "field_type_unicode_string", "field_type_byte_vector", "field_type_group", "field_type_sequence", - "field_type_template", "field_type_enum"}; + "field_type_template", "field_type_enum", + "field_type_set", + }; return names[this->field_type()]; } diff --git a/src/mfast/instructions/field_instruction.h b/src/mfast/instructions/field_instruction.h index 67aef59c..8d0cd26c 100644 --- a/src/mfast/instructions/field_instruction.h +++ b/src/mfast/instructions/field_instruction.h @@ -47,7 +47,8 @@ enum field_type_enum_t { field_type_sequence, // using of_array end, codegen needed start field_type_group, field_type_template, - field_type_enum + field_type_enum, + field_type_set, }; enum property_enum_t { diff --git a/src/mfast/instructions/set_instruction.cpp b/src/mfast/instructions/set_instruction.cpp new file mode 100644 index 00000000..e271d0ac --- /dev/null +++ b/src/mfast/instructions/set_instruction.cpp @@ -0,0 +1,16 @@ +// Copyright (c) 2016, Huang-Ming Huang, Object Computing, Inc. +// All rights reserved. +// +// This file is part of mFAST. +// See the file license.txt for licensing information. + +#include "set_instruction.h" + +namespace mfast { + +set_field_instruction * +set_field_instruction::clone(arena_allocator &alloc) const { + return new (alloc) set_field_instruction(*this); +} + +} /* mfast */ diff --git a/src/mfast/instructions/set_instruction.h b/src/mfast/instructions/set_instruction.h new file mode 100644 index 00000000..f74c5a71 --- /dev/null +++ b/src/mfast/instructions/set_instruction.h @@ -0,0 +1,45 @@ +// Copyright (c) 2016, Huang-Ming Huang, Object Computing, Inc. +// All rights reserved. +// +// This file is part of mFAST. +// See the file license.txt for licensing information. + +#pragma once + +#include "int_instructions.h" + +namespace mfast { + + class MFAST_EXPORT set_field_instruction + : public integer_field_instruction_base, + public referable_instruction { + public: + set_field_instruction(operator_enum_t operator_id, presence_enum_t optional, + uint32_t id, const char *name, const char *ns, + const op_context_t *context, + int_value_storage initial_value, + const char **elements, uint64_t num_elements, + const set_field_instruction *ref, const char *cpp_ns, + instruction_tag tag = instruction_tag()) : + integer_field_instruction_base(operator_id, field_type_set, optional, + id, name, ns, context, + initial_value.storage_, tag), + referable_instruction(ref, cpp_ns), + elements_(elements), num_elements_(num_elements) {} + + set_field_instruction(const set_field_instruction &other) : + integer_field_instruction_base(other), + referable_instruction(other), + elements_(other.elements_), num_elements_(other.num_elements_) {} + + virtual void accept(field_instruction_visitor &visitor, + void *context) const override; + virtual set_field_instruction *clone(arena_allocator &alloc) const override; + + uint64_t num_elements() const { return num_elements_; } + const char **elements() const { return elements_; } + const char **elements_; + uint64_t num_elements_; + }; + +} /* mfast */ diff --git a/src/mfast/set_ref.h b/src/mfast/set_ref.h new file mode 100644 index 00000000..c72e1ff1 --- /dev/null +++ b/src/mfast/set_ref.h @@ -0,0 +1,198 @@ +// Copyright (c) 2016, Huang-Ming Huang, Object Computing, Inc. +// All rights reserved. +// +// This file is part of mFAST. +// See the file license.txt for licensing information. +#pragma once + +#include "mfast/field_instructions.h" +#include "mfast/field_ref.h" +#include "mfast/type_category.h" + +namespace mfast +{ +namespace detail { + class codec_helper; +} + + class set_cref : public field_cref + { + public: + using value_type = uint_fast32_t; + using instruction_type = set_field_instruction; + using instruction_cptr = const instruction_type*; + using type_category = integer_type_tag; + + set_cref() = default; + set_cref(const value_storage *storage, instruction_cptr instruction) : + field_cref(storage, instruction) {} + set_cref(const set_cref &other) = default; + set_cref& operator=(const set_cref&) = delete; + explicit set_cref(const field_cref &other) : field_cref(other) {} + + uint32_t id() const { return instruction_->id(); } + bool is_initial_value() const + { + const auto init_val = this->instruction()->initial_value(); + return + this->absent() == init_val.is_empty() && + (this->absent() || value() == init_val.get()); + } + + value_type value() const { return storage_->get(); } + + instruction_cptr instruction() const + { + return static_cast(instruction_); + } + + protected: + friend class mfast::detail::codec_helper; + void save_to(value_storage &v) const + { + v.of_uint64.content_ = this->storage()->of_uint64.content_; + v.defined(true); + v.present(this->present()); + } + }; + + + inline bool operator==(const set_cref &lhs, const set_cref &rhs) + { + return (lhs.absent() == rhs.absent()) && + (lhs.absent() || lhs.value() == rhs.value()); + } + + inline bool operator!=(const set_cref &lhs, const set_cref &rhs) + { + return !(lhs == rhs); + } + class fast_istream; + + + class set_mref : public make_field_mref + { + using base_type = make_field_mref; + + public: + set_mref() = default; + set_mref(mfast::allocator *alloc, value_storage *storage, + instruction_cptr instruction) : + base_type(alloc, storage, instruction) {} + set_mref(const set_mref&) = default; + set_mref& operator=(const set_mref&) = delete; + explicit set_mref(const field_mref_base &other) : base_type(other) {} + + void as(const set_cref &cref) const + { + if (cref.absent()) + this->omit(); + else + as(cref.value()); + } + + void as(value_type v) const + { + this->storage()->present(1); + this->storage()->set(v); + } + + void to_initial_value() const + { + *this->storage() = this->instruction()->initial_value(); + } + value_type value() const { return this->storage()->get(); } + + protected: + friend class mfast::detail::codec_helper; + void copy_from(value_storage v) const { *this->storage() = v; } + }; + + template <> struct mref_of { using type = set_mref; }; + + + template + class set_field_instruction_ex : public set_field_instruction + { + public: + set_field_instruction_ex( + operator_enum_t operator_id, presence_enum_t optional, uint32_t id, + const char *name, const char *ns, const op_context_t *context, + int_value_storage initial_value, const char **element_names, + uint64_t num_elements, const set_field_instruction *ref, + const char *cpp_ns, instruction_tag tag = instruction_tag()) : + set_field_instruction(operator_id, optional, id, name, ns, context, + initial_value, element_names, num_elements, ref, + cpp_ns, tag) {} + }; + + + template + class set_cref_ex : public set_cref + { + public: + using element_type = typename SetClassType::element; + using instruction_type = typename SetClassType::instruction_type; + using intruction_cptr = const instruction_type*; + + set_cref_ex(const value_storage *storage, + const set_field_instruction *instruction) : + set_cref(storage, instruction) {} + + set_cref_ex(const field_cref &other) : set_cref(other) {} + bool operator==(const Derived &v) const { return this->value() == v.value(); } + bool operator==(element_type v) const { return this->value() == v; } + bool operator!=(const Derived &v) const { return !(*this == v); } + bool operator!=(element_type v) const { return !(*this == v); } + element_type value() const + { + return static_cast(set_cref::value()); + } + intruction_cptr instruction() const + { + return static_cast(instruction_); + } + }; + + + template + class set_mref_ex : public make_field_mref + { + using base_type = make_field_mref; + + public: + using cref_type = CRefType; + using element_type = typename CRefType::element_type; + + set_mref_ex(mfast::allocator *alloc, value_storage *storage, + const set_field_instruction *instruction) : + base_type(alloc, storage, instruction) {} + + set_mref_ex(const field_mref_base &other) : base_type(other) {} + + operator set_mref() const + { + return reinterpret_cast(*this); + } + + void as(const cref_type& ref) const + { + if (ref.absent()) + this->omit(); + else + as(ref.value()); + } + + void as(element_type v) const + { + this->storage()->present(1); + this->storage()->template set(v); + } + + void to_initial_value() const + { + *this->storage() = this->instruction()->initial_value(); + } + }; + +} diff --git a/src/mfast/sqlite3/CMakeLists.txt b/src/mfast/sqlite3/CMakeLists.txt index 3f6a938f..88c4acdf 100644 --- a/src/mfast/sqlite3/CMakeLists.txt +++ b/src/mfast/sqlite3/CMakeLists.txt @@ -13,6 +13,10 @@ if (UNIX) set_target_properties(mfast_sqlite3_static PROPERTIES OUTPUT_NAME mfast_sqlite3) endif() +if(XETRA_FAST_SPECIFICATION) + target_compile_definitions(mfast_sqlite3_static PRIVATE XETRA_FAST_SPECIFICATION) +endif(XETRA_FAST_SPECIFICATION) + install(TARGETS mfast_sqlite3_static EXPORT mFASTTargets FILE_SET HEADERS @@ -27,6 +31,10 @@ if (BUILD_SHARED_LIBS) set_property(TARGET mfast_sqlite3 PROPERTY VERSION ${MFAST_VERSION}) set_property(TARGET mfast_sqlite3 PROPERTY SOVERSION ${MFAST_VERSION}) + if(XETRA_FAST_SPECIFICATION) + target_compile_definitions(mfast_sqlite3 PRIVATE XETRA_FAST_SPECIFICATION) + endif(XETRA_FAST_SPECIFICATION) + install(TARGETS mfast_sqlite3 EXPORT mFASTTargets FILE_SET HEADERS diff --git a/src/mfast/sqlite3/field_instruction_visitor_ex.cpp b/src/mfast/sqlite3/field_instruction_visitor_ex.cpp index 6bf3ec20..3e334879 100644 --- a/src/mfast/sqlite3/field_instruction_visitor_ex.cpp +++ b/src/mfast/sqlite3/field_instruction_visitor_ex.cpp @@ -31,6 +31,11 @@ void field_instruction_visitor_ex::visit(const enum_field_instruction *inst, this->visit(static_cast(inst), data); } +void field_instruction_visitor_ex::visit(const set_field_instruction *inst, + void *data) { + this->visit(static_cast(inst), data); +} + void field_instruction_visitor_ex::visit(const unicode_field_instruction *inst, void *data) { this->visit(static_cast(inst), data); diff --git a/src/mfast/sqlite3/field_instruction_visitor_ex.h b/src/mfast/sqlite3/field_instruction_visitor_ex.h index 6e3eb710..9ed5884b 100644 --- a/src/mfast/sqlite3/field_instruction_visitor_ex.h +++ b/src/mfast/sqlite3/field_instruction_visitor_ex.h @@ -15,6 +15,7 @@ class field_instruction_visitor_ex : public field_instruction_visitor { virtual void visit(const uint64_field_instruction *, void *); virtual void visit(const decimal_field_instruction *, void *); virtual void visit(const enum_field_instruction *inst, void *data); + virtual void visit(const set_field_instruction *inst, void *data); virtual void visit(const ascii_field_instruction *, void *) = 0; virtual void visit(const unicode_field_instruction *, void *); diff --git a/src/mfast/sqlite3/tables_creator.cpp b/src/mfast/sqlite3/tables_creator.cpp index b88577f0..1138c282 100644 --- a/src/mfast/sqlite3/tables_creator.cpp +++ b/src/mfast/sqlite3/tables_creator.cpp @@ -323,6 +323,12 @@ void tables_creator::visit(const enum_field_instruction *inst, void *) { num_columns_++; } +void tables_creator::visit(const set_field_instruction *inst, void *) { + create_current_ << " " << inst->name() << " INT,\n"; + parameters_.push_back(inst->name()); + num_columns_++; +} + std::string tables_creator::create_statements() { return create_prefix_.str() + create_current_.str() + create_postfix_.str(); } diff --git a/src/mfast/sqlite3/tables_creator.h b/src/mfast/sqlite3/tables_creator.h index f72ccbc6..5be06553 100644 --- a/src/mfast/sqlite3/tables_creator.h +++ b/src/mfast/sqlite3/tables_creator.h @@ -50,6 +50,8 @@ class tables_creator : public field_instruction_visitor { virtual void visit(const uint64_vector_field_instruction *, void *); virtual void visit(const enum_field_instruction *, void *); + virtual void visit(const set_field_instruction *, void *); + const char *table_name() const; const char *primary_key_name() const; const char *primary_key_type() const; diff --git a/src/mfast/xml_parser/field_builder.cpp b/src/mfast/xml_parser/field_builder.cpp index 8f7c0e1c..a228b653 100644 --- a/src/mfast/xml_parser/field_builder.cpp +++ b/src/mfast/xml_parser/field_builder.cpp @@ -7,6 +7,7 @@ #include "field_op.h" #include "../exceptions.h" #include +#include #include "mfast/field_instructions.h" using namespace tinyxml2; @@ -520,6 +521,31 @@ void field_builder::add_template(const char *, template_instruction *inst) { << referenced_by_info(parent_->name())); } +#if defined(XETRA_FAST_SPECIFICATION) +bool parse_enum_value(const char **enum_element_names, + const uint64_t *enum_element_values, + uint64_t num_elements, const char *value_name, + uint64_t &result) { + boost::optional value_int; + try { + value_int = std::stoul(value_name); + } catch (...) {} + for (uint64_t i = 0; i < num_elements; ++i) { + // FAST 1.2 does not cleary specify what a default enum value refers to, + // search for a match in either name or value/deduce_value + if (std::strcmp(enum_element_names[i], value_name) == 0 || + (value_int.has_value() && enum_element_values[i] == *value_int)) { + if (enum_element_values) + result = enum_element_values[i]; + else + result = i; + return true; + } + } + + return false; +} +#else bool parse_enum_value(const char **enum_element_names, const uint64_t *enum_element_values, uint64_t num_elements, const char *value_name, @@ -537,6 +563,7 @@ bool parse_enum_value(const char **enum_element_names, return false; } +#endif bool parse_enum_value(const enum_field_instruction *inst, const char *value_name, uint64_t &result) { @@ -547,6 +574,117 @@ bool parse_enum_value(const enum_field_instruction *inst, struct tag_value; typedef boost::error_info value_info; + +#if defined(XETRA_FAST_SPECIFICATION) +void field_builder::visit(const enum_field_instruction *inst, void *) { + + const XMLElement *element = &this->element_; + if (!field_op::find_field_op_element(*element)) + element = content_element_; + field_op fop(inst, element, alloc()); + + const char **enum_element_names = inst->elements(); + uint64_t num_elements = inst->num_elements(); + const uint64_t *enum_element_values = inst->element_values(); + + const char *init_value_str = nullptr; + if (!fop.initial_value_.is_defined()) { + // if the defined flag is false, the content value is parsed string from + // XML + init_value_str = fop.initial_value_.get(); + } + + if (enum_element_names == nullptr) { + + std::deque names; + std::deque values; + + const XMLElement *xml_element = + content_element_->FirstChildElement("element"); + for (; xml_element != nullptr; + xml_element = xml_element->NextSiblingElement("element")) { + // Use fancier identifier if available (Eurex style) + const char *name_attr = xml_element->Attribute("id"); + // Otherwise revert to the specified name attribute + if (name_attr == nullptr) + name_attr = xml_element->Attribute("name"); + if (name_attr != nullptr) { + if (init_value_str && std::strcmp(name_attr, init_value_str) == 0) { + fop.initial_value_.set(names.size()); + } + names.push_back(string_dup(name_attr, alloc())); + + const char *value_str = xml_element->Attribute("value"); + if (value_str) { + uint64_t v = boost::lexical_cast(value_str); + if (values.empty() || v > values.back()) { + values.push_back(v); + } + } else { + // FAST 1.2 specification does not require a value attribute + if (values.empty()) + values.push_back(0); + else + values.push_back(values.back() + 1); + } + } + } + + if (values.size() != names.size()) { + throw std::runtime_error("Invalid value specification for enum elements"); + } + + num_elements = names.size(); + enum_element_names = static_cast( + alloc().allocate(names.size() * sizeof(const char *))); + std::copy(names.begin(), names.end(), enum_element_names); + + if (values.size()) { + uint64_t *values_array = static_cast( + alloc().allocate(values.size() * sizeof(uint64_t))); + std::copy(values.begin(), values.end(), values_array); + enum_element_values = values_array; + } + } else if (init_value_str) { + // In this case, the element names are already defined, but we haven't + // decide what the specified + // initial value is. + + uint64_t init_value; + if (parse_enum_value(enum_element_names, enum_element_values, num_elements, + init_value_str, init_value)) { + fop.initial_value_ = + value_storage(0); // reset the storage to defined value + fop.initial_value_.set(init_value); + } else { + BOOST_THROW_EXCEPTION( + fast_static_error("Unrecognized enum initial value : ") + << value_info(init_value_str)); + } + } + + if (!fop.initial_value_.is_defined()) { + if (fop.initial_value_.get() != nullptr) { + std::string msg = "Invalid initial value for enum : "; + throw std::runtime_error(msg + init_value_str); + } else { + // at this point if initial_value_ is still undefined, we should reset it + // to zero + fop.initial_value_.set(0); + } + } + + auto instruction = new (alloc()) enum_field_instruction( + fop.op_, get_presence(inst), get_id(inst), get_name(alloc()), + get_ns(inst, alloc()), fop.context_, + int_value_storage(fop.initial_value_), enum_element_names, + enum_element_values, num_elements, + inst->elements_ == nullptr ? nullptr : inst, inst->cpp_ns(), + parse_tag(inst)); + + parent_->add_instruction(instruction); +} +#else void field_builder::visit(const enum_field_instruction *inst, void *) { const XMLElement *element = &this->element_; @@ -647,6 +785,74 @@ void field_builder::visit(const enum_field_instruction *inst, void *) { parent_->add_instruction(instruction); } +#endif + +void field_builder::visit(const set_field_instruction *inst, void *) +{ + const auto* element = &this->element_; + if (!field_op::find_field_op_element(*element)) + element = content_element_; + field_op fop(inst, element, alloc()); + + const auto** set_element_names = inst->elements(); + auto num_elements = inst->num_elements(); + + const char* init_value_str = nullptr; + if (!fop.initial_value_.is_defined()) + init_value_str = fop.initial_value_.get(); + + if (set_element_names == nullptr) + { + std::deque names; + for (const auto* xml_elt = content_element_->FirstChildElement("element"); + xml_elt != nullptr; + xml_elt = xml_elt->NextSiblingElement("element")) + { + const auto* name_attr = xml_elt->Attribute("id"); + if (name_attr == nullptr) + name_attr = xml_elt->Attribute("name"); + if (name_attr != nullptr) + { + if (init_value_str && std::strcmp(name_attr, init_value_str) == 0) + fop.initial_value_.set(1 << names.size()); + names.push_back(string_dup(name_attr, alloc())); + } + } + num_elements = names.size(); + set_element_names = static_cast + (alloc().allocate(names.size() * sizeof(const char*))); + std::copy(names.begin(), names.end(), set_element_names); + } + else + if (init_value_str) + { + boost::optional value_int; + try + { + value_int = std::stoul(init_value_str); + } catch (...) {} + if (value_int) + fop.initial_value_.set(*value_int); + else + { + for (auto i = 0ul; i < num_elements; ++i) + if (std::strcmp(set_element_names[i], init_value_str) == 0) + { + fop.initial_value_.set(1 << i); + break; + } + } + } + + auto instruction = new (alloc()) set_field_instruction( + fop.op_, get_presence(inst), get_id(inst), get_name(alloc()), + get_ns(inst, alloc()), fop.context_, + int_value_storage(fop.initial_value_), set_element_names, + num_elements, inst->elements_ == nullptr ? nullptr : inst, + inst->cpp_ns(), parse_tag(inst)); + + parent_->add_instruction(instruction); +} instruction_tag field_builder::parse_tag(const field_instruction *inst) { uint64_t value = inst->tag().to_uint64(); diff --git a/src/mfast/xml_parser/field_builder.h b/src/mfast/xml_parser/field_builder.h index 48f17b56..d14e4445 100644 --- a/src/mfast/xml_parser/field_builder.h +++ b/src/mfast/xml_parser/field_builder.h @@ -94,6 +94,7 @@ class field_builder : public fast_xml_attributes, virtual void visit(const uint64_vector_field_instruction *, void *) override; virtual void visit(const enum_field_instruction *, void *) override; + virtual void visit(const set_field_instruction *, void *) override; instructions_view_t build_subfields(); const group_field_instruction *get_sole_templateref(); diff --git a/src/mfast/xml_parser/field_op.h b/src/mfast/xml_parser/field_op.h index 774cae43..e5ff8437 100644 --- a/src/mfast/xml_parser/field_op.h +++ b/src/mfast/xml_parser/field_op.h @@ -24,6 +24,7 @@ typedef int_field_instruction uint64_field_instruction; class ascii_field_instruction; class enum_field_instruction; class byte_vector_field_instruction; +class set_field_instruction; namespace xml_parser { using namespace tinyxml2; @@ -116,6 +117,13 @@ class field_op { initial_value_.of_array.defined_bit_ = 0; } } + void set_init_value(const char *init_value_str, + const set_field_instruction *) { + if (init_value_str) { + initial_value_ = string_value_storage(init_value_str).storage_; + initial_value_.of_array.defined_bit_ = 0; + } + } void set_init_value(const char *init_value_str, const byte_vector_field_instruction *); diff --git a/src/mfast/xml_parser/templates_builder.cpp b/src/mfast/xml_parser/templates_builder.cpp index 6a1ecee0..6f5b923a 100644 --- a/src/mfast/xml_parser/templates_builder.cpp +++ b/src/mfast/xml_parser/templates_builder.cpp @@ -36,7 +36,10 @@ templates_builder::templates_builder(dynamic_templates_description *definition, &length_instruction_prototype, "", "", cpp_ns_), enum_field_instruction_prototype_(operator_none, presence_mandatory, 0, nullptr, "", nullptr, 0, nullptr, - nullptr, 0, nullptr, cpp_ns_) { + nullptr, 0, nullptr, cpp_ns_), + set_field_instruction_prototype_(operator_none, presence_mandatory, 0, + nullptr, "", nullptr, 0, nullptr, + 0, nullptr, cpp_ns_) { static const int32_field_instruction int32_field_instruction_prototype( operator_none, presence_mandatory, 0, nullptr, "", nullptr, int_value_storage()); @@ -105,6 +108,9 @@ templates_builder::templates_builder(dynamic_templates_description *definition, this->member["template"] = &template_instruction_prototype_; this->member["boolean"] = mfast::boolean::instruction(); this->member["enum"] = &enum_field_instruction_prototype_; +#ifdef XETRA_FAST_SPECIFICATION + this->member["set"] = &set_field_instruction_prototype_; +#endif } bool templates_builder::VisitEnter(const XMLElement &element, diff --git a/src/mfast/xml_parser/templates_builder.h b/src/mfast/xml_parser/templates_builder.h index 485f074b..35afed6c 100644 --- a/src/mfast/xml_parser/templates_builder.h +++ b/src/mfast/xml_parser/templates_builder.h @@ -34,6 +34,7 @@ class templates_builder : public XMLVisitor, const group_field_instruction group_field_instruction_prototype_; const sequence_field_instruction sequence_field_instruction_prototype_; const enum_field_instruction enum_field_instruction_prototype_; + const set_field_instruction set_field_instruction_prototype_; }; } /* coder */ diff --git a/src/mfast/xml_parser/view_info_builder.cpp b/src/mfast/xml_parser/view_info_builder.cpp index bba4bbc1..db8f7e65 100644 --- a/src/mfast/xml_parser/view_info_builder.cpp +++ b/src/mfast/xml_parser/view_info_builder.cpp @@ -150,6 +150,11 @@ void view_info_builder::visit(const enum_field_instruction *inst, visit_basic(inst, pIndex); } +void view_info_builder::visit(const set_field_instruction *inst, + void *pIndex) { + visit_basic(inst, pIndex); +} + struct tag_reference_name; typedef boost::error_info reference_name_info; diff --git a/src/mfast/xml_parser/view_info_builder.h b/src/mfast/xml_parser/view_info_builder.h index 48a99960..7286cd05 100644 --- a/src/mfast/xml_parser/view_info_builder.h +++ b/src/mfast/xml_parser/view_info_builder.h @@ -30,6 +30,7 @@ class view_info_builder : public field_instruction_visitor { virtual void visit(const uint64_vector_field_instruction *, void *) override; virtual void visit(const enum_field_instruction *inst, void *data) override; + virtual void visit(const set_field_instruction *inst, void *data) override; void print(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index be7a7a86..eab5b1c3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,6 +28,8 @@ FASTTYPEGEN_TARGET(simple_types16 simple16.xml) if(XETRA_FAST_SPECIFICATION) FASTTYPEGEN_TARGET(simple_types17 simple17.xml) + FASTTYPEGEN_TARGET(simple_types18 simple18.xml) + FASTTYPEGEN_TARGET(simple_types19 simple19.xml) endif(XETRA_FAST_SPECIFICATION) FASTTYPEGEN_TARGET(test_types1 test1.xml test2.xml) @@ -94,8 +96,15 @@ set(test_sources if(XETRA_FAST_SPECIFICATION) set(test_sources ${test_sources} ${FASTTYPEGEN_simple_types17_OUTPUTS} + ${FASTTYPEGEN_simple_types18_OUTPUTS} + ${FASTTYPEGEN_simple_types19_OUTPUTS} timestamp_encoder_decoder_v2.cpp timestamp_encoder_decoder.cpp + xetra_enum_encoder_decoder_v2.cpp + xetra_enum_encoder_decoder.cpp + set_basic_test.cpp + set_encoder_decoder_v2.cpp + set_encoder_decoder.cpp ) endif(XETRA_FAST_SPECIFICATION) diff --git a/tests/set_basic_test.cpp b/tests/set_basic_test.cpp new file mode 100644 index 00000000..25794458 --- /dev/null +++ b/tests/set_basic_test.cpp @@ -0,0 +1,59 @@ +#include "catch.hpp" +#include + +#include "fast_test_coding_case_v2.hpp" +#include "byte_stream.h" + +#include "simple19.h" + +using namespace test::coding; + +TEST_CASE("set data type basic test with default value") +{ + fast_test_coding_case_v2 test_case; + simple19::Test_1 test_1; + + { + simple19::Test_1_mref test_1_mref = test_1.mref(); + auto TradeCondition = test_1_mref.set_TradeCondition(); + TradeCondition.set_OpeningPrice(); + TradeCondition.set_OfficialClosingPrice(); + } + + { + simple19::Test_1_cref test_1_cref = test_1.cref(); + auto TradeCondition = test_1_cref.get_TradeCondition(); + + REQUIRE(TradeCondition.value() == (0x00 | simple19::TradeConditionSet::ExchangeLast | simple19::TradeConditionSet::OpeningPrice | simple19::TradeConditionSet::OfficialClosingPrice)); + + REQUIRE(TradeCondition.has_ExchangeLast()); + REQUIRE(TradeCondition.has_OpeningPrice()); + REQUIRE(TradeCondition.has_OfficialClosingPrice()); + REQUIRE(!TradeCondition.has_Retail()); + } +} + +TEST_CASE("set data type basic test") +{ + fast_test_coding_case_v2 test_case; + simple19::Test_3 test_3; + + { + simple19::Test_3_mref test_3_mref = test_3.mref(); + auto TradeCondition = test_3_mref.set_TradeCondition(); + TradeCondition.set_OpeningPrice(); + TradeCondition.set_OfficialClosingPrice(); + } + + { + simple19::Test_3_cref test_3_cref = test_3.cref(); + auto TradeCondition = test_3_cref.get_TradeCondition(); + + REQUIRE(TradeCondition.value() == (0x00 | simple19::TradeConditionSet::OpeningPrice | simple19::TradeConditionSet::OfficialClosingPrice)); + + REQUIRE(!TradeCondition.has_ExchangeLast()); + REQUIRE(TradeCondition.has_OpeningPrice()); + REQUIRE(TradeCondition.has_OfficialClosingPrice()); + REQUIRE(!TradeCondition.has_Retail()); + } +} diff --git a/tests/set_encoder_decoder.cpp b/tests/set_encoder_decoder.cpp new file mode 100644 index 00000000..564cbf7c --- /dev/null +++ b/tests/set_encoder_decoder.cpp @@ -0,0 +1,25 @@ +#include "catch.hpp" +#include + +#include "fast_test_coding_case.hpp" +#include "byte_stream.h" + +#include "simple19.h" + +using namespace test::coding; + +TEST_CASE("set encoder/decoder","[set_encoder_decoder]") +{ + fast_test_coding_case test_case; + simple19::Test_1 test_1; + simple19::Test_1_mref test_1_mref = test_1.mref(); + + test_1_mref.set_field1().as(10); + + auto TradeCondition = test_1_mref.set_TradeCondition(); + TradeCondition.set_OpeningPrice(); + TradeCondition.set_OfficialClosingPrice(); + + REQUIRE(test_case.encoding(test_1.cref(),"\xF0\x81\x8A\x94",true)); + REQUIRE(test_case.decoding("\xF0\x81\x8A\x94",test_1.cref(),true)); +} diff --git a/tests/set_encoder_decoder_v2.cpp b/tests/set_encoder_decoder_v2.cpp new file mode 100644 index 00000000..b0133aca --- /dev/null +++ b/tests/set_encoder_decoder_v2.cpp @@ -0,0 +1,25 @@ +#include "catch.hpp" +#include + +#include "fast_test_coding_case_v2.hpp" +#include "byte_stream.h" + +#include "simple19.h" + +using namespace test::coding; + +TEST_CASE("set encoder_V2/decoder_v2","[set_encoder_v2_decoder_v2]") +{ + fast_test_coding_case_v2 test_case; + simple19::Test_1 test_1; + simple19::Test_1_mref test_1_mref = test_1.mref(); + + test_1_mref.set_field1().as(10); + + auto TradeCondition = test_1_mref.set_TradeCondition(); + TradeCondition.set_OpeningPrice(); + TradeCondition.set_OfficialClosingPrice(); + + REQUIRE(test_case.encoding(test_1.cref(),"\xF0\x81\x8A\x94",true)); + REQUIRE(test_case.decoding("\xF0\x81\x8A\x94",test_1.cref(),true)); +} diff --git a/tests/simple18.xml b/tests/simple18.xml new file mode 100644 index 00000000..16012949 --- /dev/null +++ b/tests/simple18.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/simple19.xml b/tests/simple19.xml new file mode 100644 index 00000000..6f27fbee --- /dev/null +++ b/tests/simple19.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/xetra_enum_encoder_decoder.cpp b/tests/xetra_enum_encoder_decoder.cpp new file mode 100644 index 00000000..75e07709 --- /dev/null +++ b/tests/xetra_enum_encoder_decoder.cpp @@ -0,0 +1,43 @@ +#include "catch.hpp" +#include + +#include "fast_test_coding_case.hpp" +#include "byte_stream.h" + +#include "simple18.h" + +using namespace test::coding; + +TEST_CASE("xetra enum test encoder/decoder","[xetra_enum_encoder_decoder]") +{ + SECTION("No optional enum / Active") + { + fast_test_coding_case test_case; + simple18::Test_1 test_1; + simple18::Test_1_mref test_1_mref = test_1.mref(); + test_1_mref.set_MDStatisticStatus().as_Active(); + REQUIRE(test_case.encoding(test_1.cref(),"\xc0\x81\x80",true)); + REQUIRE(test_case.decoding("\xc0\x81\x80",test_1.cref(),true)); + } + + SECTION("No optional enum / Inactive") + { + fast_test_coding_case test_case; + simple18::Test_1 test_1; + simple18::Test_1_mref test_1_mref = test_1.mref(); + test_1_mref.set_MDStatisticStatus().as_Inactive(); + REQUIRE(test_case.encoding(test_1.cref(),"\xe0\x81\x81\x80",true)); + REQUIRE(test_case.decoding("\xe0\x81\x81\x80",test_1.cref(),true)); + } + + SECTION("Optional enum") + { + fast_test_coding_case test_case; + simple18::Test_1 test_1; + simple18::Test_1_mref test_1_mref = test_1.mref(); + test_1_mref.set_MDStatisticStatus().as_Inactive(); + test_1_mref.set_MDStatisticFrequencyUnit().as_Minutes(); + REQUIRE(test_case.encoding(test_1.cref(),"\xe0\x81\x81\x83",true)); + REQUIRE(test_case.decoding("\xe0\x81\x81\x83",test_1.cref(),true)); + } +} \ No newline at end of file diff --git a/tests/xetra_enum_encoder_decoder_v2.cpp b/tests/xetra_enum_encoder_decoder_v2.cpp new file mode 100644 index 00000000..543d9418 --- /dev/null +++ b/tests/xetra_enum_encoder_decoder_v2.cpp @@ -0,0 +1,43 @@ +#include "catch.hpp" +#include + +#include "fast_test_coding_case_v2.hpp" +#include "byte_stream.h" + +#include "simple18.h" + +using namespace test::coding; + +TEST_CASE("xetra enum test encoder_V2/decoder_v2","[xetra_enum_encoder_v2_decoder_v2]") +{ + SECTION("No optional enum / Active") + { + fast_test_coding_case_v2 test_case; + simple18::Test_1 test_1; + simple18::Test_1_mref test_1_mref = test_1.mref(); + test_1_mref.set_MDStatisticStatus().as_Active(); + REQUIRE(test_case.encoding(test_1.cref(),"\xc0\x81\x80",true)); + REQUIRE(test_case.decoding("\xc0\x81\x80",test_1.cref(),true)); + } + + SECTION("No optional enum / Inactive") + { + fast_test_coding_case_v2 test_case; + simple18::Test_1 test_1; + simple18::Test_1_mref test_1_mref = test_1.mref(); + test_1_mref.set_MDStatisticStatus().as_Inactive(); + REQUIRE(test_case.encoding(test_1.cref(),"\xe0\x81\x81\x80",true)); + REQUIRE(test_case.decoding("\xe0\x81\x81\x80",test_1.cref(),true)); + } + + SECTION("Optional enum") + { + fast_test_coding_case_v2 test_case; + simple18::Test_1 test_1; + simple18::Test_1_mref test_1_mref = test_1.mref(); + test_1_mref.set_MDStatisticStatus().as_Inactive(); + test_1_mref.set_MDStatisticFrequencyUnit().as_Minutes(); + REQUIRE(test_case.encoding(test_1.cref(),"\xe0\x81\x81\x83",true)); + REQUIRE(test_case.decoding("\xe0\x81\x81\x83",test_1.cref(),true)); + } +} \ No newline at end of file