message_parliament

See the Userís Guide for more discussion.


void add (const commission&)

message_parliament

public

This adds the specified commission to the list of commissions making up this parliament, sorted by the low 16 bits of its schedule member. If there are identical schedule values, the order is unspecified. If you really need to control the order, use different values; the common schedule_t values are spread very far apart to give you room to make each one unique if necessary.

It is allowed to add multiple copies of the same commission, even if all the fields are the same. That would not be very useful, however. Normally something will be different: different ministers working on the same job, or the same minister looking at the message both early and late in the list. The very purpose of the id field is to let you tell them apart when there are multiple commissions for the same minister.

Calls to add and remove are serialized when calls are made from different threads. Calls to add and remove will not affect an in-progress traversal of the list from a running call to handle_message, from the same or different thread (but see notes in ministerís Userís Guide for advanced techniques).

See also: remove.


locked_commission add (minister*, message_range)

locked_commission add (minister*, message_range, schedule_t, int id= 0)

message_parliament

public

These forms of the add function (you can pass 2, 3, or 4 arguments) can be handier than the form that passes a structure, and is more efficient too. Consider the code (Listing 1):

Listing 1

commission c;
c.appointed_minister= this;  // assigns pointer to baro
c.range= theRange;
c.schedule= low(Normal);
c.id= 1;
add (c);

The call to add causes the commission structure to be copied into the list, which means the copy constructor is called on the baro. The value of c.appointed_minister had to be created to begin with, and later destructed. Manipulating a baro involves atomic operations, which are very expensive to the CPU.

By passing in the raw pointer and letting add assign it directly to its final location in the array, it saves the constructor and destructor of c, eliminating two atomic operations.

Listing 2

add (this, theRange, low(Normal), 1);

This call to add with individual parameters (Listing 2) will accomplish the same thing, without the need to create a local structure.

If you do need to do something else to the commission that is not covered by the parameters, you can still use this form! The function returns a pointer to the actual location to which it was added in the list, and you can manipulate the values in-place. However, this opens up thread-safety issues, that are discussed in detail under the find function. Suffice to show a couple examples here, and assure you that the thread safety is fully automatic:

add (this, theRange, low(Normal), 1) ->rangefunc=theFunc;

locked_commission c= add (theMinister, theRange);
c->id= 2;
c->appointed_minister.own(true);  // set ownership flag of the baro

locked_commission find (const minister*, int id=-1)

message_parliament

public

This function returns a pointer to the location of the matching commission in the list. If there is more than one (not a normal situation—if the same minister is inserted multiple times in the same list, they should have distinct ids so the minister can tell which context it is being called in) it returns a pointer to one of them with no error or indication that it is not unique. If there is no match, the return value will evaluate as a boolean false, just like a primitive pointer type.

There are inherent threading issues with having a pointer into the list, since other threads may call add or remove while this thread is still holding it. In this design, that is not to be tolerated! Obviously, you can use the listlocker to explicitly deal with it, but you donít even need to do that because the code is fully automated, by the use of a proxy object instead of the raw pointer.

The locked_commission class

The return value from find and from add is a value of the locked_commission class, which acts like a pointer to the underlying commission, but also implements a destructor to release the lock when it goes out of scope.

locked_commission c= find (theMinister);  // locate my commission record
if (!c)  return;  // acts like a null pointer if not found
c->appointed_minister= differentMinister;   // can change anything!
c->id= 2;
c->range << WM_WhatEver;
c->schedule= always(c->schedule);  // but use care changing this one
// when c goes out of scope, the lock is released.

You should use care in changing the value of schedule in-place, since the list is sorted by this value. It makes sence to set or clear the flag bits like ďalwaysĒ that donít affect the actual ordering, and it is well-behaved to change the schedule value such that it doesnít change the commissionís order in the list. But changing the schedule value to produce an out-of-order list will cause the list ordering to not be maintained properly thereafter. (Note that this is the limit of the mis-behavior. The message_parliament will not itself cause a bad pointer, memory leak, or anything undefined. What your ministers do when called in the wrong order is out of my hands.)


long handle_message (sMSG& msg)

message_parliament

public, virtual

This matches the signature of the function in class message_tap, and you can think of this function as overriding it, but this class does not derive from message_tap. The intention is that a class (such as eagduru) will derive from both message_tap and message_parliament, with code in the former calling code in the latter. But the classes are unrelated! Such is the magic of virtual functions in virtual base classes. When the two classes do wind up being part of the same concrete class, the implementation will realize that they are the same function. However, you can link any choice of calling sibling (e.g. an alternative to message_tap) and any choice of implementing sibling (e.g. an alternative to message_parliament) and get the same effect. You can aggregate different produces and consumers using the same interface with a horizontal mix-in approach, rather than a vertical chain of derived classes, and acheive much greater code reuse with flexibility in choosing features. This is a primary architectural concept in Tomahawk.

This function is implemented to iterate through the list of commissions (added by calls to add) and call the associated ministerís administer_message function, if applicable, to actually handle this message.

See the Userís Guide for details about the iteration and discussion of advanced techniques.


WNDPROC_sig OldWndProc

message_parliament

protected, data

This will be called by handle_message if no commissioned minister handled the message.

Set it to the original WndProc of the window that was hooked by message_tap. If deriving from both classes, message_parliament::OldWndProc=get_old_wndproc(); called from on_attach will do.


int remove (const minister*, int id=-1)

message_parliament

public

This removes commissions from the list of commissions making up this parliament. It will remove those that match the minister and id field, or when id is -1, all commissions for the minister regardless of id. It returns the number of commissions that were removed, which might be zero.

See threading notes under add.