Pioneer
Weld.h
Go to the documentation of this file.
1 // This code is in the public domain -- castanyo@yahoo.es
2 
3 #ifndef NV_MESH_WELD_H
4 #define NV_MESH_WELD_H
5 
6 #include "libs.h"
7 
8 // Weld function to remove array duplicates in linear time using hashing.
9 
10 namespace nv {
11 
12  template <class T>
13  struct Equal {
14  bool operator()(const T &a, const T &b) const
15  {
16  return a == b;
17  }
18  };
19 
21 #define NIL Uint32(~0)
22 
23  template <typename Key>
24  struct hash {
25  inline Uint32 sdbm_hash(const void *data_in, Uint32 size, Uint32 h = 5381)
26  {
27  const Uint8 *data = static_cast<const Uint8 *>(data_in);
28  Uint32 i = 0;
29  while (i < size) {
30  h = (h << 16) + (h << 6) - h + static_cast<Uint32>(data[i++]);
31  }
32  return h;
33  }
34 
35  Uint32 operator()(const Key &k)
36  {
37  return sdbm_hash(&k, sizeof(Key));
38  }
39  };
40  template <>
41  struct hash<int> {
42  Uint32 operator()(int x) const { return x; }
43  };
44  template <>
45  struct hash<Uint32> {
46  Uint32 operator()(Uint32 x) const { return x; }
47  };
48 
55  inline Uint32 nextPowerOfTwo(Uint32 x)
56  {
57  assert(x != 0);
58 #if 1 // On modern CPUs this is supposed to be as fast as using the bsr instruction.
59  x--;
60  x |= x >> 1;
61  x |= x >> 2;
62  x |= x >> 4;
63  x |= x >> 8;
64  x |= x >> 16;
65  return x + 1;
66 #else
67  Uint32 p = 1;
68  while (x > p) {
69  p += p;
70  }
71  return p;
72 #endif
73  }
74 
76  inline bool isPowerOfTwo(Uint32 n)
77  {
78  return (n & (n - 1)) == 0;
79  }
80 
86  template <class T, class H = hash<T>, class E = Equal<T>>
87  struct Weld {
88  // xrefs maps old elements to new elements
89  Uint32 operator()(std::vector<T> &p, std::vector<Uint32> &xrefs)
90  {
91  const Uint32 N = p.size(); // # of input vertices.
92  Uint32 outputCount = 0; // # of output vertices
93  Uint32 hashSize = nextPowerOfTwo(N); // size of the hash table
94  Uint32 *hashTable = new Uint32[hashSize + N]; // hash table + linked list
95  Uint32 *next = hashTable + hashSize; // use bottom part as linked list
96 
97  xrefs.resize(N);
98  memset(hashTable, NIL, (hashSize + N) * sizeof(Uint32)); // init hash table (NIL = 0xFFFFFFFF so memset works)
99 
100  H hash;
101  E equal;
102  for (Uint32 i = 0; i < N; i++) {
103  const T &e = p[i];
104  const Uint32 hashValue = hash(e) & (hashSize - 1);
105  //const Uint32 hashValue = CodeSupHash(e) & (hashSize-1);
106  Uint32 offset = hashTable[hashValue];
107 
108  // traverse linked list
109  while (offset != NIL && !equal(p[offset], e)) {
110  offset = next[offset];
111  }
112 
113  xrefs[i] = offset;
114 
115  // no match found - copy vertex & add to hash
116  if (offset == NIL) {
117  // save xref
118  xrefs[i] = outputCount;
119 
120  // copy element
121  p[outputCount] = e;
122 
123  // link to hash table
124  next[outputCount] = hashTable[hashValue];
125 
126  // update hash heads and increase output counter
127  hashTable[hashValue] = outputCount++;
128  }
129  }
130 
131  // cleanup
132  delete[] hashTable;
133 
134  p.resize(outputCount);
135 
136  // number of output vertices
137  return outputCount;
138  }
139  };
140 
141 } // namespace nv
142 
143 #endif // NV_MESH_WELD_H
#define NIL
Null index. @ Move this somewhere else... This could have collisions with other definitions!
Definition: Weld.h:21
Definition: Weld.h:10
Uint32 nextPowerOfTwo(Uint32 x)
Definition: Weld.h:55
bool isPowerOfTwo(Uint32 n)
Return true if n is a power of two.
Definition: Weld.h:76
Definition: Weld.h:13
bool operator()(const T &a, const T &b) const
Definition: Weld.h:14
Definition: Weld.h:87
Uint32 operator()(std::vector< T > &p, std::vector< Uint32 > &xrefs)
Definition: Weld.h:89
Uint32 operator()(Uint32 x) const
Definition: Weld.h:46
Uint32 operator()(int x) const
Definition: Weld.h:42
Definition: Weld.h:24
Uint32 sdbm_hash(const void *data_in, Uint32 size, Uint32 h=5381)
Definition: Weld.h:25
Uint32 operator()(const Key &k)
Definition: Weld.h:35