Arrays of functions, function signatures and template instantiation
JR
zorael at gmail.com
Mon Apr 29 16:49:15 PDT 2013
I'm piecing together a small IRC bot as my second pet project,
and next up is splitting the socket-listening/event handling into
a separate thread.
TL;DR: skip to the link at the bottom -- can't it be done neater?
Raw IRC commands are strings whose format differs depending on
the *type* of the IRC event (for lack of a better word). These
event types are arbitrary short strings like "NICK", "PRIVMSG",
"NOTICE", "PING", "001", etc. I'd sleep better if it were an
enum, but as it is I'm parsing the type from the raw string by
regex, so obviously I'm getting another string out of it.
(Granted, you could cast them to that enum in a huge switch, but
I'm not sure you'd gain any academic efficiency points
considering the extra time spent in that switch.)
After some more regex I have an Event struct with string members
like .sender, .target, .type, .content and some others.
Naturally, depending on what actually happened I may want to
react to it. Most on-event reactions are functions to pass the
Event to, like onPrivateMessage(Event evt) -- but sometimes I
want to know the impending server response of a command I just
sent.
As an example, when you connect to a server, the first things you
send are user details (full name etc) and a nickname request. If
what the server sends next is the welcome event "001", then all
is well -- wait for the end-of-motd event "376" and then slowly
start joining your channels and doing your stuff. But if it is
the nickname-in-use event "433", then everything stops until you
have requested an available nick.
So I had in mind an event handler and a message dispatcher. The
event handler would be in its own thread listening to the socket
stream, and once it reads a string it would parse it into an
Event, then pass it along to the message dispatcher. The
dispatcher would keep a record of which threads have registered
interest in receiving what events, and would send messages
accordingly. The solution that springs to mind is an associative
matrix/array-of-array where one of the index keys is the event
type string, and the other is the thread ID (Tid).
But I still want to keep onPrivateMessage(Event evt) and friends
around, so in a stroke of hubris I thought it would be neat if I
could find a generic solution that could work with both arrays of
thread IDs *and* arrays of function pointers. I'm not sure where
the 'event handler' struct would end and where the 'message
dispatcher' would start though -- perhaps I'll just combine them,
call it Overlord and be done with it. Or maybe
ResponsibilityCreep.
Much shotgun programming later and I now have two templates;
MatrixWalker and FuncRunner, subject to serious renaming. (They
were called Herp and Derp a few hours back.)
Given a function pointer and a matrix of type Foo[Tid][string],
MatrixWalker will foreach all and invoke the function on both
keys (Tid, string) and the final element Foo. The function
signature must match the types used, hence the FuncRunner
template as an adapter. Tid needn't be Tid unless it's in the
context of messaging, naturally, and in the context of messaging
Foo is irrelevant and could be bool. (Keeping a single array like
Tid[string] would only allow for one event registered per Tid, so
Tid has to be a key unless you could somehow store multiple
values per key. Even if possible [?], deregistering the right Tid
from an event string key wouldn't be straightforward anymore.)
> Error: function expected before (), not func of type void
> function(string, uint)*
Yay! Woe.
http://dpaste.dzfl.pl/9273fb92
Can't it be done neater than this? It *does* work now, but it's
incredibly hacky and I'm not satisfied with it. The whole
'passing a function pointer to a function that casts the
signature and invokes it' deal makes me cringe. :>
Many thanks in advance, would love any and every piece of advice
you could spare. With some luck there are some easy shortcuts and
I'm just too green to see them.
More information about the Digitalmars-d-learn
mailing list