Robot Dreams

Robot Dreams

Thursday, February 23. 2006

Set, Query, Result

First off, a general update. It's been a slow start to the blog, sorry about that. But I'm still recovering from a total drive failure of the machine I do most of my development work from. So it's been a hard slog to reinstall everything, especially that initial Windows install with at least 15 reboots (I was counting them and that's when I gave up). On to the subject at hand...

One of the data structures in C++ I make use of most are the associative standard containers. I use them because of the bounded algorithmic guarantees they provide. But one of the most nagging problems with them is that it is hard to do any meaningful searching once one has arranged to keep the sorted elements. Sure it's easy to find equivalent elements with for example std::set::equal_range. But if how you are sorting is anything but the element itself as a value it's rather painful to come up with the usual convoluted special value elements to do the searching for you. For example having:

struct A
{
    int type;
    std::string label;
    std::string description;
};

struct S
{
    bool operator()(
        boost::shared_ptr<A> const & a,
        boost::shared_ptr<A> const & b ) const
    {
        return a->type < b->type;
    }
};

std::multiset<boost::shared_ptr<A>,S> db;

And wanting to find out how many A's of type #2 there are. So even though the set is arrange in the most optimal way for getting that answer one is thwarted in using the property of the set only because std::multiset::count, and others, don't take anything but the an element.

With the use of some of the Boost libraries one can get around such a limitation. The idea is to replace the elements stored in the set with something more flexible, but still maintain the basic properties and advantages of directly storing the elements. With some freedom in what the elements can be one can tailor the comparison function object to handle any search one might think of, including freestanding call point functions (lambdas).

The reformulation is to use the Boost Variant and Boost Any libraries. The former as the values we store, and the latter as the values we search with. First we change the set itself to store the variant:

typedef boost::variant<boost::shared_ptr<A>,
    boost::any> V;
std::multiset<V,S> db;

With that change we can store either the original element pointer, or anything else we want through boost::any instances. Not that we ever will store a boost::any in the set, but having it as a possible value allows us to pass anything into the various set methods that take elements. But this complicates the sorting function we are using a bit as we now need to make sure we do the right thing based on the stored type. Luckily the Boost Variant library already provides a handy utility to minimize the code:

struct S
{
    bool operator()( V const & a, V const & b ) const
    {
        boost::apply_visitor(*this,a,b);
    }
    bool operator()(
        boost::shared_ptr<A> const & a,
        boost::shared_ptr<A> const & b ) const
    {
        return a->type < b->type;
    }
};

Now, the fun part. We want to be able to count the number of elements that have the type member as #2. And we can now pass that into the method:

std::cout << "#2 count = " << db.count(boost::any(2));

But to make that work we need to teach our container to interpret that kind of value as the search we want to do. To do this we will need to detect when that boost::any special value is being used and translated it to the int. Luckily the "detection" is what the boost::apply_visitor is already doing above. All we need to do is add extra comparisons for those values:

struct S
{
    // The same operators as above, plus:
    bool operator()( boost::shared_ptr<A> & a, boost::any const & b ) const
    {
        return a->type < boost::any_cast<int>(b);
    }
    bool operator()( boost::any const & a, boost::shared_ptr<A> & b ) const
    {
        return boost::any_cast<int>(a) < b->type;
    }
    bool operator()( boost::any const & a, boost::any const & b ) const
    {
        return boost::any_cast<int>(a) < boost::any_cast<int>(b);
    }
};

Technically the last method is not needed but it's good to have for completeness. Now when the count algorithm searches for the range of elements to count it will pass in to the comparison function our special boost::any value in the guise of a boost::variant and the correct comparison gets done. This allows for the perhaps more useful iteration of categorically similar elements:

std::pair<iterator,iterator> toOutput = db.equal_range(boost::any(2));
while ( toOutput.first != toOutput.second )
{
    std::cout
        << boost::get< boost::shared_ptr<A> >(*toOutput.first)->label
        << "\n";
    ++toOutput.first;
}

The above can be generalized further to handle just about any kind of search, as long as it's within the ordering of the container. But I leave that as an exercise for the reader :-)

Posted by Rene Rivera in Programming at 21:19 Comments (0) Trackbacks (0)
Defined tags for this entry: algorithms, boost, c++, programming

Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)

No comments

Add Comment

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.
You can use [geshi lang=lang_name [,ln={y|n}]][/lang] tags to embed source code snippets
E-Mail addresses will not be displayed and will only be used for E-Mail notifications

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA 1CAPTCHA 2CAPTCHA 3CAPTCHA 4CAPTCHA 5


 
Submitted comments will be subject to moderation before being displayed.
 

Calendar

Back September '10
Mon Tue Wed Thu Fri Sat Sun
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      

Archives

September 2010
August 2010
July 2010
Recent...
Older...

Categories

XML Diversions
XML Life
XML Meta
XML News
XML Politics
XML Programming



All categories

Show tagged entries

aspenxml
autostitchxml
boostxml
c++xml
cameraxml
chicagoxml
conferencexml
doorxml
drinkingxml
evanstonxml
hardwarexml
hawaiixml
kauaixml
liberalxml
panoramaxml
photoxml
planexml
politicsxml
programmingxml
robotxml
torontoxml
travelxml
weatherxml

Quicksearch

Syndicate This Blog

XML RSS 1.0 feed
XML RSS 2.0 feed
ATOM/XML ATOM 1.0 feed

Other

  • Blogrolls...
  • Blogroll Me!
  • Subscribe with Bloglines