Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

message processing using template

178 views
Skip to first unread message

kira kira

unread,
May 18, 2012, 9:00:45 AM5/18/12
to
Hi,

Suppose there are messages required to process. the code would look
like this.
void process (int type)
{
if (type == MSG_TYPE_A)
{
processMsgA();
}
else if (type == MSG_TYPE_B)
{
processMsgB();
}
}

I would like to know if it is possible to use template to achieve the
same result.

Regards,
Michael


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Zoltan Juhasz

unread,
May 18, 2012, 5:06:23 PM5/18/12
to
{ Please provide at least some context with one or more small
quotes from the article you're replying to -mod }

As you can see, vast majority of the information is actually only
available at run-time. That means that the part that you can actually
do at compile time, is to
- automatically establish the type selection,
- automatically associate user-defined type-id with a given type
- call the appropriate handler in a user-defined functor, given
that it provides an overload for all the expected types

The run-time type selection is effectively 'emulates' the switch-case
(actually an if-elseif-else) construct. It will not be pretty for
sure, so unless you'll work with a very volatile set of types that
can appear in the binary file, it is probably not worth it.

Anyway, the basic building blocks that you'll need:

- a run-time, user-defined type-id (e.g. int type in your example)
- a type-list that contains all the types appearing in the file
- a base class that
- acts as a base-class for user-defined types, that contains the
type-id member data, and initializes at run-time with the
appropriate type-id (derived from the type-list position)
- entry point to process the input (let's call it process())
- a tryProcess functor that establishes the if-elseif-else construct by
recursively calling itself and iterating through the type-list,
with a termination case if the type is not present


template < typename Derived, typename TypeList >
struct BinaryInterface
{
int const type_id;

typedef TypeList DefinedTypes;

// in ctr initialize type_id with the Derived type's position
// inside the type-list (DefinedTypes)
// see mpl::vector, mpl::find and boost::is_same

// static function to read from raw input
// (e.g. mem-location in this case)
template< typename FunT >
static FunT process( void * & input, FunT functor )
{
return Internal::tryProcess<
mpl::size< DefinedTypes >::value - 1, BinaryInterface
>()( input, functor );
}
};


The tryProcess can be something along these lines:

template < std::size_t N, typename BinaryInterfaceT >
struct tryProcess
{
typedef typename BinaryInterfaceT::DefinedTypes DefinedTypes;

// current type at position N in the type-list
typedef typename mpl::at< DefinedTypes, mpl::int_< N > >::type
DerivedType;

template< typename FunT >
FunT operator()( void * & input, FunT functor )
{
// is this the type we are looking for?
if ( static_cast< BinaryInterfaceT * >( input )->type_id == N )
{
// get a typed ptr out of input
DerivedType * derivedInput =
static_cast< DerivedType * > ( input );

// tell the user-defined functor the last read-size
// and the advance the pointer appropriately
reinterpret_cast< char * & >( input )
+= functor.readSize = sizeof( DerivedType );

// execute the user-defined functor on the last object we read
// it needs to overload the operator() for all expected types
functor( derivedInput );
return functor;
}
// nope, keep looking
else
{
return tryProcess< N-1, BinaryInterfaceT >()( input, functor );
}
}
};

// partial-specialization for the termination case
// the 0th position in the type-list is reserved for the error case
// this is not really needed if you are willing to play with indeces
template< typename BinaryInterfaceT >
struct tryProcess< 0, BinaryInterfaceT >
{
template< typename FunT >
FunT operator()( void * & input, FunT functor )
{
throw OutOfBound(
static_cast< BinaryInterfaceT * >( input ) -> type_id
);
return functor; // never executed, but to prevent warnings
}
};

And finally the type-list is:

typedef boost::mpl::vector<
boost::mpl::void_ // placeholder, place types after this
, MyType1
, MyType2
> MyTypeList;


HTH

-- Zoltan

red floyd

unread,
May 18, 2012, 5:30:45 PM5/18/12
to
On 5/18/2012 6:00 AM, kira kira wrote:
> Hi,
>
> Suppose there are messages required to process. the code would look
> like this.
> void process (int type)
> {
> if (type == MSG_TYPE_A)
> {
> processMsgA();
> }
> else if (type == MSG_TYPE_B)
> {
> processMsgB();
> }
> }
>
> I would like to know if it is possible to use template to achieve the
> same result.
>

Use inheritance an virtual functions.

struct Message {
virtual void Process() = 0;
virtual ~Message() { }
};

struct MsgA : public Message {
void Process() {
// process MsgA
}
};

struct MsgB : public Message {
void Process() {
// process MsgB
}
};

DeMarcus

unread,
May 18, 2012, 8:25:22 PM5/18/12
to
On 2012-05-18 15:00, kira kira wrote:
> Hi,
>
> Suppose there are messages required to process. the code would look
> like this.
> void process (int type)
> {
> if (type == MSG_TYPE_A)
> {
> processMsgA();
> }
> else if (type == MSG_TYPE_B)
> {
> processMsgB();
> }
> }
>
> I would like to know if it is possible to use template to achieve the
> same result.
>


To get some inspiration, you could look at two different design patterns
called 'double dispatch' and 'visitor'.

http://en.wikipedia.org/wiki/Double_dispatch
http://en.wikipedia.org/wiki/Visitor_pattern

A good book if you like design patterns is Pattern-Oriented Software
Architecture. The volume below describes distributed computing and
covers messages.

http://www.amazon.com/dp/0470059028


Regards,
Daniel

kira kira

unread,
May 21, 2012, 12:20:10 AM5/21/12
to
Thank you all. it is so great that I know something new.
However, what if there are some shared resources e.g. sequence number
check for each message?
If every handler is an object, the only way to access the shared
resources is to use setter(i.e. setSeqNo()), right?

cpplj...@gmail.com

unread,
May 21, 2012, 9:26:04 AM5/21/12
to
On Friday, May 18, 2012 4:06:23 PM UTC-5, Zoltan Juhasz wrote:

> { Please provide at least some context with one or more small quotes
> from the article you're replying to -mod }
>
> As you can see, vast majority of the information is actually only
> available at run-time. That means that the part that you can
> actually do at compile time, is to
> - automatically establish the type selection,
> - automatically associate user-defined type-id with a given type
> - call the appropriate handler in a user-defined functor, given
> that it provides an overload for all the expected types
>
[snip]
This sounds a lot like boost variant's apply_visitor:

http://www.boost.org/doc/libs/1_49_0/doc/html/boost/apply_visitor.html

However, variant uses the preprocessor at places:

http://www.boost.org/doc/libs/1_49_0/doc/html/variant/tutorial.html#variant.tutorial.preprocessor

So, if you don't want that, you might consider:

http://thenewcpp.wordpress.com/2012/02/15/variadic-templates-part-3-or-how-i-wrote-a-variant-class/

HTH.

-regards,
Larry

Jorgen Grahn

unread,
May 27, 2012, 6:29:13 AM5/27/12
to
On Fri, 2012-05-18, red floyd wrote:
> On 5/18/2012 6:00 AM, kira kira wrote:
>> Hi,
>>
>> Suppose there are messages required to process. the code would look
>> like this.
>> void process (int type)
>> {
>> if (type == MSG_TYPE_A)
>> {
>> processMsgA();
>> }
>> else if (type == MSG_TYPE_B)
>> {
>> processMsgB();
>> }
>> }
>>
>> I would like to know if it is possible to use template to achieve the
>> same result.
>
> Use inheritance an virtual functions.
>
> struct Message {
> virtual void Process() = 0;
> virtual ~Message() { }
> };
>
> struct MsgA : public Message {
...
> struct MsgB : public Message {
...

I'm guessing (based on his other posting mentioning sequence numbers)
that the messages are part of some network protocol, perhaps an
UDP-based one like GTP or L2TP. Or perhaps he's implementing TCP ...

I find a less object-oriented approach the best. A dumb class
RxMessage for parsing messages I receive, and TxMessage for building
messages I need to send. These would know about the general message
format only -- typically a header with message type, sequence number,
checksum and so on, followed by type-specific data.

I may need to both read and write MSG_TYPE_FOO messages, but creating
a single MessageFoo class would be a mistake -- reading and writing
are two completely different things.

Also, I believe creating a fully parsing MessageFoo is often a
mistake. Some of these protocols have messages with a very rich inner
structure. There may be dozens of possible fields of various types.
Expressed as a C++ struct that can turn into dozens of vectors, most
of which are empty most of the time. A waste of resources -- and
almost as hard to interpret as the original binary message was!

The actual processing logic goes into other classes called things like
Retransmitter, Connection, Session, Peer ... depending on the protocol.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

kira kira

unread,
Jun 7, 2012, 1:36:02 PM6/7/12
to
On May 27, 6:29 pm, Jorgen Grahn <grahn+n...@snipabacken.se> wrote:
>
> I'm guessing (based on his other posting mentioning sequence numbers)
> that the messages are part of some network protocol, perhaps an
> UDP-based one like GTP or L2TP. Or perhaps he's implementing TCP ...
>
> I find a less object-oriented approach the best. A dumb class
> RxMessage for parsing messages I receive, and TxMessage for building
> messages I need to send. These would know about the general message
> format only -- typically a header with message type, sequence number,
> checksum and so on, followed by type-specific data.
>
> I may need to both read and write MSG_TYPE_FOO messages, but creating
> a single MessageFoo class would be a mistake -- reading and writing
> are two completely different things.
>
> Also, I believe creating a fully parsing MessageFoo is often a
> mistake. Some of these protocols have messages with a very rich inner
> structure. There may be dozens of possible fields of various types.
> Expressed as a C++ struct that can turn into dozens of vectors, most
> of which are empty most of the time. A waste of resources -- and
> almost as hard to interpret as the original binary message was!
>
> The actual processing logic goes into other classes called things like
> Retransmitter, Connection, Session, Peer ... depending on the protocol.
>
> /Jorgen

{ quoted signature and banner removed by mod; please do it yourself. -mod }

So it is wise to use the normal function call with if-else loop.
Template is not suitable for this case, right?


--

Jorgen Grahn

unread,
Jun 9, 2012, 9:57:23 AM6/9/12
to
...
>
> So it is wise to use the normal function call with if-else loop.

At least that's what I find myself doing. Or a switch, rather. If I
implement a five-message protocol, I don't feel bad for having a
five-case switch statement somewhere in my code.

IMHO when I've just received a binary message, it's too early to turn
on the run-time polymorphism and have some factory build
FooMessage/BarMessage ... objects from it. I may not even have a real
reason to copy data from the input buffer.

But you still haven't provided any details, so I'm still talking about
things *I've* done and hoping this is relevant to your problem.

> Template is not suitable for this case, right?

Which case -- yours or mine? I do think templates are useful when
implementing message servers in general, but I cannot say exactly how.

Perhaps others have ready-made architectural ideas about templates. I
just keep an eye open, and when I see that I can simplify the code
with a template, I do it.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .


woodb...@gmail.com

unread,
Jun 13, 2012, 11:26:07 AM6/13/12
to
On Sunday, May 27, 2012 5:29:13 AM UTC-5, Jorgen Grahn wrote:
>
> I'm guessing (based on his other posting mentioning sequence numbers)
> that the messages are part of some network protocol, perhaps an
> UDP-based one like GTP or L2TP. Or perhaps he's implementing TCP ...
>
> I find a less object-oriented approach the best. A dumb class
> RxMessage for parsing messages I receive, and TxMessage for building
> messages I need to send. These would know about the general message
> format only -- typically a header with message type, sequence number,
> checksum and so on, followed by type-specific data.
>
> I may need to both read and write MSG_TYPE_FOO messages, but creating
> a single MessageFoo class would be a mistake -- reading and writing
> are two completely different things.
>
> Also, I believe creating a fully parsing MessageFoo is often a
> mistake. Some of these protocols have messages with a very rich inner
> structure. There may be dozens of possible fields of various types.
> Expressed as a C++ struct that can turn into dozens of vectors, most
> of which are empty most of the time. A waste of resources -- and
> almost as hard to interpret as the original binary message was!
>
> The actual processing logic goes into other classes called things like
> Retransmitter, Connection, Session, Peer ... depending on the protocol.
>

I'm not sure if I understand you very well, but I guess I
agree more with what you're saying than Red Floyd. I'm
working on the C++ Middleware Writer. It's meant to
help with building systems that send/receive binary
messages.

Brian
Ebenezer Enterprises
http://webEbenezer.net


--
0 new messages