This file is indexed.

/usr/include/mathic/HashTable.h is in libmathic-dev 1.0~git20160320-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
// MathicGB copyright 2012 all rights reserved. MathicGB comes with ABSOLUTELY
// NO WARRANTY and is licensed as GPL v2.0 or later - see LICENSE.txt.


// issues:
//  1. memory management of nodes
//  2. statistics gathering
//  3. resizing
//  4. put ASSERT's in, to check for all manner of contracts

// Notes to self:
// see http://attractivechaos.wordpress.com/2008/08/28/comparison-of-hash-table-libraries/

#ifndef MATHIC_HASHTABLE_GUARD
#define MATHIC_HASHTABLE_GUARD

#include "stdinc.h"

#include <memtailor.h>
#include <cmath>
#include <utility>
#include <string>

namespace mathic {

  template<class Configuration> 
  class HashTable;

  class BasicHashTableConfiguration {
    typedef int Key;
    typedef int Value;

    size_t hash(Key k);
    bool keysEqual(Key k1, Key k2);
  };

  template<class Configuration> 
  class HashTable;

  template<class C> 
  class HashTable {
  public:
    typedef C Configuration;
    typedef typename C::Key Key;
    typedef typename C::Value Value;

    // Allowed actions for a Node* returned by lookup or insert:
    //  1. Key is const, while the Node* is in the hash table.
    //  2. Value can be modified by the callee at any time
    //  3. The 'next' field should not be referenced.
    // As for allocating and deallocating Node*:
    //  Do not allocate your own: only use Node* 's returned by the package
    //  There is no need to deallocate a Node*:  when a 'reset() is done, all
    //   Node* 's which have been allocated are deallocated at one time.
    //   When this happens, the Key and Value are not deallocated?
    // If 'remove' returns a Node*, then it is safe to change the key and/or value, e.g.
    //  to free the space pointed to by 'key' (if that is a pointer value, for instance).

    class Handle {
    public:
      friend class HashTable;

      Handle(Key k, Value v):
	next(0),
	entry(k,v)
      {}

      const Key& key() const {return entry.first;}
      const Value& value() const {return entry.second;}
      Value& value() {return entry.second;}
      void setKeyButOnlyDoSoIfThisHandleIsNotInHashTable(Key &new_k) {entry.first=new_k;}
    private:
      Handle *next;
      std::pair<Key, Value> entry;
    };

    // Create a hash table
    HashTable(const Configuration &conf, unsigned int nbits = 10);

    ~HashTable() {}

    // Returns the stored configuration.
    Configuration& configuration() {return mConf;}
    
    // Returns the stored configuration.
    Configuration const& configuration() const {return mConf;}

    // insert the key 'k' into the hash table.  If the key is already there,
    // and return std::pair(false, ...)
    // else return std::pair(true, node in the hash table).
    std::pair<bool, Handle*> insert(Key const& k, Value const& v);

    // If 'k' is present in the hash table, then its 'Node*' is returned.
    // If not, then NULL is returned.
    Handle* lookup(const Key &k);

    // remove 'p' from the hash table.  'p' itself is also removed.
    // what about the entries in 'p'?  Are the destructors called?
    void remove(Handle* & p);

    void reset(); // Major assumption: all nodes have been removed from the table already

    void hardReset(); // Slow, avoid if possible.

    // Returns how many bytes of memory this data structure consumes
    // not including sizeof(*this).
    size_t memoryUse() const;
    
    // Returns a string that describes how this data structure was
    // configured.
    std::string name() const;

  private:
    Handle* makeNode(const Key &k, const Value &v);

    void grow(unsigned int nbits);

    // Used for consistency checking.  Returns the number of nodes in the table.
    // Should match mNodeCount.
    size_t computeNodeCount() const;

    // Used for consistency checking.  Returns the number of nonempty bins in the hash table.
    // Should match mBinCount.
    size_t computeBinCount() const;
  
    size_t mHashMask; // this is the number, in binary:  00001111...1, where
                      // the number of 1's is mLogTableSize
    size_t mTableSize;
    size_t mLogTableSize; // number of bits in the table: mTableSize should be 2^mLogTableSize

    size_t mNodeCount;  // current number of nodes in the hash table
    size_t mBinCount; // number of nonzero bins

    size_t mMaxCountBeforeRebuild;

    // tweakable parameters
    double mRebuildThreshold;
    bool mAlwaysInsertAtEnd;

    memt::BufferPool mNodePool;
    std::vector<Handle *> mHashTable;
    Configuration mConf;
  };

  template<class C>
  HashTable<C>::HashTable(const Configuration &conf, unsigned int nbits):
    mLogTableSize(nbits),
    mTableSize(static_cast<size_t>(1) << nbits),
    mHashMask((static_cast<size_t>(1) << nbits) - 1),
    mNodeCount(0),
    mBinCount(0),
    mRebuildThreshold(0.1),
    mAlwaysInsertAtEnd(true),
    mNodePool(sizeof(Handle)),
    mConf(conf) 
  {
    mHashTable.resize(mTableSize);
    mMaxCountBeforeRebuild = static_cast<size_t>(mRebuildThreshold * mTableSize);
  }
  
  template<class C>
  void HashTable<C>::reset() {
    mNodePool.freeAllBuffers();
  }

  template<class C>
  typename HashTable<C>::Handle *HashTable<C>::makeNode(const Key &k, const Value &v)
  {
    mNodeCount++;
    void *buf = mNodePool.alloc();
    Handle* result = new (buf) Handle(k,v);
    return result;
  }

  template<class C>
  std::pair<bool, typename HashTable<C>::Handle *> HashTable<C>::insert(const Key &k, const Value &v) 
  {
    size_t hashval = mConf.hash(k) & mHashMask;
    
    MATHIC_ASSERT(hashval < mHashTable.size());
    Handle *tmpNode = mHashTable[hashval];
    Handle *result = 0;
    if (tmpNode == 0)
      {
	result = makeNode(k,v);
	mHashTable[hashval] = result;
      }
    else
      {
	while (true)
	  {
	    if (mConf.keysEqual(tmpNode->key(), k))
	      {
		result = tmpNode;
		return std::pair<bool,Handle *>(false,result);
	      }
	    if (tmpNode->next == 0)
	      {
		// time to insert the monomial
		result = makeNode(k, v);
		if (mAlwaysInsertAtEnd)
		  {
		    tmpNode->next = result;
		  }
		else
		  {
		    result->next = mHashTable[hashval];
		    mHashTable[hashval] = result;
		  }
		break;
	      }
	    tmpNode = tmpNode->next;
	  }
      }
    
    if (mNodeCount > mMaxCountBeforeRebuild)
      grow(static_cast<unsigned int>(mLogTableSize + 2));  // increase by a factor of 4??
    
    MATHIC_ASSERT(computeNodeCount() == mNodeCount);
    return std::pair<bool, Handle *>(true,result);
  }

  template<class C>
  typename HashTable<C>::Handle * HashTable<C>::lookup(const Key &k)
  {
    size_t hashval = mConf.hash(k) & mHashMask;
    
    MATHIC_ASSERT(hashval < mHashTable.size());
    for (Handle *p = mHashTable[hashval]; p != 0; p = p->next)
      {
	if (mConf.keysEqual(p->key(), k))
	  return p;
      }
    return NULL;
  }
    
  template<class C>
  void HashTable<C>::remove(Handle *& p) 
  {
    mNodeCount--;
    size_t const hashval = mConf.hashvalue(p->key) & mHashMask;
    Handle head;
    Handle* tmpNode = mHashTable[hashval];
    head.next = tmpNode;
    for (Handle* q = &head; q->next != 0; q = q->next) 
      {
	if (q->next == p) 
	  {
	    q->next = p->next;
	    mHashTable[hashval] = head.next;
	    if (head.next == 0) mBinCount--;
	    //TODO: call destructor for pair, then call 'free' with the mNodePool
	    return;
	  }
      }
    // If we get here, then the node is not at its supposed hash value.
    // That probably means either that the node has been deleted twice
    // or that the value in the node changed so that its hash value
    // changed. That is not allowed.
    MATHIC_ASSERT(false);
  }
  
  template<class C>
  void HashTable<C>::grow(unsigned int new_nbits) 
  {
    MATHIC_ASSERT(computeNodeCount() == mNodeCount);
    size_t const old_table_size = mTableSize;
    mTableSize = static_cast<size_t>(1) << new_nbits;
    mLogTableSize = new_nbits;
    mHashMask = mTableSize-1;
    std::vector<Handle *> old_table(mTableSize);
    std::swap(old_table, mHashTable);

    mBinCount = 0;
    for (size_t i = 0; i < old_table_size; ++i)
      {
	Handle *p = old_table[i];
	while (p != 0)
	  {
	    Handle *q = p;
	    p = p->next;
	    q->next = 0;
	    // Reinsert node.  We know that it is unique
	    size_t hashval = mConf.hash(q->key()) & mHashMask;
	    Handle *r = mHashTable[hashval];
	    if (r == 0) mBinCount++;
	    if (r == 0 || !mAlwaysInsertAtEnd) 
	      {
		q->next = r;
		mHashTable[hashval] = q;
	      }
	    else
	      {
		// put it at the end
		for ( ; r->next != 0; r = r->next) { }
		r->next = q;
	      }
	  }
      }
    
    mMaxCountBeforeRebuild =
      static_cast<size_t>(std::floor(mTableSize * mRebuildThreshold));
    
    MATHIC_ASSERT(computeNodeCount() == mNodeCount);
  }

  template<class C>
  size_t HashTable<C>::memoryUse() const
  {
    size_t result = mHashTable.capacity() * sizeof(Handle *);
    result += mNodePool.getMemoryUse();
    return result;
  }
  
  template<class C>
  size_t HashTable<C>::computeNodeCount() const
  {
    size_t result = 0;
    for (size_t i=0; i<mTableSize; i++)
      {
	for (Handle *p = mHashTable[i]; p != 0; p = p->next) result++;
      }
    return result;
  }

  template<class C>
  size_t HashTable<C>::computeBinCount() const
  {
    size_t result = 0;
    for (size_t i=0; i<mTableSize; i++)
      {
	if (mHashTable[i] != 0) result++;
      }
    return result;
  }

  template<class C>
  std::string HashTable<C>::name() const
  {
    return std::string("HashTable");
  }
  
} // namespace mathic

#endif

// Local Variables:
// indent-tabs-mode: nil
// mode: c++
// compile-command: "make -C $MATHIC/mathic "
// End: