
----- Original Message ----- From: "Douglas Gregor" <gregod@cs.rpi.edu> To: <boost@lists.boost.org> Sent: Wednesday, March 17, 2004 9:22 AM
This is the slot ordering issue again :) If you insert with a group that precedes the group being called, it will not be called during that invocation. If you insert with a group that follows the gorup being
called,
it will be called during that invocation. If you insert in the same group as the one being called, you don't know because there is no guaranteed ordering within a group [*].
I see... makes sense to me.
Which operation's complexity are you concerned about? I've never heard
of
a
performance problem...
Sometimes, from the event property values, the signal source can tell what slot exactly or subset of slots need to be called and that other slots should not be bothered with this event instance. In what case the signal source should havea random access to the slots. Otherwise it will have to propagate the event to *all* slots and let them decide on what to do. If the number of slots is not too big, this works just fine. However if the number of slots is huge, the optimization is important and one of the optimized solutions will most likely require a random access to slots based on the slot index and slot ordering support, including slot insertions at specified positions in the slot list.
Ok, I understand this. I thought you were referring to a different source of inefficiency.
In any case, getting random access (traversal) iterators and fast ordered insertions/deletions is not a trivial task. Did you have some particular data structure in mind that could do this?
I guess it could be something like tree (balanced, Red-Black whatever). But, I'd let the user to define the container type.
Here is a question for you: would the ability to invoke only the slots
within
a particular group solve this problem? That is implementable within the current semantics, although it will not give random access.
Bingo. It'll give me a control over how the slots are called. Then, what I can do is associate my group numbers with the items. //physical list box callback void on_lisbox_event( event e ); listbox lb(on_lisbox_event); //physical listbox interface signal<event> sig; void connect_item( item i ) { int group = generate_uniq_group_number(); //add the item label to the listbox int index = lb.add(i.label()); //returns the new item index //set my user data associate with the label lb.set_user_data( index, group ); //make connection sig.connect( group, i ); } void on_lisbox_event( event e ) { //index of the item that generated this event int index = e.get_index(); //get the group int group = lb.get_user_data( index ); //send event to the item sig( e, group ); } The set_user_data()/get_user_data() function is the key. Except generate_uniq_group_number() (which is not going to be pretty), it should work. Will signals automatically free resources for groups that are empty? A question about combiner: struct combiner { template<typename InputIterator> T operator()(InputIterator first, InputIterator last) const; }; Are [first,last] iterators ordered by the group number? [...]
You might be better off with a vector of boost::function objects.
Yes, I thought about it too. However I'd like to have the "trackable" feature.
I'd say that instead of changing the existing signals semantic to support the slot ordering and random slot access, I would make it possible to access and call slots that are referenced by signals::connection objects and leave the rest to the user. In a way, it is just an extension to the combiner semantic. Indeed with combiner, the user can propagate the event as she likes anyway except that she has no idea what slot is what (it is really strange to me).
You usually can't tell what slots you're calling anyway, because type information is lost to the user once you've connected the slot. The point
of
a callback is that you don't know where you're calling back to.
It is not always the case. For example Win32 supports the so called callback chains so you know where in the chain you are. Even more... from your callback, you can make a call that will send the event down the chain then it will return and your callback can do something else. People use this technique all the time. To make signals usable for serious GUI development, I think that it should support something like this. [...]
I'll try to give a real life example once again. In Win32 the standard listbox control can generate messages that have the listbox item index as one of the message parameters. Imagine that each item in the listbox is implemented as a signal slot. How would you propagate the Win32 messages that are targeting separate listbox items
If we had the ability to invoke only the slots that were part of a
particular
group, you would make the group the listbox item number. Slots that are interested in all item numbers would not have any group; slots interested in a particular item number would be in that group. Item numbers aren't all that great to use, because items can be inserted or deleted. You'd probably be better off using some other form of identifier for list items.
It's a bit of a strange problem. I don't believe that random access
Yes, something like this (see my example above). traversal
iterators are the right answer; calling via a signals::connection derived class is rather redundant, because you'd be cloning the signal's internal ordering.
I will be imposing my own ordering, not cloning the signal's ordering that I don't know anyway.
Invocation of slots in a particular group might do it for you, but only if you don't need to deal with, e.g., slots that accept a subrange of item index numbers.
I need to build something like callback chains as well. I guess that I'll have to do some not very pretty tricks... but yes, it should do it for me. Eugene