unordered_map

This is gonna be hard to explain.

I am learning to use some physics library. I need a unique pairs of "materials" in some container and be able to get its "interaction" value.
So i thought to use unordered_map:

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <iostream>
#include <unordered_map>

// material types
enum E_MAT_TYPE
{
	EMT_WOOD     = 0,
	EMT_CONCRETE = 1,
	EMT_WATER    = 2,
	EMT_DIRT     = 3,
	EMT_METAL    = 4
};

struct MatPair
{
	int id0;
	int id1;

	MatPair(int _id0, int _id1) : id0(_id0), id1(_id1) {}

	bool operator == (const MatPair& o) const
	{
		if((id0 == o.id0 && id1 == o.id1) || (id0 == o.id1 && id1 == o.id0))
			return true;
		return false;
	}
};

struct MatInteraction
{
	float value;
};

// from WIKI
namespace std 
{
	template <>
	class hash<MatPair>
	{
	public :
		size_t operator () (const MatPair& m ) const
		{
			return hash<int>()(m.id0) ^ hash<int>()(m.id1);
		}
	};
}

class MatInterManager
{
private:
	std::unordered_map<MatPair, MatInteraction> mMat;
	MatInteraction                              defInteraction; // default
public:
	MatInterManager()
	{
		defInteraction.value = 0.0f; 
	}
	MatInteraction getInteraction(int id0, int id1)
	{
		auto it = mMat.find(MatPair(id0, id1));
		if(it != mMat.end())
			return (*it).second;
		return defInteraction;
	}
	void addInteraction(int id0, int id1, const MatInteraction& mInt)
	{
		mMat[MatPair(id0, id1)] = mInt;
	}
};

int main()
{
	MatInteraction intWoodConcrete = { 1.0f };
	MatInteraction intWoodWater    = { 2.0f };
	MatInteraction intWoodDirt     = { 3.0f };
	MatInteraction intWoodMetal    = { 4.0f };

	MatInterManager mgr;
	mgr.addInteraction(EMT_WOOD, EMT_CONCRETE, intWoodConcrete);
	mgr.addInteraction(EMT_WOOD, EMT_WATER,    intWoodWater);
	mgr.addInteraction(EMT_WOOD, EMT_DIRT,     intWoodDirt);
	mgr.addInteraction(EMT_WOOD, EMT_METAL,    intWoodMetal);

	auto inter0 = mgr.getInteraction(EMT_DIRT, EMT_WOOD);
	std::cout << "DIRT + WOOD = " << inter0.value << std::endl;

	auto inter1 = mgr.getInteraction(EMT_DIRT, EMT_DIRT);
	std::cout << "DIRT + DIRT = " << inter1.value << std::endl; // should return default

        ...

	return 0;
}


I am worried about hash function witch i used from WIKI article.
Am i guaranteed a unique pairs with this? Or you have better idea?

Thank you for your time.
> Or you have better idea?

boost::hash_combine()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <unordered_map>
#include <boost/functional/hash.hpp>

using MatPair = std::pair<int,int> ;

struct hash_MatPair
{
    std::size_t operator() ( const MatPair& m ) const
    {
        std::size_t s = 0 ;
        boost::hash_combine( s, m.first ) ;
        boost::hash_combine( s, m.second ) ;
        return s ;
    }
};

using MatInteraction = float ;

class MatInterManager
{
    std::unordered_map< MatPair, MatInteraction, hash_MatPair > mMat;
    // ...
};


Looks like seed for hash combine must be in same order, i need hash function for pair of ints such that :
pair(EMT_WOOD, EMT_METAL) == pair(EMT_METAL, EMT_WOOD)

and can be same, for example: pair(EMT_WOOD, EMT_WOOD), if that is relevant.
> i need hash function for pair of ints such that :
> pair(EMT_WOOD, EMT_METAL) == pair(EMT_METAL, EMT_WOOD)

Then the hash function needs to be symmetric. XOR is symmetric, but it can generate a large number of collisions.

Perhaps something like this:

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
31
32
#include <unordered_map>
#include <functional>

// material types
enum E_MAT_TYPE : unsigned char
{
	EMT_WOOD     = 0,
	EMT_CONCRETE = 1,
	EMT_WATER    = 2,
	EMT_DIRT     = 3,
	EMT_METAL    = 4
};

using MatPair = std::pair< E_MAT_TYPE, E_MAT_TYPE > ;

struct hash_MatPair
{
    std::size_t operator() ( const MatPair& m ) const
    {
        const int a = m.first+1 ;
        const int b = m.second+1 ;
        return std::hash<int>()( a*b + (a+b) ) ;
    }
};

using MatInteraction = float ;

class MatInterManager
{
    std::unordered_map< MatPair, MatInteraction, hash_MatPair > mMat;
    // ...
};

Topic archived. No new replies allowed.