Friday, October 31, 2008

C/C++ __gnu_cxx hash_set

In this post, we go about __gnu_cxx::hash_set. As we saw before, we need to define our own HashFcn. We'll also need to define EqualKey if we're using custom data types. Another workaround is to overload the == operator inside the std namespace, then you don't have to provide your own EqualKey. It should look like:

namespace std {
bool operator==(const dnsRecord& rec1, const dnsRecord& rec2) {
return rec1.ip == rec2.ip;
}
}
However, I prefer the first solution, and we'll use it in the code below. We also define our own hasher and pass it to the hash_set declaration instead of specializing the hash template inside the __gnu_cxx namespace as we did in the previous post.
#include <iostream>
#include <ext/hash_set>

using namespace std;
using namespace __gnu_cxx;

class dnsRecord {
public:
unsigned long ip;
string domainName;
};

class MyHasher {
public:
size_t operator()(const dnsRecord &r) const
{
return h(r.domainName.c_str());
};

private:
__gnu_cxx::hash<char*> h;
};

class MyComparator
{
public:
bool operator()(const dnsRecord& rec1, const dnsRecord& rec2) const {
return rec1.ip == rec2.ip;
}
};

int main(int argc, char *argv[])
{
hash_set<dnsRecord, MyHasher, MyComparator> hset;
dnsRecord rec1;
dnsRecord rec2;
dnsRecord rec3;
rec1.ip = 989798l; rec1.domainName = "dname1";
rec2.ip = 112334l; rec2.domainName = "dname2";
rec2.ip = 808323l; rec3.domainName = "dname3";
hset.insert(rec1);
hset.insert(rec2);
hset.insert(rec3);

dnsRecord rec4;
rec4.ip = 0;
rec4.domainName = "dname1";

hash_set<dnsRecord, MyHasher, MyComparator>::iterator it;
for(it = hset.begin(); it != hset.end(); it++)
cout << (*it).ip << ", " << (*it).domainName << endl;

rec4.domainName = "dname3";
hset.erase(rec4);

rec4.domainName = "dname3";
if(hset.find(rec4) == hset.end())
cout << "Successfully removed dname3" << endl;
else
cout << "Error!" << endl;

return EXIT_SUCCESS;
}

3 comments:

Partheneus said...

ı defined a equal class and according to this ı insert nodes into the set.

bool Equal::operator()( Node n1, Node n2){
return n1.name.compare(n2.name)==0;
}

after ı inserted nodes into the set, ı want to change the content of the node.
clearly , ı want to add info to the vector field of node that ı already inserted into the set.

how can ı do that?

Partheneus said...

to explain clearly ı am reading a file and then ı am getting data,
data 1: name of node(string)
data 2: child info (will be stored in the vector field of node)

set.insert("kevin"); //but this has vector a
set.inset("kevin");// this has vector b

because their name is the same only first one included in the set.

ı want the set to have node "kevin" includin both a and b vector elemnts.

ı hope ı could explain my problem.

ı really need help, thank you for your hand ....

Ahmed Abdelkader said...

@Partheneus: per your definition of equality, the two nodes are considered the same as both have the same name. This explains the behavior you're getting now. As for what you're trying to achieve, you could retrieve the existing node -if any- then add the new contents to its vector. If that doesn't work, you'll probably need to consider different data structures for your problem. I hope this helps. You should also check stackoverflow.com for more questions and answers. Good luck :)