|
Boost : |
From: Alberto Ganesh Barbati (AlbertoBarbati_at_[hidden])
Date: 2008-02-04 18:18:26
JOAQUIN LOPEZ MU?Z ha scritto:
>
> OK, I'd classify these two examples as scenarios where K and
> T contain esentially the same info but the translation
> function f() is computationally expensive. This is a valid
> context, just not the one I deem the most common. Maybe the
> particular case K!=T could be solved by a different class
> keyed_flyweight used like this (the example is similar to that
> of GoF you referred to):
>
> struct character
> {
> character(char c):c(c){}
> char c;
> };
>
> int main()
> {
> // fw_t objects are constructed from chars but are convertible
> // to character.
> typedef keyed_flyweight<char,character> fw_t;
>
> // creates an internal character('a')
> fw_t x1('a');
>
> // same shared value as x1, zero temporary character's
> fw_t x2('a');
>
> // creates an internal character('b')
> fw_t x3('b');
> }
>
> Is this approach more convincing to you? It turns out it can be
> implemented with exactly the same machinery as flyweight (i.e.
> holders, factories, locking and tracking policies), so it could
> be provided as a companion to classic flyweight<> if there is
> interest in it. The attached code shows the idea is viable, the
> prototype keyed_flyweight implemented there has all their
> aspects (holder, factory, etc.) fixed for simplicity, and lacks
> some boilerplate features, but it proves its point. The idea
> is that the factory keeps elements of type similar to
>
> entry = pair<K,T*>
>
> So, only when a new entry is created need we equip it with a
> new T, hence completely avoding T temporaries. This incurs a cost
> in the form of additional storage and a slightly more expensive
> creation process (when no duplicates are found), so we shouldn't
> take flyweight<T> as shorthand for keyed_flyweight<T,T>,
> both classes serve different scenarios and ought to be
> provided separately.
>
> Well, if you think this line of research is interesting I can
> pursue it.
First of all, thanks for having considered my feedback. I was tempted to
say that I liked the keyed_flyweight approach, but I preferred reading
the rest of the thread before replying. When I reached the post of yours
where you mention the "third" case where the keys are stored inside or
can otherwise be computed from values, I realized that maybe we could
not only get that case, but let it all happen (including the non-keyed
case) with just one flyweight class template. Here's how I see it:
1) we have two types: key_type for keys and value_type for values. The
two types can be coincident (as in your non-keyed proposal) or be
different (keyed case)
2) the constructor of flyweight semantically takes keys, not values
3) keys (not values) are fed as-is to the factory insert() method:
here's the key point, it's up to the factory to determine whether the
key is already present and if it's not present to construct the
corresponding value. There's actually no need for a find() method. The
flyweight template need not know how to compare keys with values,
actually it does not even need to know that it is happening.
Let me say it again with different words: the flyweight/factory
interface has only one method, namely insert() as in the current design.
A possible map-base factory might implement the factory::insert() method
as a double call map::find() and map::insert(), this would just be an
implementation detail of the factory, the flyweight machinery needs not
be aware of that.
4) the insert() method returns a handle
5) the factory provides a way to extract values from handles
The rest of the design would more or less stays exactly the same. The
"third" case can easily be implemented in this framework using
Boost.MultiIndex.
Does it make sense? Is there something obvious (o even less obvious :)
that I'm missing?
>
> Well, thank you for giving me plenty of food for thought :)
>
You're welcome! :-)
Ganesh
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk