summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/ocl/fix/parser.hpp72
-rw-r--r--src/fix/parser_impl.cpp95
-rw-r--r--test/fix_basic/CMakeLists.txt2
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)