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;
}

Tuesday, October 28, 2008

C/C++ __gnu_cxx hash_map

I had some trouble getting this to work, so I decided to post a quick tutorial...

We start with a simple hash_map with int keys and string values:

#include <iostream>
#include <ext/hash_map>

using namespace std;
using namespace __gnu_cxx;

int main(int argc, char *argv[])
{
//declaration
hash_map<int, string> hmap;

//insertion
int ints[] = {213, 432, 45, 10};
string strings[] = {"s1", "s2", "s3", "s4"};

for(int i = 0; i < 4; i ++)
hmap[ints[i]] = strings[i];

//iteration
for(hash_map<int, string>::iterator it = hmap.begin(); it != hmap.end(); it ++)
cout << (*it).first << " => " << (*it).second << endl;

//deletion
hmap.erase(ints[0]);
cout << "Removed: " << ints[0] << endl;

//search
if(hmap.find(ints[0]) == hmap.end())
cout << "Couldn't find: " << ints[0] << endl;

if(hmap.find(ints[1]) != hmap.end())
cout << "Found: " << ints[1] << ": " << hmap[ints[1]] << endl;

return EXIT_SUCCESS;
}
It gets a little bit messy when using string keys. Since hash_map is not part of the standard STL, there're some issues you need to worry about. In our case, there's no implementation provided for hash, or in other words, the hash_map can't hash strings by default. Strangely though, hash is defined for char*, and we'll make use of that fact.

You can either specialize the hash template for std::string inside the __gnu_cxx namespace or define your own hash functor and use it in your hash_map declaration. Remember that hash_map is declared as hash_map<Key, Type, HashFcn, EqualKey, Alloc>. I prefer the second solution, you can check it out here. For now, we'll go on with the first one.
#include <iostream>
#include <ext/hash_map>

using namespace std;
using namespace __gnu_cxx;

namespace __gnu_cxx {
template<>
struct hash<std::string>
{
hash<char*> h;
size_t operator()(const std::string &s) const
{
return h(s.c_str());
};
};
}

typedef struct {
int x;
int y;
} point;

int main(int argc, char *argv[])
{
//declaration
hash_map<string, point> hmap;

//insertion
string strings[] = {"p1", "p2", "p3", "p4"};

point a, b, c, d;
a.x = a.y = 0;
b.x = b.y = 1;
c.x = c.y = 2;
d.x = d.y = 3;

hmap[strings[0]] = a;
hmap[strings[1]] = b;
hmap[strings[2]] = c;
hmap[strings[3]] = d;

//iteration
for(hash_map<string, point>::iterator it = hmap.begin(); it != hmap.end(); it ++)
cout << (*it).first << " => (" << (*it).second.x << ", " << (*it).second.y << ")" << endl;

//deletion
hmap.erase(strings[1]);
cout << "Removed: " << strings[1] << endl;

//search
if(hmap.find(strings[1]) == hmap.end())
cout << "Couldn't find: " << strings[1] << endl;

if(hmap.find(strings[0]) != hmap.end())
cout << "Found: " << strings[0] << ": (" << hmap[strings[0]].x << ", " << hmap[strings[0]].y << ")" << endl;

return EXIT_SUCCESS;
}

Repair Network Connection in Ubuntu

I'm running Ubuntu 8.04 under VirtualBox on Vista. I've created a virtual network interface for the vm and bridged my network connections. The network connection was down for a while, so when I started vm there was no connection. After a while however, the connection was restored and I was able to use it on Vista. The problem is, the vm didn't feel that the connection was restored. I googled for that and got a useful thread on ubuntuforums. I applied the solution I found there and added a launcher to my panel.

Right-click the panel -> "Add to Panel..." -> "Custom Application Launcher" then enter:

Type: Application
Name: NetRepair
Command: gksudo /etc/init.d/networking restart
Comment: Repair Network Connection
Click OK.

The launcher should appear on your panel. When you click the icon, it'll run the command you entered and will ask for your password. Hopefully, this should 'repair' your network connection.

btw, this is my first post from ubuntu!