diff options
| -rw-r--r-- | include/ocl/fix/parser.hpp | 72 | ||||
| -rw-r--r-- | src/fix/parser_impl.cpp | 95 | ||||
| -rw-r--r-- | test/fix_basic/CMakeLists.txt | 2 |
3 files changed, 110 insertions, 59 deletions
diff --git a/include/ocl/fix/parser.hpp b/include/ocl/fix/parser.hpp index 41d3638..4800a86 100644 --- a/include/ocl/fix/parser.hpp +++ b/include/ocl/fix/parser.hpp @@ -10,9 +10,11 @@ #include <ocl/fix/detail/config.hpp> #include <string> +#include <memory> namespace ocl::fix { + class visitor; struct range; class range_buffer; @@ -24,13 +26,6 @@ namespace ocl::fix using tag_type = std::string; using value_type = std::string; - namespace detail - { - inline const char* begin_fix() noexcept - { - return "FIX.4.2"; - } - } // namespace detail struct range final { @@ -66,7 +61,7 @@ namespace ocl::fix std::string magic_{}; string_hash_map<value_type> message_{}; - static inline const char* begin = detail::begin_fix(); + static inline const char* begin; explicit range_buffer() = default; ~range_buffer() = default; @@ -102,64 +97,25 @@ namespace ocl::fix /// @brief visitor object which returns a fix::range_buffer instance. class visitor final { - public: - static constexpr int soh = '\x01'; - static constexpr char eq = '='; - static constexpr unsigned base = 10U; - - explicit visitor() = default; - ~visitor() = default; + struct impl; + std::unique_ptr<impl> impl_; - visitor& operator=(const visitor&) = delete; - visitor(const visitor&) = delete; + public: + visitor() = default; - range_buffer operator()(const std::string& in) - { - return this->visit(in); - } + /// \brief Alias of visit. + range_buffer operator()(const boost::string_view& in); /// @brief Visits a FIX message and parse it into a range_buffer object. /// @param in The input FIX message as a string. /// @warning This function may throw exceptions. - range_buffer visit(const std::string& in) - { - range_buffer ret{}; - - if (in.empty()) - return ret; - - std::string key; - - std::size_t off = 0UL; - - while (off < in.size()) - { - std::size_t eq_pos = in.find(eq, off); - if (eq_pos == std::string::npos) - break; - - std::string tag = in.substr(off, eq_pos - off); - - std::size_t soh_pos = in.find(soh, eq_pos + 1); - if (soh_pos == std::string::npos) - soh_pos = in.size(); - - std::string value = in.substr(eq_pos + 1, soh_pos - eq_pos - 1); - - if (ret.magic_.empty()) - { - ret.magic_ = value; - ret.magic_len_ = value.size(); - } - - ret.message_[tag] = value; + range_buffer visit(const boost::string_view& in); + }; - off = soh_pos + 1; - } +#if !defined(OCL_FIX_HAS_IMPL) +struct visitor::impl {}; +#endif - return ret; - } - }; } // namespace ocl::fix #endif // ifndef __OCL_FIX_PARSER diff --git a/src/fix/parser_impl.cpp b/src/fix/parser_impl.cpp new file mode 100644 index 0000000..28c9d0d --- /dev/null +++ b/src/fix/parser_impl.cpp @@ -0,0 +1,95 @@ +/* + * File: fix/parser_impl.cpp + * Purpose: Financial Information Exchange parser in C++ + * Author: Amlal El Mahrouss (amlal@nekernel.org) + * Copyright 2025, Amlal El Mahrouss, licensed under the Boost Software License. + */ + +#define OCL_FIX_HAS_IMPL +#include <ocl/fix/parser.hpp> + +namespace ocl::fix +{ + + namespace detail + { + inline const char* begin_fix() noexcept + { + return "FIX.4.2"; + } + } // namespace detail + + struct visitor::impl final + { + public: + static constexpr int soh = '\x01'; + static constexpr char eq = '='; + static constexpr unsigned base = 10U; + + explicit impl() = default; + ~impl() = default; + + impl& operator=(const impl&) = delete; + impl(const impl&) = delete; + + /// @brief Visits a FIX message and parse it into a range_buffer object. + /// @param in The input FIX message as a string. + /// @warning This function may throw exceptions. + range_buffer visit(const boost::string_view& in) + { + if (auto begin = detail::begin_fix(); begin != range_buffer::begin) + range_buffer::begin = begin; + + range_buffer ret{}; + + if (in.empty()) + return ret; + + std::string key; + + std::size_t off = 0UL; + + while (off < in.size()) + { + std::size_t eq_pos = in.find(eq, off); + if (eq_pos == std::string::npos) + break; + + std::string tag = in.substr(off, eq_pos - off).to_string(); + + std::size_t soh_pos = in.find(soh, eq_pos + 1); + if (soh_pos == std::string::npos) + soh_pos = in.size(); + + std::string value = in.substr(eq_pos + 1, soh_pos - eq_pos - 1).to_string(); + + if (ret.magic_.empty()) + { + ret.magic_ = value; + ret.magic_len_ = value.size(); + } + + ret.message_[tag] = value; + + off = soh_pos + 1; + } + + return ret; + } + }; + + /// \brief Alias of visit. + range_buffer visitor::operator()(const std::string& in) + { + return impl_->visit(in); + } + + /// @brief Visits a FIX message and parse it into a range_buffer object. + /// @param in The input FIX message as a string. + /// @warning This function may throw exceptions. + range_buffer visitor::visit(const std::string& in) + { + return impl_->visit(in); + } + +} // namespace ocl::fix diff --git a/test/fix_basic/CMakeLists.txt b/test/fix_basic/CMakeLists.txt index 41ba095..6a92644 100644 --- a/test/fix_basic/CMakeLists.txt +++ b/test/fix_basic/CMakeLists.txt @@ -13,7 +13,7 @@ FetchContent_MakeAvailable(googletest) enable_testing() -add_executable(FIXTestBasic fix.test.cpp) +add_executable(FIXTestBasic fix.test.cpp ../../src/fix/parser_impl.cpp) target_link_libraries(FIXTestBasic gtest_main) set_property(TARGET FIXTestBasic PROPERTY CXX_STANDARD 20) |
