summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/ocl/fix/parser.hpp143
-rw-r--r--include/ocl/hashing/hash.hpp31
2 files changed, 71 insertions, 103 deletions
diff --git a/include/ocl/fix/parser.hpp b/include/ocl/fix/parser.hpp
index 71e0eb6..60a4f9a 100644
--- a/include/ocl/fix/parser.hpp
+++ b/include/ocl/fix/parser.hpp
@@ -9,6 +9,7 @@
#define _OCL_FIX_PARSER_HPP
#include <core/config.hpp>
+#include <hashing/hash.hpp>
#include <io/print.hpp>
#include <algorithm>
#include <string>
@@ -16,48 +17,27 @@
namespace ocl::fix
{
- template <typename char_type>
class basic_visitor;
- template <typename char_type>
struct basic_range;
- template <typename char_type>
class basic_range_data;
/// @brief Buffer+Length structure
- template <typename char_type = char>
- using range_ptr_t = basic_range<char_type>;
+ using range_ptr_t = basic_range*;
namespace detail
{
- template <typename char_type = char>
- const char_type* begin_fix() noexcept;
-
- template <>
- inline const char* begin_fix<char>() noexcept
+ inline const char* begin_fix() noexcept
{
return "FIX.4.2";
}
-
- template <>
- inline const char16_t* begin_fix<char16_t>() noexcept
- {
- return u"FIX.4.2";
- }
-
- template <>
- inline const char8_t* begin_fix<char8_t>() noexcept
- {
- return u8"FIX.4.2";
- }
} // namespace detail
- template <typename char_type = char>
struct basic_range final
{
- char_type* bytes_{nullptr};
- size_t length_{};
+ char* bytes_{nullptr};
+ size_t length_{};
bool is_valid() noexcept
{
@@ -72,26 +52,23 @@ namespace ocl::fix
/// @brief Convert basic_range to usable string.
/// @note This function assumes that the basic_range is valid and contains ASCII bytes.
- template <typename char_type = char>
- inline std::basic_string<char_type> to_string(basic_range<char_type>& basic_range) noexcept
+ inline std::string to_string(basic_range& basic_range) noexcept
{
- if (basic_range.length_ < 0)
- return std::basic_string<char_type>{};
+ if (basic_range.length_ < 1)
+ return std::string{};
- return std::basic_string<char_type>(basic_range.bytes_, basic_range.length_);
+ return std::string(basic_range.bytes_, basic_range.length_);
}
/// @brief a basic_range object containing the FIX packet values.
- template <typename char_type = char>
class basic_range_data final
{
public:
- std::size_t magic_len_{};
- std::basic_string<char_type> magic_{};
- std::size_t body_len_{};
- std::vector<std::pair<std::basic_string<char_type>, std::basic_string<char_type>>> body_{};
+ std::size_t magic_len_{};
+ std::string magic_{};
+ string_hash_map<std::string> message_{};
- static inline const char_type* begin = detail::begin_fix<char_type>();
+ static inline const char* begin = detail::begin_fix();
explicit basic_range_data() = default;
~basic_range_data() = default;
@@ -99,24 +76,21 @@ namespace ocl::fix
basic_range_data& operator=(const basic_range_data&) = default;
basic_range_data(const basic_range_data&) = default;
- std::basic_string<char_type> operator[](const std::basic_string<char_type>& key)
+ std::string operator[](const std::string& key)
{
if (key.empty())
- return std::basic_string<char_type>{};
-
- auto it = std::find_if(this->body_.begin(), this->body_.end(), [&key](const std::pair<std::basic_string<char_type>, std::basic_string<char_type>>& in) {
- return in.first == key;
- });
+ return std::string{};
- if (it != this->body_.cend())
+ auto it = message_.find(key);
+ if (it != message_.end())
return it->second;
- return std::basic_string<char_type>{};
+ return std::string{};
}
bool is_valid()
{
- return magic_.starts_with(basic_range_data<char_type>::begin);
+ return this->operator[]("8").empty() == false;
}
explicit operator bool()
@@ -126,14 +100,13 @@ namespace ocl::fix
};
/// @brief basic_visitor object which returns a fix::basic_range_data instance.
- template <typename char_type = char>
class basic_visitor final
{
public:
/// AMLALE: Yeah...
- static constexpr const int soh = '\x01';
- static constexpr const char_type eq = '=';
- static constexpr uint32_t base = 10U;
+ static constexpr const int soh = '\x01';
+ static constexpr const char eq = '=';
+ static constexpr uint32_t base = 10U;
explicit basic_visitor() = default;
~basic_visitor() = default;
@@ -141,7 +114,7 @@ namespace ocl::fix
basic_visitor& operator=(const basic_visitor&) = default;
basic_visitor(const basic_visitor&) = default;
- basic_range<char_type> operator()(const std::basic_string<char_type>& in)
+ basic_range_data operator()(const std::string& in)
{
return this->visit(in);
}
@@ -149,77 +122,57 @@ namespace ocl::fix
/// @brief Visit a FIX message and parse it into a basic_range_data object.
/// @param in The input FIX message as a string.
/// @warning This function may throw exceptions.
- basic_range_data<char_type> visit(const std::basic_string<char_type>& in)
+ basic_range_data visit(const std::string& in)
{
- basic_range_data<char_type> ret{};
+ basic_range_data ret{};
if (in.empty())
return ret;
- std::basic_string<char_type> key;
+ std::string key;
std::size_t off = 0UL;
- while (true)
+ while (off < in.size())
{
- if (in.size() < off)
+ // Find the '=' separator
+ std::size_t eq_pos = in.find(eq, off);
+ if (eq_pos == std::string::npos)
break;
- if (in[off] != basic_visitor::eq)
- {
- if (in[off] == basic_visitor::soh)
- {
- ++off;
- continue;
- }
-
- key += in[off];
- ++off;
- continue;
- }
+ // Extract tag (everything from current position to '=')
+ std::string tag = in.substr(off, eq_pos - off);
- if (in.size() < (off + 1))
- break;
+ // Find the SOH delimiter after the value (or end of string)
+ std::size_t soh_pos = in.find(soh, eq_pos + 1);
+ if (soh_pos == std::string::npos)
+ soh_pos = in.size();
- std::basic_string<char_type> val = in.substr(off + 1);
-
- if (val.find(basic_visitor::soh) != std::basic_string<char_type>::npos)
- {
- val.erase(val.find(basic_visitor::soh));
- }
+ // Extract value (everything from after '=' to SOH)
+ std::string value = in.substr(eq_pos + 1, soh_pos - eq_pos - 1);
+ // Store first value as magic (should be BeginString)
if (ret.magic_.empty())
{
- ret.magic_ = val;
- ret.magic_len_ = ret.magic_.size();
+ ret.magic_ = value;
+ ret.magic_len_ = value.size();
}
- ret.body_.emplace_back(std::make_pair(key, val));
+ // Store tag-value pair
+ ret.message_[tag] = value;
- off += val.size() + 1;
-
- key.clear();
+ // Move to position after the SOH
+ off = soh_pos + 1;
}
- ret.body_len_ = ret.body_.size();
-
return ret;
}
};
- template <typename char_type = char, typename error_handler>
- inline void must_pass(basic_range_data<char_type>& basic_range, error_handler& handler)
- {
- if (!basic_range.is_valid())
- {
- handler.template error<true>("Invalid FIX Message.");
- }
- }
-
- using fix_tag_type = std::basic_string<char>;
+ using fix_tag_type = std::string;
- using range_data = basic_range_data<char>;
- using visitor = basic_visitor<char>;
+ using range_data = basic_range_data;
+ using visitor = basic_visitor;
} // namespace ocl::fix
#endif // ifndef _OCL_FIX_PARSER_HPP \ No newline at end of file
diff --git a/include/ocl/hashing/hash.hpp b/include/ocl/hashing/hash.hpp
index c64daf4..3a29979 100644
--- a/include/ocl/hashing/hash.hpp
+++ b/include/ocl/hashing/hash.hpp
@@ -13,6 +13,7 @@
#include <cstdint>
#include <string>
#include <cstddef>
+#include <concepts>
/// @brief Crc32 implementation in C++
/// @author Amlal El Mahrouss (amlal@nekernel.org)
@@ -57,9 +58,8 @@ namespace ocl
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
- template <typename buffer_type>
- static std::uint32_t
- crc32(buffer_type in, size_t len) noexcept
+ static std::size_t
+ crc32(const char* in, size_t len) noexcept
{
if (!in || *in == 0)
return 0;
@@ -73,6 +73,9 @@ namespace ocl
}
};
+ template <typename V>
+ using string_hash_map = std::unordered_map<std::string, V, std::hash<ocl::hash_trait>>;
+
template <typename K, typename V>
using hash_map = std::unordered_map<K, V, std::hash<ocl::hash_trait>>;
} // namespace ocl
@@ -82,20 +85,32 @@ namespace std
template <>
struct hash<ocl::hash_trait> final
{
- hash() = default;
+ hash() = default;
~hash() = default;
template <typename T>
- inline std::size_t operator()(T* in_)
+ inline std::size_t operator()(T* in_) const
{
- return ocl::hash_trait::crc32<char*>((char*)in_, sizeof(T));
+ return ocl::hash_trait::crc32(reinterpret_cast<const char*>(in_), sizeof(T));
}
- inline std::size_t operator()(const std::string& in_)
+ inline std::size_t operator()(const std::string& in_) const
{
- return ocl::hash_trait::crc32<const char*>(in_.c_str(), in_.size());
+ return ocl::hash_trait::crc32(in_.c_str(), in_.size());
}
};
+
+ // Source - https://stackoverflow.com/a/68521441
+ // Posted by StoryTeller - Unslander Monica, modified by community. See post 'Timeline' for change history
+ // Retrieved 2025-11-30, License - CC BY-SA 4.0
+
+ template <class Fn, class... ArgTypes>
+ struct is_invocable_hash : std::bool_constant <
+ requires(Fn fn, ArgTypes... arg_types)
+ {
+ {std::forward<Fn>(fn)(std::forward<ArgTypes>(arg_types)...)}->std::same_as<hash<ocl::hash_trait>>;
+ }>{};
+
} // namespace std
#endif // !_OCL_CRC32_HPP \ No newline at end of file