tags:

views:

97

answers:

1

How would you solve this problem? (At the beginning it seemed simple, then I found it to be puzzling).

  • You have a class called Executor. Suppose you have many instance of it and they do different things upon call of a method do(Argument).
  • Argument has 2 different parameters and they are A* pa, B* pb (one of which can be null)
  • Now, I want a class Manager that receives Argument istances and forwards them to the appropriate instance of Executor (let's call this method Filter). This is done after, some time before, each Executor called the Manager.subscribe(A* pa, B* pb) method to say to wich one of these is interested. Note that: if pa or (not both) pb are NULL, means ANY (I mean if pa is NULL, only pb is checked). Of course there must not be more than one Executor.
  • The implementation must be FAST, the ideal should be a vector, or something close like an hash map... BUT THE COMPARISON HAS TO BE MADE ON THE CONTENTS OF pa and pb, not their value as pointers.
  • Finally,it must be possible that subscription can be cancelled by an executor (without waiting too long). Anyway I want that Filter, subscribe and cancelSubscription are very fast.

I've been thinking of many arrangements, with hash maps, lists and multimaps... But all of them lack speed or easyness, or something else. What would you do?

+2  A: 

I think you want to create a class called "Subscription" which represents a single subscription from an Executor to a Manager containing information on under what conditions the this Subscription would trigger, as well as some sort of GUID or name for this subscription. I'm thinking something like

 class Subscription
 {
   GUID g;
   A_filter a;
   B_filter b;
   Executor *e;
 }

Subcription would also have a method to "Check" if it should trigger based on given values for A and B and then call the executor on those parameters if it matches.

The Manager class would then contain three maps, one of these Maps Guid to Subscription* and would allow very quick unsubcribes, basically look up the GUID in the unsubscribe request to get the Subscription object, use that object to determine what values for A and B might need to be deleted from the A map and B map, then delete the object. Subscribe is just a matter of creating the Subscription object and adding values to the Guid Map, A Map, and B Map.

Doing a look up based on (A , B), if either A or B is null, you do the look up in the other hash table and trigger the Subscription that is returned. If Neither A nor B are null, things get more tricky.

Here, the thing to do would be to find an intersection on the sets returned by looking up A and looking up B.This can be done manually, but a speedier method might just be to have one additional map which the key is B appended to A.

bdk
Why the GUID? The OP doesn't mention the need for named connections.
Georg Fritzsche
I added the guid so there would be some key to use for the unsubscribe call. If duplicate subscriptions aren't allowed, I guess you could skip that and use a + b + e as the key for unsubscribing
bdk
I used a very similar approach... the problem here lies in the A and B maps. As a single value of A and B may point to many subscriptions, I shall use multimaps. In that situation I will have to manipulate very complexely an entry in case of unsubscription as the multimap will give you an iterator to the values associated with a key, but no means to change them. The only way is to store these values in a *list*, remove the entry, and put again those values (except the unsubscribed one) in the multimap. But all this seems so morbously complex and un-elegant... doesn't seem to be a good solution
gotch4
So your only problem with multimaps was finding an efficient approach for unsubscription? You should have mentioned that :)
Georg Fritzsche