#ifndef __AST_HASH_TABLE_H #define __AST_HASH_TABLE_H #include #include #ifndef WIN32 #include #endif #include <5D/Values> //#include #include #include #include namespace Values { struct hashstr { uint32_t jenkins_one_at_a_time_hash(const char *key, size_t len) const { uint32_t hash, i; for(hash = i = 0; i < len; ++i) { hash += key[i]; hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash; } unsigned long operator()(const char* str) const { return(jenkins_one_at_a_time_hash(str, strlen(str))); } }; struct eqstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) == 0; } }; struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; ////typedef std::unordered_map, eqstr, gc_allocator > > RawHashtable; ////typedef __gnu_cxx::hash_map, eqstr, gc_allocator > > RawHashtable; //typedef std::map > > RawHashtable; //// has no allocator: typedef khmap_t > > RawHashtable; typedef enum { HS_FREE, HS_OCCUPIED, HS_FREE_AGAIN, } HashtableEntryState; template struct HashtableEntry { HashtableEntryState state; K first; // key. Idiotic name because of interface compability. V second; // value. Idiotic name because of interface compability. }; /* Key Value Hasher Comparator */ template class RawHashtable : public Values::Node { private: HashtableEntry* entries; /* or std::vector, for that matter */ int capacity; int count; inline unsigned int hash(const K& k) const { return (unsigned int) H()(k); } inline struct HashtableEntry* findEntry(const K& key) const { if(capacity == 0) return(NULL); int index = hash(key) % capacity; struct HashtableEntry* entry = &entries[index]; if(entry->state == HS_FREE) return(NULL); if(entry->state != HS_OCCUPIED || !C()(entry->first, key)) { int c; for(c = 0; c < capacity; ++c) { ++index; if(index >= capacity) index = 0; entry = &entries[index]; if(entry->state == HS_FREE) return(NULL); if(C()(entry->first, key)) break; } } bool B_matches = C()(entry->first, key); return(B_matches ? entry : NULL); } void growTo(int count) { if(count > this->capacity) { HashtableEntry* oldEntries = this->entries; int oldCapacity = this->capacity; capacity = (1 << ((int)log2(count) + 1)) + 1; // FIXME use primes or something this->entries = new (UseGC) HashtableEntry[capacity]; // and zeroed out for(int i = 0; i < capacity; ++i) { this->entries[i].state = HS_FREE; } this->capacity = capacity; for(int i = 0; i < oldCapacity; ++i) { struct HashtableEntry* entry = &oldEntries[i]; if(entry->state == HS_OCCUPIED) put(entry->first, entry->second); } } } struct HashtableEntry* actualPut(const K& key, const V& value) { struct HashtableEntry* entry = findEntry(key); if(!entry) { growTo(count + 1); int index = hash(key) % capacity; entry = &entries[index]; if(entry->state == HS_OCCUPIED) { int c; for(c = 0; c < capacity; ++c) { ++index; if(index >= capacity) index = 0; entry = &entries[index]; if(entry->state != HS_OCCUPIED) break; } if(c == capacity) { /* oops. completely full. This shouldn't happen */ abort(); } } assert(entry->state != HS_OCCUPIED); ++count; } entry->state = HS_OCCUPIED; entry->first = key; entry->second = value; // = HashtableEntry(key, value); return(entry); } public: void clear(void) { entries = NULL; capacity = 0; count = 0; } RawHashtable(void) { clear(); } size_t size(void) const { return(count); } class const_iterator { private: HashtableEntry* entry; int remainder; public: const_iterator(HashtableEntry* entry, int remainder) : entry(entry), remainder(remainder) { } inline void operator++(void) { assert(remainder > 0); for(++entry, --remainder; remainder > 0 && entry->state != HS_OCCUPIED; ++entry, --remainder) ; } inline std::pair operator*(void) const { return(std::pair(entry->first, entry->second)); } inline HashtableEntry* operator->(void) const { return(entry); } inline bool operator==(const const_iterator& b) const { if(this == &b) return(true); else if(entry == b.entry) return(true); else return(false); } inline bool operator!=(const const_iterator& b) const { return(!operator==(b)); } }; inline const_iterator begin(void) const { int i; for(i = 0; i < capacity && entries[i].state != HS_OCCUPIED; ++i) ; return(const_iterator(&entries[i], capacity - i)); } inline const_iterator end(void) const { return(const_iterator(&entries[capacity], 0)); } inline const_iterator find(const K& key) const { struct HashtableEntry* entry = findEntry(key); if(entry) { return(const_iterator(entry, capacity - (entry - entries))); } else return(end()); } inline void put(const K& key, const V& value) { (void) actualPut(key, value); } inline bool empty() const { return(count == 0); } inline bool containsKeyP(const K& key) const { return(findEntry(key) != NULL); } inline V get(const K& key) const { struct HashtableEntry* entry = findEntry(key); assert(entry); return entry->second; } inline V& operator[](const K& key) { struct HashtableEntry* entry = findEntry(key); if(!entry) { V value = 0; entry = actualPut(key, value); } return entry->second; } inline const V& operator[](const K& key) const { return(get(key)); } inline void removeByKey(const K& key) { struct HashtableEntry* entry = findEntry(key); if(entry) entry->state = HS_FREE_AGAIN; // TODO shrink } }; typedef RawHashtable Hashtable; #ifdef CX11xx class Hashtable : public RawHashtable, public Values::Node { }; #endif NodeT keysOfHashtable(Hashtable::const_iterator iter, Hashtable::const_iterator endIter); }; #endif /* ndef __VALUES_HASH_TABLE_H */