I have a byte stream that represents a message in my application. There are 5 fields in the message for demonstration. The first byte in the stream indicates which message fields are present for the current stream. For instance 0x2
in the byte-0 means only the Field-1 is present for the current stream.
The mask field might have 2^5=32 different values. To parse this varying width of message, I wrote the example structure and parser below. My question is, is there any other way to parse such dynamically changing fields? If the message had 64 fields with I would have to write 64 cases, which is cumbersome.
#include <iostream>
typedef struct
{
uint8_t iDummy0;
int iDummy1;
}__attribute__((packed, aligned(1)))Field4;
typedef struct
{
int iField0;
uint8_t ui8Field1;
short i16Field2;
long long i64Field3;
Field4 stField4;
}__attribute__((packed, aligned(1)))MessageStream;
char* constructIncomingMessage()
{
char* cpStream = new char(1+sizeof(MessageStream)); // Demonstrative message byte array
// 1 byte for Mask, 20 bytes for messageStream
cpStream[0] = 0x1F; // the 0-th byte is a mask marking
// which fields are present for the messageStream
// all 5 fields are present for the example
return cpStream;
}
void deleteMessage( char* cpMessage)
{
delete cpMessage;
}
int main() {
MessageStream messageStream; // Local storage for messageStream
uint8_t ui8FieldMask; // Mask to indicate which fields of messageStream
// are present for the current incoming message
const uint8_t ui8BitIsolator = 0x01;
uint8_t ui8FieldPresent; // ANDed result of Mask and Isolator
std::size_t szParsedByteCount = 0; // Total number of parsed bytes
const std::size_t szMaxMessageFieldCount = 5; // There can be maximum 5 fields in
// the messageStream
char* cpMessageStream = constructIncomingMessage();
ui8FieldMask = (uint8_t)cpMessageStream[0];
szParsedByteCount += 1;
for(std::size_t i = 0; i<szMaxMessageFieldCount; ++i)
{
ui8FieldPresent = ui8FieldMask & ui8BitIsolator;
if(ui8FieldPresent)
{
switch(i)
{
case 0:
{
memcpy(&messageStream.iField0, cpMessageStream+szParsedByteCount, sizeof(messageStream.iField0));
szParsedByteCount += sizeof(messageStream.iField0);
break;
}
case 1:
{
memcpy(&messageStream.ui8Field1, cpMessageStream+szParsedByteCount, sizeof(messageStream.ui8Field1));
szParsedByteCount += sizeof(messageStream.ui8Field1);
break;
}
case 2:
{
memcpy(&messageStream.i16Field2, cpMessageStream+szParsedByteCount, sizeof(messageStream.i16Field2));
szParsedByteCount += sizeof(messageStream.i16Field2);
break;
}
case 3:
{
memcpy(&messageStream.i64Field3, cpMessageStream+szParsedByteCount, sizeof(messageStream.i64Field3));
szParsedByteCount += sizeof(messageStream.i64Field3);
break;
}
case 4:
{
memcpy(&messageStream.stField4, cpMessageStream+szParsedByteCount, sizeof(messageStream.stField4));
szParsedByteCount += sizeof(messageStream.stField4);
break;
}
default:
{
std::cerr << "Undefined Message field number: " << i << '\n';
break;
}
}
}
ui8FieldMask >>= 1; // shift the mask
}
delete deleteMessage(cpMessageStream);
return 0;
}
The first thing I'd change is to drop the __attribute__((packed, aligned(1)))
on Field4. This is a hack to create structures which mirror a packed wire-format, but that's not the format you're dealing with anyway.
Next, I'd make MessageStream a std::tuple
of std::optional<T>
fields.
You now know that there are std::tuple_size<MessageStream>
possible bits in the mask. Obviously you can't fit 64 bits in a ui8FieldMask
but I'll assume that's a trivial problem to solve.
You can write a for-loop from 0 to std::tuple_size<MessageStream>
to extract the bits from ui8FieldMask
to see which bits are set. The slight problem with that logic is that you'll need compile-time constants I
for std::get<size_t I>(MessageStream)
, and a for-loop only gives you run-time variables.
Hence, you'll need a recursive template <size_t I> extract(char const*& cpMessageStream, MessageStream&)
, and of course a specialization extract<0>
. In extract<I>
, you can use typename std::tuple_element<I, MessageStream>::type
to get the std::optional<T>
at the I'th position in your MessageStream
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.