Last active
December 13, 2016 19:04
-
-
Save scraimer/35dfd89208d6c7778548c48730d6c495 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
/* | |
Problem Space: | |
-------------- | |
FIXT1.1 is a protocol where FIX data is sent in fields separated by a 0x01. | |
In each field, the format is "tag=value", where "tag" is a number | |
from 1 upwards. | |
Goal: | |
----- | |
Create a FIXT1.1 "parser" that reads a FIX string, | |
and provides pointers to the value at each tag. | |
In this case, we'll assume the flat case: each tag only appears once. | |
(I'm calling it flat because there's no "depth" due to nesting) | |
Later one, we'll handle the none-flat case, where tags can be part of | |
"repeating groups", and therefore may repeat more than once. | |
Reading through that might require using an interator instead | |
of allowing random access. | |
Ideas: | |
- Create depth by extending the flat parser to be able to | |
have pointers into other flat parsers. And we can do this | |
by using the pointer to either point at char* or at | |
another flat or another complex_parser. | |
- Allow random access: using the NoEntries as the key for the group. | |
For example, if we do get<268>(), it'll return the | |
the subgroup as another parser, etc: | |
// Get the first MDEntryType (tag 269) as integer: | |
int MDEntryType_first = parser.get<268>().get<269,int>(); | |
// Get the second MDEntryType (tag 269) as integer: | |
int MDEntryType second = parser.get<268>().get<parser::next>().get<269,int>(); | |
fix_simple_parser<277,278> parser; | |
char* f277 = parser.get<277>(); // Good | |
char* f279 = parser.get<279>(); // Compile time error, since 279 wasn't in the list | |
*/ | |
#define NULL ((void*)0) | |
/** | |
The flat parser assumes only a single instance of each FIx field, and | |
assumes that only the FIX fields with the tags specified in F1..FN are | |
to be made readable. Other FIX fields are to be ignored. | |
Usage: | |
fix_flat_parser parser; | |
... | |
parser.parse(fix_string); | |
int int_value = parser.get<34,int>() | |
char const * str_value = parser.get<49>(); | |
*/ | |
template <int F1 = 0, int F2 = 0, int F3 = 0, int F4 = 0, int F5 = 0, | |
int F6 = 0, int F7 = 0, int F8 = 0, int F9 = 0> | |
class fix_flat_parser | |
{ | |
// This is just a base class that allows us to cast thingy<K> inside get_thingy<K>(), | |
// so that we don't a compilation error trying to return differing types. | |
struct thingy_base { }; | |
// 'thingy' is a pointer to a position on the FIX string where the value of FIX tag 'K' is. | |
// TODO: expand it so that thingy can hold sub-groups (repeating groups) of tags | |
template <int K> | |
struct thingy : thingy_base | |
{ | |
char const * _ptr; | |
thingy() : _ptr( static_cast<char const *>(NULL) ) | |
{ | |
} | |
char const * val() const | |
{ | |
return _ptr; | |
} | |
}; | |
thingy<F1> _t1; | |
thingy<F2> _t2; | |
thingy<F3> _t3; | |
thingy<F4> _t4; | |
thingy<F5> _t5; | |
thingy<F6> _t6; | |
thingy<F7> _t7; | |
thingy<F8> _t8; | |
thingy<F9> _t9; | |
public: | |
fix_flat_parser(char const * const fix_string) | |
{ | |
} | |
template <int K> | |
thingy<K> const & get_thingy() const | |
{ | |
static_assert( K == F1 || K == F2 || K == F3 || K == F4 || | |
K == F5 || K == F6 || K == F7 || K == F8 || K == F9, | |
"Value of K must be one of the FIX tags specified" | |
" in the template instantiation"); | |
thingy_base const * return_value_unforced = static_cast<thingy_base const *>(NULL); | |
switch( K ) | |
{ | |
case F1: return_value_unforced = &_t1; break; | |
case F2: return_value_unforced = &_t2; break; | |
case F3: return_value_unforced = &_t3; break; | |
case F4: return_value_unforced = &_t4; break; | |
case F5: return_value_unforced = &_t5; break; | |
case F6: return_value_unforced = &_t6; break; | |
case F7: return_value_unforced = &_t7; break; | |
case F8: return_value_unforced = &_t8; break; | |
case F9: return_value_unforced = &_t9; break; | |
} | |
return *(static_cast< thingy<K> const * >( return_value_unforced )); | |
} | |
// XXX This is only here to allow short and easy initialization. | |
// I need to re-write the parser that tokanized the tag=value pairs. | |
void set1(char const * s) | |
{ | |
_t1._ptr = _t2._ptr = _t3._ptr = _t4._ptr = _t5._ptr = _t6._ptr = _t7._ptr = _t8._ptr = _t9._ptr = s; | |
} | |
}; | |
extern char data[100]; | |
int main() | |
{ | |
fix_flat_parser<277,279,330,4,5,6,7,8,9> p( data ); | |
p.set1( data ); | |
char const * s = p.get_thingy<8>().val(); | |
if( s == NULL ) | |
{ | |
return 0; | |
} | |
else | |
{ | |
// TODO: make the parser smaller | |
// - switch to integers as offsets | |
return sizeof(p); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment