Tangleman
Tangleman

Reputation: 1

C++ container of structs needed for dual access find operations

I have a structure that I need to put into a container in C++. here is the struct:

struct PDCUTestMessage
{
string name;
unsigned char id;
int numberOfParameters;
string param1Name;
string param2Name;
string param3Name;
string param4Name;
string param5Name;
boost::function<void(vector<unsigned char>)> process;
PDCUTestMessage();
PDCUTestMessage(string_name, unsigned char _id, int _numberOfParameters, boost::function<void(vector<unsigned char>)> _process): name(_name), id(_id), numberOfParameters(_numberOfParameters), process(_process){}
};

I will need about 65 of these structs, so I'm looking to put them into a container (I'm thinking a list, a vector, or a map). I need to be able to access the function pointer (process) of a given PDCUTestMessage via two different search values: name and id. I noticed that map only allows one value and one key. Is there any container that would allow me to quickly search for a PDCUTestMessage use either name or id as a key? And how would I write the search and access the function that the pointer is pointing to?

I hope this makes sense. Let me know if you need further clarification.

Thanks!

Upvotes: 0

Views: 273

Answers (3)

murrekatt
murrekatt

Reputation: 6129

As already mentioned Boost.MultiIndex is one way to approach a problem like this. It's very powerful and fast, but in most cases it just means slow compilation and complex code while not getting much other benefits.

65 items is not really much and as Mark Ransom mentioned a linear search could work well enough for what you're doing. This you need to measure.

Another way to do things is to have a std::vector hold the messages (65 messages) and then you can have two separate containers you use for lookup: first is id-to-index and second is name-to-index. The index is the position of the message in the vector. Something like this:

class YourContainerClass
{
public:
    bool lookupById(unsigned char id, PDCUTestMessage& message)
    {
        std::map<unsigned char, int>::iterator it = idToIndexMap.find(id);
        if (it == idToIndexMap.end())
            return false;
        message = messages[*it];
        return true;
    }

    bool lookupByName(const std::string& name, PDCUTestMessage& message)
    {
        std::map<std::string, int>::iterator it = nameToIndexMap.find(id);
        if (it == nameToIndexMap.end())
            return false;
        message = messages[*it];
        return true;
    }

private:
    std::vector<PDCUTestMessage> messages;
    std::map<unsigned char, int> idToIndexMap;
    std::map<std::string, int> nameToIndexMap;
};

To manage the internal containers your insert must do the work to push_back in the messages vector and at the same time insert into the two maps the corresponding things to find the index in the vector from id and name.

This is just one way what the API would look like. You could also wrap the messages in boost::shared_ptr to get a bit different API. This is a bit outside the question of yours, because I also don't know how you intend to use the messages and their lifetimes.

I would say even if Boost.MultiIndex is a very cool container it should not be the first option. There are many ways to do this and it comes down the specific problems what makes most sense.

Hope you find what makes most sense to you.

Upvotes: 0

Mark Ransom
Mark Ransom

Reputation: 308206

With only 65 items in your container, a simple linear search may be fast enough for your needs. Use the name as the key for your map (or set) and use std::find when you need to search by id.

Upvotes: 0

Cubbi
Cubbi

Reputation: 47428

Since you're already using boost, the boost.multi-index container library may be of use here. In particular, consider the examples in the Multiple sort tutorial section.

Upvotes: 1

Related Questions