9b163cf86010952ab40289682763657228842ef2
[ginac.git] / ginac / hash_seed.h
1 /** @file hash_seed.h
2  *
3  * Type-specific hash seed. */
4
5 #ifndef GINAC_HASH_SEED_H
6 #define GINAC_HASH_SEED_H
7
8 #include <typeinfo>
9 #include <cstring>
10 #include "utils.h"
11 #ifdef _WIN32
12 #define GINAC_HASH_USE_MANGLED_NAME 1
13 #endif
14
15 #ifdef GINAC_HASH_USE_MANGLED_NAME
16 #include "crc32.h"
17 #endif
18
19 namespace GiNaC
20 {
21 /**
22  * We need a hash function which gives different values for objects of
23  * different types. Hence we need some unique integer for each type.
24  * Fortunately, standard C++ RTTI class `type_info' stores a pointer to
25  * mangled type name. Normally this pointer is the same for all objects
26  * of the same type (although it changes from run to run), so it can be
27  * used for computing hashes. However, on some platforms (such as woe32)
28  * the pointer returned by type_info::name() might be different even for
29  * objects of the same type! Hence we need to resort to comparing string
30  * representation of the (mangled) type names. This is quite expensive,
31  * so we compare crc32 hashes of those strings. We might get more hash
32  * collisions (and slower evaluation as a result), but being a bit slower
33  * is much better than being wrong.
34  */
35 #ifndef GINAC_HASH_USE_MANGLED_NAME
36 static inline unsigned make_hash_seed(const std::type_info& tinfo)
37 {
38         // This pointer is the same for all objects of the same type.
39         // Hence we can use it.
40         const void* mangled_name_ptr = (const void*)tinfo.name();
41         unsigned v = golden_ratio_hash((uintptr_t)mangled_name_ptr);
42         return v;
43 }
44 #else
45 static unsigned make_hash_seed(const std::type_info& tinfo)
46 {
47         const char* mangled_name = tinfo.name();
48         return crc32(mangled_name, std::strlen(mangled_name), 0);
49 }
50 #endif
51 } // namespace GiNaC
52 #endif /* GINAC_HASH_SEED_H */
53
54