void hashMapInsert(Thread* t, object map, object key, object value, uint32_t (*hash)(Thread*, object)) { // note that we reinitialize the array variable whenever an // allocation (and thus possibly a collection) occurs, in case the // array changes due to a table resize. PROTECT(t, map); uint32_t h = hash(t, key); bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); ++ hashMapSize(t, map); if (array == 0 or hashMapSize(t, map) >= arrayLength(t, array) * 2) { PROTECT(t, key); PROTECT(t, value); hashMapResize(t, map, hash, array ? arrayLength(t, array) * 2 : 16); array = hashMapArray(t, map); } object k = key; if (weak) { PROTECT(t, key); PROTECT(t, value); object r = makeWeakReference(t, 0, 0, 0, 0); jreferenceTarget(t, r) = key; jreferenceVmNext(t, r) = t->m->weakReferences; t->m->weakReferences = r; k = r; array = hashMapArray(t, map); } object n = makeTriple(t, k, value, 0); array = hashMapArray(t, map); unsigned index = h & (arrayLength(t, array) - 1); set(t, n, TripleThird, arrayBody(t, array, index)); set(t, array, ArrayBody + (index * BytesPerWord), n); if (hashMapSize(t, map) <= arrayLength(t, array) / 3) { // this might happen if nodes were removed during GC in which case // we weren't able to resize at the time hashMapResize(t, map, hash, arrayLength(t, array) / 2); } }
int main(int argc, const char** argv) { const char* fileName = "input1.txt"; if (argc > 1) { fileName = argv[1]; } printf("Opening file: %s\n", fileName); clock_t timer = clock(); HashMap* map = hashMapNew(10); // --- Concordance code begins here --- printf ("Opened [%s]\n", fileName); FILE * file = fopen (fileName, "r"); if (file == NULL) { printf ("File not found! [%s]\n", fileName); } while (!feof(file)) { fgets (readBuffer, MAX_STRING_LENGTH, file); if (readBuffer[strlen(readBuffer) - 1] == '\n') { readBuffer[strlen(readBuffer) - 1] = 0; } printf ("Read Line [%s]\n", readBuffer); char * curString = strtok (readBuffer, STRING_SEPS); while (curString) { printf (" -- Token: [%s]\n", curString); int * value = hashMapGet(map, curString); if (value == NULL) { hashMapPut(map, curString, 1); } else { hashMapPut(map, curString, (*value)+1); } curString = strtok (NULL, STRING_SEPS); } } fclose (file); // --- Concordance code ends here --- hashMapPrint(map); timer = clock() - timer; printf("\nRan in %f seconds\n", (float)timer / (float)CLOCKS_PER_SEC); printf("Empty buckets: %d\n", hashMapEmptyBuckets(map)); printf("Number of links: %d\n", hashMapSize(map)); printf("Number of buckets: %d\n", hashMapCapacity(map)); printf("Table load: %f\n", hashMapTableLoad(map)); hashMapDelete(map); return 0; }
object hashMapRemoveNode(Thread* t, object map, unsigned index, object p, object n) { if (p) { set(t, p, TripleThird, tripleThird(t, n)); } else { set(t, hashMapArray(t, map), ArrayBody + (index * BytesPerWord), tripleThird(t, n)); } -- hashMapSize(t, map); return n; }
object hashMapRemove(Thread* t, object map, object key, uint32_t (*hash)(Thread*, object), bool (*equal)(Thread*, object, object)) { bool weak = objectClass(t, map) == type(t, Machine::WeakHashMapType); object array = hashMapArray(t, map); object o = 0; if (array) { unsigned index = hash(t, key) & (arrayLength(t, array) - 1); object p = 0; for (object n = arrayBody(t, array, index); n;) { object k = tripleFirst(t, n); if (weak) { k = jreferenceTarget(t, k); if (k == 0) { n = tripleThird(t, hashMapRemoveNode(t, map, index, p, n)); continue; } } if (equal(t, key, k)) { o = tripleSecond(t, hashMapRemoveNode(t, map, index, p, n)); break; } else { p = n; n = tripleThird(t, n); } } if ((not t->m->collecting) and hashMapSize(t, map) <= arrayLength(t, array) / 3) { PROTECT(t, o); hashMapResize(t, map, hash, arrayLength(t, array) / 2); } } return o; }
/** * Tests all hash map functions after adding and removing all of the given keys * and values. * @param test * @param links The key-value pairs to be added and removed. * @param notKeys Some keys not in the table to test contains and get. * @param numLinks The number of key-value pairs to be added and removed. * @param numNotKeys The number of keys not in the table. * @param numBuckets The initial number of buckets (capacity) in the table. */ void testCase(CuTest* test, HashLink* links, const char** notKeys, int numLinks, int numNotKeys, int numBuckets) { HashMap* map = hashMapNew(numBuckets); Histogram hist; // Add links for (int i = 0; i < numLinks; i++) { hashMapPut(map, links[i].key, links[i].value); } // Print table printf("\nAfter adding all key-value pairs:"); hashMapPrint(map); // Check size CuAssertIntEquals(test, numLinks, hashMapSize(map)); // Check capacity CuAssertIntEquals(test, map->capacity, hashMapCapacity(map)); // Check empty buckets int sum = 0; for (int i = 0; i < map->capacity; i++) { if (map->table[i] == NULL) { sum++; } } CuAssertIntEquals(test, sum, hashMapEmptyBuckets(map)); // Check table load CuAssertIntEquals(test, (float)numLinks / map->capacity, hashMapTableLoad(map)); // Check contains and get on valid keys. for (int i = 0; i < numLinks; i++) { CuAssertIntEquals(test, 1, hashMapContainsKey(map, links[i].key)); int* value = hashMapGet(map, links[i].key); CuAssertPtrNotNull(test, value); CuAssertIntEquals(test, links[i].value, *value); } // Check contains and get on invalid keys. for (int i = 0; i < numNotKeys; i++) { CuAssertIntEquals(test, 0, hashMapContainsKey(map, notKeys[i])); CuAssertPtrEquals(test, NULL, hashMapGet(map, notKeys[i])); } // Check that all links are present and have a unique key. histFromTable(&hist, map); CuAssertIntEquals(test, numLinks, hist.size); assertHistCounts(test, &hist); histCleanUp(&hist); // Remove keys for (int i = 0; i < numLinks; i++) { hashMapRemove(map, links[i].key); } // Print table printf("\nAfter removing all key-value pairs:"); hashMapPrint(map); // Check size CuAssertIntEquals(test, 0, hashMapSize(map)); // Check capacity CuAssertIntEquals(test, map->capacity, hashMapCapacity(map)); // Check empty buckets CuAssertIntEquals(test, map->capacity, hashMapEmptyBuckets(map)); // Check table load CuAssertIntEquals(test, 0, hashMapTableLoad(map)); // Check contains and get on valid keys. for (int i = 0; i < numLinks; i++) { CuAssertIntEquals(test, 0, hashMapContainsKey(map, links[i].key)); CuAssertPtrEquals(test, NULL, hashMapGet(map, links[i].key)); } // Check contains and get on invalid keys. for (int i = 0; i < numNotKeys; i++) { CuAssertIntEquals(test, 0, hashMapContainsKey(map, notKeys[i])); CuAssertPtrEquals(test, NULL, hashMapGet(map, notKeys[i])); } // Check that there are no links in the table. histFromTable(&hist, map); CuAssertIntEquals(test, 0, hist.size); assertHistCounts(test, &hist); histCleanUp(&hist); hashMapDelete(map); }