Skip to content

Instantly share code, notes, and snippets.

@nixiz
Created August 13, 2020 17:42
Show Gist options
  • Save nixiz/bdad042f3ebb2898cf9e9131148ce0ff to your computer and use it in GitHub Desktop.
Save nixiz/bdad042f3ebb2898cf9e9131148ce0ff to your computer and use it in GitHub Desktop.
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
#include <algorithm>
#include <execution>
using namespace std;
// fix mesaj tag'leri için kullanılacak parser sınıflarının deklerasyonları
// tek bir dosya içerisinde örnek uygulandığı için bu sınıfların yukarıda
// deklare edilmesi gerekmektedir. düzgün bir hiyerarşde bu sınıflar kodlanırsa
// buna gerek kalmayacaktır.
struct date_time_t {};
struct legacy_any_tag_parser;
struct tag_1_parser;
struct tag_2_parser;
// ...
// ...
// ...
struct tag_52_parser;
// bütün fix mesajlarının parse edildikten sonra yapılacağı işler için
// temel visitor pattern'i uygulanmış bu sınıf kullanılabilir.
// paket içerisinde gelen bütün mesajlar burada işlendikten sonra
// work_with_message() gibi bir metod üzerinden ne yapılmak isteniyorsa yapılabilir.
class FixMessageProcessor {
public:
void process_fix_tag(const legacy_any_tag_parser& parser) {}
void process_fix_tag(const tag_1_parser& parser) {}
void process_fix_tag(const tag_2_parser& parser) {}
// ...
// ...
// ...
void process_fix_tag(const tag_52_parser& parser);
public:
void work_with_message() { }
};
// eski tip parser burada kullanılmaya devam edilebilir. bu sayede
// özelleştirilmemiş bir fix tag mesajı için gelen mesajın işlenmesi devam edecektir
struct legacy_any_tag_parser {
bool parse(const std::string_view& message) {
std::cout << "parsing message: " << message << "\n";
return false;
}
void apply(FixMessageProcessor& fmp) {
fmp.process_fix_tag(*this);
}
};
// istenilen veya dönüştürülecek türlere göre özelleştirilmiş parser sınıfları:
struct tag_1_parser {
bool parse(const std::string_view& message) { return false; }
void apply(FixMessageProcessor& fmp) {
fmp.process_fix_tag(*this);
}
};
// ...
// ...
// ...
struct tag_52_parser {
bool parse(const std::string_view& message) { return true; }
void apply(FixMessageProcessor& fmp) {
fmp.process_fix_tag(*this);
}
date_time_t date_time;
};
void FixMessageProcessor::process_fix_tag(const tag_52_parser& parser) {
date_time_t time = parser.date_time;
}
// tag numarasına göre özelleştirilmemiş parser sınıfları varsayılan olarak
// legacy, yavaş parser sınıfını kullanarak devam edebilirler.
template <int tag>
struct tag_traits {
using type = void;
using parser = legacy_any_tag_parser;
};
template <>
struct tag_traits<1> {
// her tag için belirlenmiş bir dönüşüm türü olduğu varsayılarak
// 1 tag'i için dönüş yapılacak tipin int olması gerekiyorsa int olarak
// belirtilecektir.
using type = int;
using parser = tag_1_parser;
};
template <>
struct tag_traits<52> {
// aynı şekilde 52 tag'i için date time sınıfı kullanılacaktır
using type = date_time_t;
using parser = tag_52_parser;
};
// fix mesajından çıkarılacak tag değerine göre özelleştirilmiş parser sınıfların
// çağrılmasını sağlayan sınıf.
template <int tag = -1>
struct fix_tag_parser {
using tag_type = typename tag_traits<tag>::type;
using tag_parser = typename tag_traits<tag>::parser;
static bool parse(const std::string_view& message) {
// gereksinime göre parser sınıfı burada yaratılabilir veya
// yaratılmadan statik metoduna yönlendirilebilir.
// aynı şekilde statik instance kullanıldığında parser sınıfını
// bir sonraki işleme hazırlamak da gerekebilir.
// 'parser.clean()' veya 'parser.prepare()' gibi..
return parser.parse(message);
}
static void apply(FixMessageProcessor& fmp) {
parser.apply(fmp);
}
private:
static inline tag_parser parser;
};
// stackoverflow'dan buldum kullanılabilir: https://stackoverflow.com/a/58048821
std::vector<std::string_view> split(const std::string_view str, const char delim = ',')
{
std::vector<std::string_view> result;
int indexCommaToLeftOfColumn = 0;
int indexCommaToRightOfColumn = -1;
for (int i = 0; i < static_cast<int>(str.size()); i++)
{
if (str[i] == delim)
{
indexCommaToLeftOfColumn = indexCommaToRightOfColumn;
indexCommaToRightOfColumn = i;
int index = indexCommaToLeftOfColumn + 1;
int length = indexCommaToRightOfColumn - index;
std::string_view column(str.data() + index, length);
result.push_back(std::move(column));
}
}
const std::string_view finalColumn(str.data() + indexCommaToRightOfColumn + 1, str.size() - indexCommaToRightOfColumn - 1);
result.push_back(finalColumn);
return result;
}
// aynı şekilde tek dosya üzerinde yazdığım için deklare etmem gerekiyor
void on_fix_tag_received(FixMessageProcessor& fmp, const string_view& message);
// tcp'den veya bir yerden gelen fix mesajının alındığı metod:
void on_fix_message_received(
const char* message, int len)
{
// her gelen mesaj için fix taglerini toplayarak işlemek için hazır hale getiren bir sınıfımız olsun
FixMessageProcessor processor;
// cheksum hesapla ve mesajın doğruluğunu kontrol et:
bool is_message_valid = true;
if (!is_message_valid) return;
// gelen mesajları tag'ler halinde gruplayarak paralel veya seri bir şekilde
// bir döngüde işle:
auto fix_tags = split(message, '|');
for_each(std::execution::par, begin(fix_tags), end(fix_tags),
[&processor](const string_view& tag) {
// ve her tag parçasını için parser metodumuzu çağıralım
on_fix_tag_received(processor, tag);
});
// bütün mesajlar pars edildikten sonra gerekli olan işlemleri yapalım.
processor.work_with_message();
}
void on_fix_tag_received(
FixMessageProcessor& fmp,
const string_view& message)
{
auto message_parts = split(message, '=');
int tag = std::stoi(message_parts.at(0).data());
// burada gelen mesajın tag numarasına göre, ona özel parser metodlarını çağırıyoruz
switch (tag)
{
case 1:
{
bool res = fix_tag_parser<1>::parse(message_parts.at(1));
if (res) {
fix_tag_parser<1>::apply(fmp);
}
}
break;
case 2:
{
bool res = fix_tag_parser<2>::parse(message_parts.at(1));
if (res) {
fix_tag_parser<2>::apply(fmp);
}
}
break;
case 52:
{
bool res = fix_tag_parser<52>::parse(message_parts.at(1));
if (res) {
fix_tag_parser<52>::apply(fmp);
}
}
break;
default:
{
bool res = fix_tag_parser<>::parse(message);
if (res) {
fix_tag_parser<>::apply(fmp);
}
}
break;
}
}
int main(int argc, const char* argv[]) {
const char sample_msg[] = "8=FIX.4.2|9=196|35=X|49=A|56=B|34=12|52=20100318-03:21:11.364|262=A|268=2|279=0|269=0|278=BID|55=EUR/USD|270=1.37215|15=EUR|271=2500000|346=1|279=0|269=1|278=OFFER|55=EUR/USD|270=1.37224|15=EUR|271=2503200|346=1|10=171";
on_fix_message_received(sample_msg, sizeof(sample_msg));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment