See the User’s Guide for more discussion.
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.
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):
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.
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
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.
locked_commission classThe 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.)
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.
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.
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.