├── README.md ├── c source ├── addNullDel.c ├── clone.c ├── copyFromHashTable.c ├── findKey.c ├── findVal.c ├── forEachVal.c ├── getFromHash.c ├── hash.h ├── hashDestroy.c ├── hashGet.c ├── hashPut.c ├── hashRemove.c ├── hashTraverse.c ├── multPut.c ├── multPutConst.c ├── multPutNoDel.c ├── newHashTable.c ├── next.c ├── rehash.c └── toString.c ├── examples ├── benchmark.ahk ├── example.ahk ├── example2.ahk ├── example2_v1.ahk ├── example_v1.ahk └── persistentExample.ahk ├── hashTable.ahk ├── hashTable_v1.ahk └── wikiImages └── hash.png /README.md: -------------------------------------------------------------------------------- 1 | # hashTable 2 | 3 | There is some content in the [wiki](https://github.com/HelgeffegleH/hashTable/wiki "Visit hashTable wiki.") 4 | 5 | [AutoHotkey forum post](https://autohotkey.com/boards/viewtopic.php?f=6&t=36377 "Visit autohotkey.com") -------------------------------------------------------------------------------- /c source/addNullDel.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | int __cdecl addNullDel(tableData** table, pfnLib lib, unsigned short* keys, unsigned short* vals, unsigned int n){ 3 | unsigned int ko, ki; // key offset, key index 4 | unsigned int vo, vi; // val offset, val index 5 | 6 | unsigned int bucketN; // bucket number from findKey 7 | unsigned int status; // status, see findKey() 8 | unsigned int m,i; // loop index, for finding/copying keys/values. 9 | 10 | node* foundNode; // node placeholders 11 | node* newNode; 12 | unsigned short* newKey; // key, value placeholders 13 | unsigned short* newVal; 14 | 15 | ko=0; // init offsets and indices 16 | vo=0; 17 | ki=0; 18 | vi=0; 19 | 20 | int done=0; // break main loop condition 21 | for (m=0;mpmalloc((ki+1)*2); 31 | for (i=0; ipmalloc((vi+1)*2); 36 | for (i=0; ipfindKey((*table)->nodes,newKey,(*table)->length, &bucketN, &status); // search for key. 45 | if (status==1){ // Key found, just put value. 46 | lib->pfree(foundNode->val); 47 | lib->pfree(newKey); 48 | foundNode->val=newVal; 49 | continue; 50 | } 51 | newNode = lib->pmalloc(sizeof(node)); // key not found, make a new node 52 | newNode->next=0; // Set up the new node 53 | newNode->key=newKey; 54 | newNode->val=newVal; 55 | if (status == 0) { // No node in bucket. newNode becomes the first node in the bucket 56 | (*table)->nodes[bucketN] = newNode; 57 | } else { 58 | foundNode->next = newNode; // there are node(s) in the bucket, append new node to the last one 59 | } 60 | (*table)->numkeys++; // increment number of keys in table 61 | // Regarding the check for rehash. 62 | // This is not needed here becuase added check if rehash would be needed in script pre-calling this. 63 | // However, the bin-code in script includes this check. Change in future if rememeber. Might apply to other c-files to. 64 | if ( (double) (*table)->numkeys > (double) ((*table)->maxLoad*(*table)->length) ) // check if rehash 65 | (*table) = lib->prehash(table,lib); 66 | // continue main loop 67 | } // end main loop 68 | return 1; 69 | } -------------------------------------------------------------------------------- /c source/clone.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | tableData* __cdecl clone(tableData** table, pfnLib lib){ 3 | // newTable is the clone 4 | tableData* newTable = lib->pnewHashTable((*table)->length,lib->pmalloc,(*table)->tableSizes,(*table)->maxLoad,(*table)->nextLenInd); // set up the new table struct to be identical to the table being cloned. 5 | if (newTable==0) // fail 6 | return 0; 7 | newTable->numkeys=(*table)->numkeys; // copy number of keys 8 | unsigned int i,j; 9 | unsigned int ki,vi; // key/val strlen 10 | 11 | unsigned short* newKey; // key, value placeholders 12 | unsigned short* newVal; 13 | 14 | node* newNode; // node placeholders 15 | node* oldNode; 16 | node* nextNode; 17 | for (i=0; i<(*table)->length; ++i){ // visit all nodes 18 | oldNode = (*table)->nodes[i]; 19 | 20 | while (oldNode!=0) { 21 | newNode = (node*) lib->pmalloc(sizeof(node)); // make a new node 22 | ki=0; 23 | vi=0; 24 | while(oldNode->key[ki++]); // calculate key/val strlen. 25 | while(oldNode->val[vi++]); 26 | newKey = lib->pmalloc(ki*2); 27 | newVal = lib->pmalloc(vi*2); 28 | for (j=0; jkey[j]; 30 | for (j=0; jval[j]; 32 | newNode->next=0; // copy old values to new node 33 | newNode->key=newKey; 34 | newNode->val=newVal; 35 | oldNode=oldNode->next; 36 | 37 | nextNode = newTable->nodes[i]; 38 | if (nextNode==0){ // place the new node first in the bucket if no nodes there... 39 | newTable->nodes[i]=newNode; 40 | continue; 41 | } 42 | while (nextNode->next!=0) // ... else go to the end of bucket and place it there. 43 | nextNode=nextNode->next; 44 | nextNode->next=newNode; 45 | 46 | } 47 | } 48 | return newTable; // done 49 | } -------------------------------------------------------------------------------- /c source/copyFromHashTable.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | typedef int __cdecl (*put)(tableData**, pfnLib, unsigned short*, unsigned short*); 3 | typedef struct copyParams { 4 | tableData** destTable; 5 | pfnLib lib; 6 | put pput; 7 | } *pparams; 8 | int __cdecl copyFromHashTable(unsigned short* key, unsigned short* val, unsigned int i, unsigned int cbid, unsigned int hash, pparams p){ 9 | p->pput(p->destTable,p->lib,key,val); 10 | return 1; 11 | } -------------------------------------------------------------------------------- /c source/findKey.c: -------------------------------------------------------------------------------- 1 | typedef struct node node; 2 | struct node { 3 | node* next; 4 | unsigned short* key; 5 | unsigned short* val; 6 | }; 7 | 8 | node* __cdecl findKey(node** nodes, unsigned short* key, unsigned int tableLength, unsigned int* bucketN, unsigned int* status){ 9 | unsigned int k,m; // k, key strlen, m loop ind 10 | unsigned int hash=0; // ∑_i key[i]*pow(31,i), i ∈ [0,k-1] 11 | unsigned int p=1; // power factor, p=31^i, i ∈ [0,k-1] 12 | 13 | for (k=0; key[k]!=0;++k){ // calculate key hash (and key string length) 14 | hash+=key[k]*p; 15 | p*=31; 16 | } 17 | hash = hash % tableLength; // map to valid index range 18 | *bucketN = hash; // bucket number, i.e., pos in nodes 19 | *status=0; // 0, no match and no nodes in bucket. 1 if match, i.e., key is in the table. 2 if no match but bucket has nodes. 20 | node* outNode; 21 | outNode = nodes[hash]; 22 | if (outNode==0) 23 | return 0; 24 | while (1){ // not null 25 | for(m=0; mkey[m]!=key[m]) 27 | goto nomatch; 28 | if (m==k && outNode->key[m]==0){ // match 29 | *status=1; 30 | return outNode; 31 | } 32 | nomatch:; 33 | if (outNode->next!=0) { 34 | outNode=outNode->next; 35 | } else { 36 | *status=2; 37 | return outNode; 38 | } 39 | } 40 | return 0; // no match 41 | } -------------------------------------------------------------------------------- /c source/findVal.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | 3 | unsigned short* __cdecl findVal(tableData** table, pfnLib lib, unsigned short* val){ 4 | unsigned int i,m; 5 | node* curNode; 6 | unsigned int k=0; 7 | while (val[k]!=0) // strlen(val) 8 | k++; 9 | for (i=0; i<(*table)->length; ++i){ // goes through all nodes from hash = 0; 10 | curNode = (*table)->nodes[i]; 11 | while (curNode!=0){ // visit all node->next 12 | for(m=0; mval[m]!=val[m]) 14 | goto nomatch; 15 | if (m==k && curNode->val[m]==0){ // match 16 | return curNode->key; 17 | } 18 | nomatch:; 19 | curNode=curNode->next; 20 | } 21 | } 22 | return 0; 23 | } -------------------------------------------------------------------------------- /c source/forEachVal.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | typedef int __cdecl (*calloutFn)(unsigned short*,unsigned short*,unsigned int,unsigned int,unsigned int,void*); 3 | int __cdecl forEachVal(tableData** table, pfnLib lib, unsigned short* val, calloutFn pcalloutFn,unsigned int cbid, void* uParams){ 4 | unsigned int i,m; // hash code, strcmp index. 5 | unsigned int j=0; // iteration number 6 | int exit=0; // return when 1. Set to 1 when calloutFn returns -2. 7 | node* curNode; // node placeholders. 8 | node* prevNode; 9 | node* tmpNode; 10 | unsigned int k=0; 11 | while (val[k]!=0) // strlen(val) 12 | k++; 13 | for (i=0; i<(*table)->length; ++i){ // goes through all nodes from hash = 0; 14 | curNode = (*table)->nodes[i]; 15 | prevNode=0; 16 | while (curNode!=0){ // visit all node->next 17 | for(m=0; mval[m]!=val[m]) 19 | goto nomatch; 20 | if (m==k && curNode->val[m]==0){ // match 21 | // Switch from traverse.c 22 | switch (pcalloutFn(curNode->key,curNode->val,++j,cbid,i,uParams)){ 23 | case 1: // continue 24 | prevNode=curNode; 25 | curNode=curNode->next; 26 | break; 27 | case 0: // stop 28 | return 0; 29 | case -2: // remove and stop; 30 | exit=1; 31 | case -1: // remove key - value 32 | tmpNode=curNode->next; 33 | lib->pfree(curNode->key); // free the node which is being removed 34 | lib->pfree(curNode->val); 35 | lib->pfree(curNode); 36 | if (prevNode!=0) // keep links 37 | prevNode->next=tmpNode; 38 | else 39 | (*table)->nodes[i]=tmpNode; 40 | (*table)->numkeys--; 41 | if (exit) 42 | return -2; 43 | curNode=tmpNode; 44 | break; 45 | } 46 | } else { 47 | nomatch:; 48 | curNode=curNode->next; 49 | } 50 | } 51 | } 52 | return 1; 53 | } -------------------------------------------------------------------------------- /c source/getFromHash.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | node* __cdecl getFromHash(node** nodes, unsigned int hash, unsigned int n){ 3 | // returns the n:th node at nodes[hash], 0 if no node is found. 4 | // called by next for "regular" ahk for loop. _newenum() 5 | node* foundNode = nodes[hash]; 6 | if (foundNode == 0 || n==1) 7 | return foundNode; 8 | int i=1; 9 | while(foundNode->next != 0 && inext; 11 | i++; 12 | } 13 | if (i==n) 14 | return foundNode; 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /c source/hash.h: -------------------------------------------------------------------------------- 1 | #include 2 | typedef struct node node; 3 | typedef struct tableData tableData; 4 | // data structure 5 | struct node { // each key value pair is contained in a linked list, in their respective bucket (hash) 6 | node* next; 7 | unsigned short* key; 8 | unsigned short* val; 9 | }; 10 | struct tableData { 11 | node** nodes; // the buckets. Array of nodes. Nodes form a linked list. All keys yielding the same hash are placed in the same linked list of nodes. I.e., placed in: nodes[hash] 12 | unsigned int* tableSizes; // list of available array sizes (number of buckets) 13 | double maxLoad; // Determines when to rehash, see hashPut 14 | unsigned int length; // number of buckets (nodes in the array) 15 | unsigned int numkeys; // the number of key val pairs in the table 16 | unsigned int nextLenInd; // which size to expand to on the next rehash: newSize = tableSizes[nextLenInd] 17 | }; 18 | // Function lib declarations 19 | typedef void* __cdecl (*_malloc)(size_t); // for allocating memory for data 20 | typedef void __cdecl (*_free)(void*); // for freeing memory 21 | typedef node* __cdecl (*findKey)(node**,unsigned short*,unsigned int,unsigned int*,unsigned int*); // findKey() 22 | typedef tableData* __cdecl (*_rehash)(tableData**, void*); // rehash() 23 | typedef tableData* __cdecl (*_newHashTable)(unsigned int,_malloc,unsigned int*,double,unsigned int); // newHashTable() 24 | //typedef void (*mb)(int,void*); // db, typically a message box 25 | 26 | typedef struct functionLib { 27 | _malloc pmalloc; 28 | _free pfree; 29 | findKey pfindKey; 30 | _rehash prehash; 31 | _newHashTable pnewHashTable; 32 | //mb pmb; // db 33 | } fnLib, *pfnLib; -------------------------------------------------------------------------------- /c source/hashDestroy.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | void __cdecl destroy(tableData** table, pfnLib lib){ 3 | unsigned int i; // loop ind. 4 | node* oldNode; // node place holders 5 | node* nextNode; 6 | // free nodes, key val. 7 | for (i=0; i<(*table)->length; ++i){ // visit all nodes 8 | oldNode = (*table)->nodes[i]; 9 | while (oldNode!=0){ 10 | nextNode=oldNode->next; // free key value and node 11 | lib->pfree(oldNode->key); 12 | lib->pfree(oldNode->val); 13 | lib->pfree(oldNode); 14 | oldNode=nextNode; 15 | } 16 | } 17 | // free the old table. 18 | lib->pfree((*table)->nodes); 19 | lib->pfree((*table)); 20 | } -------------------------------------------------------------------------------- /c source/hashGet.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | unsigned short* __cdecl hashGet(tableData** table, pfnLib lib, unsigned short* key){ 3 | unsigned int bucketN; 4 | unsigned int status; 5 | node* foundNode = lib->pfindKey((*table)->nodes,key,(*table)->length, &bucketN, &status); // see findKey() 6 | if (status == 1) 7 | return foundNode->val; // return pointer to val if found 8 | return 0; 9 | } -------------------------------------------------------------------------------- /c source/hashPut.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | 3 | int __cdecl hashPut(tableData** table, pfnLib lib, unsigned short* key, unsigned short* val ){ 4 | unsigned int bucketN; // bucket number from findKey 5 | unsigned int status; // status, see findKey() 6 | unsigned int i; // loop index, for copying key / value. 7 | node* foundNode; 8 | unsigned int vallen=0; // value string legngt 9 | while (val[vallen]!=0) // calc value string length 10 | vallen++; 11 | unsigned short* newVal = lib->pmalloc( (vallen + 1) * 2); // alloc memory for new value 12 | for (i=0; i<=vallen; ++i) // copy the value 13 | newVal[i]=val[i]; 14 | foundNode = lib->pfindKey((*table)->nodes,key,(*table)->length, &bucketN, &status); // search for key. 15 | if (status==1){ // Key found, just put value. 16 | lib->pfree(foundNode->val); 17 | foundNode->val=newVal; 18 | return 1; 19 | } 20 | node* newNode = lib->pmalloc(sizeof(node)); // key not found, make a new node 21 | unsigned int keylen=0; // calculate key string length 22 | while (key[keylen]!=0) 23 | keylen++; 24 | unsigned short* newKey = lib->pmalloc((keylen + 1) * 2); // alloc memory for new key 25 | for (i=0; i<=keylen; ++i) // copy key 26 | newKey[i]=key[i]; 27 | newNode->next=0; // Set up the new node 28 | newNode->key=newKey; 29 | newNode->val=newVal; 30 | if (status == 0) { // No node in bucket. newNode becomes the first node in the bucket 31 | (*table)->nodes[bucketN] = newNode; 32 | } else { 33 | foundNode->next = newNode; // there are node(s) in the bucket, append new node to the last one 34 | } 35 | (*table)->numkeys++; // increment number of keys in table 36 | if ( (double) (*table)->numkeys > (double) ((*table)->maxLoad*(*table)->length) ) { // check if rehash 37 | (*table) = lib->prehash(table,lib); 38 | return -1; // did rehash after adding new key value pair 39 | } 40 | return 0; // new key value pair added, no rehash 41 | } -------------------------------------------------------------------------------- /c source/hashRemove.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | 3 | int __cdecl hashRemove(tableData** table, pfnLib lib, unsigned short* key){ 4 | unsigned int k,m; // k, key strlen, m loop ind 5 | unsigned int hash=0; // ∑_i key[i]*pow(31,i), i ∈ [0,k-1] 6 | unsigned int p=1; // power factor, p=31^i, i ∈ [0,k-1] 7 | 8 | for (k=0; key[k]!=0;++k){ // calculate key hash 9 | hash+=key[k]*p; 10 | p*=31; 11 | } 12 | 13 | hash = hash % (*table)->length; // map to valid index range 14 | node* prevNode=0; 15 | node* curNode = (*table)->nodes[hash]; 16 | if (curNode==0) 17 | return 0; // no nodes in bucket. Didn't remove key value pair 18 | while (1){ 19 | for(m=0; mnodes[hash] 20 | if (curNode->key[m]!=key[m]) 21 | goto nomatch; 22 | if (m==k && curNode->key[m]==0){ // match 23 | if (prevNode!=0) // there was a node in the bucket before the found match 24 | prevNode->next=curNode->next; 25 | else 26 | (*table)->nodes[hash]=curNode->next; // there was no previous node in this bucket 27 | lib->pfree(curNode->key); // free the node and its values 28 | lib->pfree(curNode->val); 29 | lib->pfree(curNode); 30 | 31 | (*table)->numkeys--; // decrement count 32 | return 1; // removed the key value 33 | } 34 | nomatch:; 35 | if (curNode->next!=0) { // continue with the next node if exist 36 | prevNode = curNode; 37 | curNode=curNode->next; 38 | } else { 39 | return 2; // No key found in bucket. 40 | } 41 | } 42 | return 0; // not reachable 43 | } -------------------------------------------------------------------------------- /c source/hashTraverse.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | typedef int __cdecl (*calloutFn)(unsigned short*,unsigned short*,unsigned int,unsigned int,unsigned int,void*); 3 | int __cdecl traverse(tableData** table, pfnLib lib, calloutFn pcalloutFn,unsigned int cbid, void* uParams){ 4 | unsigned int i; // loop ind (hash number) 5 | unsigned int j=0; // iteration number 6 | int exit = 0; // for exiting after removed key-val pair 7 | node* curNode; 8 | node* prevNode; 9 | node* tmpNode; 10 | 11 | for (i=0; i<(*table)->length; ++i){ // visit all buckets 12 | curNode = (*table)->nodes[i]; 13 | prevNode=0; 14 | while (curNode!=0){ // Visit all nodes in each bucket 15 | switch (pcalloutFn(curNode->key,curNode->val,++j,cbid,i,uParams)){ 16 | case 1: // continue 17 | prevNode=curNode; 18 | curNode=curNode->next; 19 | break; 20 | case 0: // stop 21 | return 0; 22 | case -2: // remove and stop; 23 | exit=1; 24 | case -1: // remove key - value 25 | tmpNode=curNode->next; 26 | lib->pfree(curNode->key); // free the node which is being removed 27 | lib->pfree(curNode->val); 28 | lib->pfree(curNode); 29 | if (prevNode!=0) // keep links 30 | prevNode->next=tmpNode; 31 | else 32 | (*table)->nodes[i]=tmpNode; 33 | (*table)->numkeys--; 34 | if (exit) 35 | return -2; 36 | curNode=tmpNode; 37 | break; 38 | } 39 | } 40 | } 41 | return 1; 42 | } -------------------------------------------------------------------------------- /c source/multPut.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | int __cdecl multPut(tableData** table, pfnLib lib, unsigned short* keys, unsigned short* vals, unsigned short* del){ 3 | unsigned int ko, ki; // key offset, key index 4 | unsigned int vo, vi; // val offset, val index 5 | 6 | unsigned int bucketN; // bucket number from findKey 7 | unsigned int status; // status, see findKey() 8 | unsigned int i,j; // loop index, for finding/copying keys/values. 9 | 10 | node* foundNode; // node placeholders 11 | node* newNode; 12 | unsigned short* newKey; // key, value placeholders 13 | unsigned short* newVal; 14 | 15 | unsigned int dellen=0; // delimiter string length 16 | 17 | while(del[dellen++]); // calc delimiter string length 18 | dellen--; // exclude null terminator from strlen. 19 | 20 | ko=0; // init offsets and indices 21 | vo=0; 22 | ki=0; 23 | vi=0; 24 | 25 | int done=0; // break main loop condition 26 | do { // main loop 27 | while(1){ // find key 28 | while (keys[ko+ki]!=0 && keys[ko+ki]!=del[0]) // search for delimiter 29 | ++ki; 30 | for(j=0; keys[ko+ki+j]==del[j] && jpmalloc((ki+1)*2); 58 | for (i=0; ipmalloc((vi+1)*2); 63 | for (i=0; ipfindKey((*table)->nodes,newKey,(*table)->length, &bucketN, &status); // search for key. 72 | if (status==1){ // Key found, just put value. 73 | lib->pfree(foundNode->val); 74 | lib->pfree(newKey); 75 | foundNode->val=newVal; 76 | continue; 77 | } 78 | newNode = lib->pmalloc(sizeof(node)); // key not found, make a new node 79 | newNode->next=0; // Set up the new node 80 | newNode->key=newKey; 81 | newNode->val=newVal; 82 | if (status == 0) { // No node in bucket. newNode becomes the first node in the bucket 83 | (*table)->nodes[bucketN] = newNode; 84 | } else { 85 | foundNode->next = newNode; // there are node(s) in the bucket, append new node to the last one 86 | } 87 | (*table)->numkeys++; // increment number of keys in table 88 | if ( (double) (*table)->numkeys > (double) ((*table)->maxLoad*(*table)->length) ) // check if rehash 89 | (*table) = lib->prehash(table,lib); 90 | // continue main loop 91 | 92 | } while (!done); // end main loop 93 | return 1; 94 | } -------------------------------------------------------------------------------- /c source/multPutConst.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | int __cdecl multPutConstVal(tableData** table, pfnLib lib, unsigned short* keys, unsigned short* val, unsigned short* del){ 3 | unsigned int ko, ki; // key offset, key index 4 | 5 | unsigned int bucketN; // bucket number from findKey 6 | unsigned int status; // status, see findKey() 7 | unsigned int i,j; // loop index, for finding/copying keys. 8 | 9 | node* foundNode; // node placeholders 10 | node* newNode; 11 | unsigned short* newKey; // key placeholder. 12 | unsigned short* newVal; // val placeholder. 13 | 14 | 15 | unsigned int dellen=0; // delimiter string length 16 | while(del[dellen++]); // calc delimiter string length 17 | dellen--; // exclude null terminator from strlen. 18 | 19 | unsigned int vallen=0; // value string length 20 | while(val[vallen++]); // calc valu string length 21 | vallen--; // exclude null terminator from strlen. 22 | 23 | 24 | ko=0; // init offest and index. 25 | ki=0; 26 | 27 | int done=0; // break main loop condition 28 | 29 | do { // main loop 30 | while(1){ // find key 31 | while (keys[ko+ki]!=0 && keys[ko+ki]!=del[0]) // search for delimiter 32 | ++ki; 33 | for(j=0; keys[ko+ki+j]==del[j] && jpmalloc((ki+1)*2); 46 | for (i=0; ipmalloc((vallen+1)*2); 51 | for (i=0; ipfindKey((*table)->nodes,newKey,(*table)->length, &bucketN, &status); // search for key. 60 | if (status==1){ // Key found, just put value. 61 | lib->pfree(foundNode->val); 62 | lib->pfree(newKey); 63 | foundNode->val=newVal; 64 | continue; 65 | } 66 | newNode = lib->pmalloc(sizeof(node)); // key not found, make a new node 67 | newNode->next=0; // Set up the new node 68 | newNode->key=newKey; 69 | newNode->val=newVal; 70 | if (status == 0) { // No node in bucket. newNode becomes the first node in the bucket 71 | (*table)->nodes[bucketN] = newNode; 72 | } else { 73 | foundNode->next = newNode; // there are node(s) in the bucket, append new node to the last one 74 | } 75 | (*table)->numkeys++; // increment number of keys in table 76 | if ( (double) (*table)->numkeys > (double) ((*table)->maxLoad*(*table)->length) ) // check if rehash 77 | (*table) = lib->prehash(table,lib); 78 | // continue main loop 79 | 80 | } while (!done); // end main loop 81 | return 1; 82 | } -------------------------------------------------------------------------------- /c source/multPutNoDel.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | int __cdecl multPutNoDel(tableData** table, pfnLib lib, unsigned short* keys, unsigned short* vals, int constVal){ 3 | unsigned int bucketN; // bucket number from findKey 4 | unsigned int status; // status, see findKey() 5 | unsigned int i,j; // loop index, for finding/copying keys/values. 6 | 7 | node* foundNode; // node placeholders 8 | node* newNode; 9 | unsigned short* newKey; // key, value placeholders 10 | unsigned short* newVal; 11 | 12 | size_t valsize; 13 | unsigned int vallen; 14 | if (constVal){ // handle constant value 15 | vallen=0; 16 | while (vals[vallen++]); // value length including null terminator. 17 | valsize=vallen*2; 18 | } else { 19 | valsize=4; 20 | } 21 | 22 | i=0; 23 | while (keys[i]){ 24 | if (constVal == 0 && vals[i]==0) 25 | return 0; 26 | newKey = lib->pmalloc(4); 27 | newVal = lib->pmalloc(valsize); 28 | newKey[0]=keys[i]; 29 | newKey[1]=0; 30 | if (constVal) { // handle constant value 31 | for(j=0; jpfindKey((*table)->nodes,newKey,(*table)->length, &bucketN, &status); // search for key. 39 | if (status==1){ // Key found, just put value. 40 | lib->pfree(foundNode->val); 41 | lib->pfree(newKey); 42 | foundNode->val=newVal; 43 | continue; 44 | } 45 | newNode = lib->pmalloc(sizeof(node)); // key not found, make a new node 46 | newNode->next=0; // Set up the new node 47 | newNode->key=newKey; 48 | newNode->val=newVal; 49 | if (status == 0) { // No node in bucket. newNode becomes the first node in the bucket 50 | (*table)->nodes[bucketN] = newNode; 51 | } else { 52 | foundNode->next = newNode; // there are node(s) in the bucket, append new node to the last one 53 | } 54 | (*table)->numkeys++; // increment number of keys in table 55 | if ( (double) (*table)->numkeys > (double) ((*table)->maxLoad*(*table)->length) ) // check if rehash 56 | (*table) = lib->prehash(table,lib); 57 | // continue main loop 58 | } 59 | return 1; 60 | } -------------------------------------------------------------------------------- /c source/newHashTable.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | 3 | tableData* _newHashTable(unsigned int len,_malloc pmalloc,unsigned int* tableSizes,double maxLoad,unsigned int nextLenInd){ 4 | unsigned int i; 5 | tableData* table = pmalloc(sizeof(tableData)); // alloc memory for tableData struct 6 | if (table==0) // fail 7 | return 0; 8 | table->nodes = pmalloc(sizeof(node*)*len); // alloc memory for node pointer array 9 | if (table->nodes==0) // fail 10 | return 0; 11 | for (i=0; inodes[i]=0; 13 | 14 | table->tableSizes=tableSizes; // set up members 15 | table->maxLoad=maxLoad; 16 | table->length=len; 17 | table->numkeys=0; 18 | table->nextLenInd=nextLenInd; 19 | return table; 20 | } -------------------------------------------------------------------------------- /c source/next.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | typedef node* __cdecl (*getFromHash)(node**, unsigned int, unsigned int); 3 | // (node** nodes, unsigned int hash, unsigned int n) 4 | // This if for the ahk for loop. _newenum() 5 | node* __cdecl next(tableData** table, unsigned int* hash, unsigned int* n, getFromHash pgetFromHash){ 6 | // n is the n:th key/val pair to get from bucket hash. If not exist, set n to 1 and increment hash. Else, increment n and return foundNode. 7 | node* foundNode=0; 8 | hash-=1; // due to numput returning the "wrong" address. Doing it in compiled version is ugly but improves performance. Mind the input. 9 | n-=1; // -- "" -- 10 | while (*hash<(*table)->length){ 11 | foundNode = pgetFromHash((*table)->nodes,*hash,*n); 12 | if (foundNode == 0){ 13 | *n=1; 14 | (*hash)++; 15 | } else { 16 | (*n)++; 17 | return foundNode; 18 | } 19 | } 20 | return 0; 21 | } -------------------------------------------------------------------------------- /c source/rehash.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | tableData* __cdecl rehash(tableData** table, pfnLib lib){ 3 | unsigned int newLength = (*table)->tableSizes[(*table)->nextLenInd]; // get the new length 4 | if (newLength == 0) // fail 5 | return 0; 6 | tableData* newTable = lib->pnewHashTable(newLength,lib->pmalloc,(*table)->tableSizes,(*table)->maxLoad,(*table)->nextLenInd+1); // set up the new table struct 7 | if (newTable==0) // fail 8 | return 0; 9 | newTable->numkeys=(*table)->numkeys; // number of keys are not changed by rehash 10 | unsigned int i; 11 | unsigned int k,p; // k, key strlen, p power factor 12 | unsigned int hash; // ∑_i key[i]*pow(31,i), i ∈ [0,k-1] 13 | 14 | node* oldNode; // node place holders 15 | node* nextNode; 16 | node* newNode; 17 | for (i=0; i<(*table)->length; ++i){ // visit all nodes 18 | oldNode = (*table)->nodes[i]; 19 | if (oldNode==0) 20 | continue; 21 | do { 22 | newNode=oldNode; 23 | oldNode=oldNode->next; 24 | newNode->next=0; 25 | for (k=0,p=1,hash=0; newNode->key[k]!=0;++k){ // calculate key hash in the new table 26 | hash+=newNode->key[k]*p; 27 | p*=31; 28 | } 29 | hash = hash % newLength; // map to valid index range 30 | 31 | nextNode = newTable->nodes[hash]; 32 | if (nextNode==0){ // place the new node first in the bucket if no nodes there... 33 | newTable->nodes[hash]=newNode; 34 | continue; 35 | } 36 | while (nextNode->next!=0) // ... else go to the end of bucket and place it there. 37 | nextNode=nextNode->next; 38 | nextNode->next=newNode; 39 | 40 | } while (oldNode!=0); 41 | } 42 | // free the old table. 43 | lib->pfree((*table)->nodes); 44 | lib->pfree((*table)); 45 | return newTable; // done 46 | } -------------------------------------------------------------------------------- /c source/toString.c: -------------------------------------------------------------------------------- 1 | #include 2 | typedef void* __cdecl (*realloc)(void*,size_t); 3 | /* 4 | void *memcpy( 5 | void *dest, 6 | const void *src, 7 | size_t count 8 | ); 9 | */ 10 | typedef void* __cdecl (*memcpy)(void*,const void*,size_t); 11 | 12 | typedef struct toStringParams { 13 | unsigned short* buf; // string buffer. 14 | unsigned short* del1; // key val delimiter 15 | unsigned short* del2; // pair delimiter 16 | realloc prealloc; // realloc fn 17 | memcpy pmemcpy; // memccpy fn 18 | unsigned int len; // buffer length 19 | unsigned int o; // buffer offset 20 | unsigned int dellen1; // delimiter 1 length. The delimiter lengths must be 0 if not used, see 'int what'. 21 | unsigned int dellen2; // delimiter 2 length. That is, dellen2 is 0 if what is 1, and dellen1 is 0 if what is 2 22 | int what; // what to get, 0 indicates both key and val, 1, only key, 2, only val. 23 | } *pparams; 24 | int __cdecl toString(unsigned short* key, unsigned short* val, unsigned int i, unsigned int cbid, unsigned int hash, pparams p){ 25 | unsigned short* reBuf; 26 | unsigned int keylen=0; 27 | unsigned int vallen=0; 28 | if (p->what<2) { 29 | while (key[keylen++]); 30 | keylen--; 31 | } 32 | if (p->what!=1) { 33 | while (val[vallen++]); 34 | vallen--; 35 | } 36 | int minlen = p->o+keylen+vallen+p->dellen1+p->dellen2; 37 | if (minlen >= p->len){ 38 | p->len = minlen*2; 39 | reBuf = p->prealloc(p->buf, p->len*2); // alloc 2 x length in bytes. 40 | if (reBuf==0) 41 | return 0; 42 | p->buf = reBuf; 43 | } 44 | if (p->what<2) { 45 | p->pmemcpy(p->buf+p->o,key,keylen*2); 46 | p->o+=keylen; 47 | p->pmemcpy(p->buf+p->o,p->del1,p->dellen1*2); 48 | p->o+=p->dellen1; 49 | } 50 | if (p->what!=1) { 51 | p->pmemcpy(p->buf+p->o,val,vallen*2); 52 | p->o+=vallen; 53 | p->pmemcpy(p->buf+p->o,p->del2,p->dellen2*2); 54 | p->o+=p->dellen2; 55 | } 56 | return 1; 57 | } -------------------------------------------------------------------------------- /examples/benchmark.ahk: -------------------------------------------------------------------------------- 1 | ; Benchmark script for hashTable.ahk 2 | ; Results vary sligthly due to using random strings. 3 | ; This test takes about 10-20 seconds to run at N:=100000. Do not add a zero, it takes very long time 4 | 5 | ; Note: to abort, use esc::exitapp() 6 | 7 | #include ..\hashTable.ahk 8 | randomSeed(3737) 9 | N:=100000 ; Number of key value pairs. Default test case is 100000. Benefits for hashTable can start at around 5000 pairs. 10 | result:="" 11 | makestr(keyvals,N) ; Makes N random words, "`n" - delimited. 12 | 13 | p:=3 ; round to p, for display purposes. 14 | 15 | ; 16 | ; Adding to empty array / table 17 | ; 18 | 19 | ht := new hashTable() 20 | t1:=QPC() 21 | loop parse, keyvals, "`n" 22 | ht[A_LoopField] := A_LoopField 23 | t2:=QPC() 24 | result.= "Adding " ht.count() " key/value pairs to empty array / table:`n`n" 25 | result.= "Hash table`t`t" round(t2-t1,p) "ms.`n" 26 | 27 | ahk_array := [] 28 | ahk_array.setCapacity(N) 29 | t1:=QPC() 30 | loop parse, keyvals, "`n" 31 | ahk_array[A_LoopField] := A_LoopField 32 | t2:=QPC() 33 | result.= "Ahk array`t`t`t" round(t2-t1,p) "ms.`n" 34 | 35 | keyvals:=sort(keyvals) 36 | 37 | ahk_array := [] 38 | ahk_array.setCapacity(N) 39 | t1:=QPC() 40 | loop parse, keyvals, "`n" 41 | ahk_array[A_LoopField] := A_LoopField 42 | t2:=QPC() 43 | result.= "Ahk array sorted`t`t" round(t2-t1,p) "ms.`n" 44 | 45 | ht := new hashTable() 46 | t1:=QPC() 47 | ht.splitAdd(&keyvals,&keyvals,"`n",,isByref:=true) 48 | t2:=QPC() 49 | result.= "Hash table splitAdd`t`t" round(t2-t1,p) "ms.`n" 50 | 51 | ; 52 | ; Adding to already large array / table 53 | ; 54 | 55 | N:=10000 56 | result.= "`nAdding: " N " more values:`n`n" 57 | addInLoop:=true 58 | makestr(moreKeyVals, N) 59 | t1:=QPC() 60 | if addInLoop 61 | loop parse, moreKeyVals, "`n" 62 | ht[A_LoopField] := A_LoopField 63 | else 64 | ht.splitAdd(&moreKeyVals, &moreKeyVals, "`n",,true) 65 | t2:=QPC() 66 | result.= "Hash table" (addInLoop?"":" (splitAdd)") "`t`t" round(t2-t1,p) "ms.`n" 67 | moreKeyVals:=sort(moreKeyVals) ; Great benefit 68 | t1:=QPC() 69 | loop parse, moreKeyVals, "`n" 70 | ahk_array[A_LoopField] := A_LoopField 71 | t2:=QPC() 72 | result.= "Ahk array`t`t`t" round(t2-t1,p) "ms.`n" 73 | 74 | ; 75 | ; Removing values 76 | ; 77 | 78 | result.= "`nRemoving the " N " values:`n`n" 79 | 80 | t1:=QPC() 81 | loop parse, moreKeyVals, "`n" 82 | ht.delete(A_LoopField) 83 | t2:=QPC() 84 | result.= "Hash table`t`t" round(t2-t1,p) "ms.`n" 85 | moreKeyVals:=sort(moreKeyVals) ; Marginal benefit 86 | t1:=QPC() 87 | loop parse, moreKeyVals, "`n" 88 | ahk_array.delete(A_LoopField) 89 | t2:=QPC() 90 | result.= "Ahk array`t`t`t" round(t2-t1,p) "ms.`n" 91 | 92 | ; 93 | ; looping 94 | ; 95 | 96 | result.= "`nLoop self-times:`n`n" 97 | 98 | t1:=QPC() 99 | for k, v in ht 100 | continue 101 | t2:=QPC() 102 | result.= "Hash table self time:`t`t" round(t2-t1,p) "ms.`n" 103 | 104 | t1:=QPC() 105 | for k, v in ahk_array 106 | continue 107 | t2:=QPC() 108 | result.= "Ahk array self time:`t`t" round(t2-t1,p) "ms.`n" 109 | 110 | t1:=QPC() 111 | ht.forEach(callbackcreate("forLoop","cdecl fast")) 112 | t2:=QPC() 113 | result.= "Hash table forEach:`t`t" round(t2-t1,p) "ms.`n" 114 | result.= "`nhasVal()`n`n" 115 | 116 | ; 117 | ; hasVal() - (searches for a value which doesn't exist.) 118 | ; 119 | t1:=QPC() 120 | r:=ht.hasVal(1) 121 | t2:=QPC() 122 | result.= "hash table: ( " r " )`t`t" round(t2-t1,p) "ms.`n" 123 | 124 | t1:=QPC() 125 | r:=arrHasVal(ahk_array,1) 126 | t2:=QPC() 127 | result.= "Ahk array: ( " r " )`t`t" round(t2-t1,p) "ms." 128 | 129 | ; 130 | ; toString() 131 | ; 132 | result.= "`n`ntoString()`n`n" 133 | t1:=QPC() 134 | str1:=ht.toString() 135 | t2:=QPC() 136 | result.= "hash table: ( " strlen(str1) " )`t" round(t2-t1,p) "ms.`n" 137 | 138 | t1:=QPC() 139 | r:=arrToString(ahk_array, "`t=`t", "`n") 140 | t2:=QPC() 141 | result.= "Ahk array: ( " strlen(r) " )`t" round(t2-t1,p) "ms." 142 | 143 | msgbox(result,"Hash table benchmark",0x40) 144 | exitapp() 145 | 146 | esc::exitapp() 147 | 148 | ; Help functions 149 | forLoop(key,val,i){ 150 | key:=strget(key), val:=strget(val) 151 | return 1 152 | } 153 | arrHasVal(arr,val){ 154 | for k, v in arr 155 | if v==val 156 | return true 157 | return false 158 | } 159 | arrToString(arr,del1,del2){ 160 | local str 161 | for k, v in arr 162 | str.=k . del1 . v . del2 163 | return rtrim(str,del2) 164 | } 165 | 166 | makestr(byref str, N){ 167 | loop N 168 | str.=rndstr(random(5,25),97,97+25) "`n" 169 | rtrim(str,"`n") 170 | } 171 | rndstr(n,min:=1,max:=65535){ 172 | varsetcapacity(str,(n+1)*2), p:=&str, numput(0,&str+(n*1)*2,"ushort") 173 | loop n 174 | p:=numput(random(min,max),p,"ushort") 175 | return strget(&str) 176 | } 177 | ;------------------------------------------------------------------------------- 178 | QPC() { ; microseconds precision ; borrowed from wolf_II 179 | ;------------------------------------------------------------------------------- 180 | static Freq, init := DllCall("QueryPerformanceFrequency", "Int64P", Freq) 181 | local Count 182 | DllCall("QueryPerformanceCounter", "Int64P", Count) 183 | Return (Count / Freq)*1000 184 | } -------------------------------------------------------------------------------- /examples/example.ahk: -------------------------------------------------------------------------------- 1 | ; Simplest example. Creating a hashTable and adding a key/value pair. Shows hasKey, hasVal splitAdd and finally toTree() to view the result. 2 | #include ..\hashTable.ahk 3 | ht := new hashTable 4 | ht["hello"] := "hash" 5 | msgbox('hasKey("hello") = ' ht.hasKey("hello") '`nhasVal("hash") = ' ht.hasVal("hash"),"Hash table example.") 6 | keys:=" 7 | ( 8 | key1 9 | key2 10 | key3 11 | )" 12 | vals:=" 13 | ( 14 | val1 15 | val2 16 | val3 17 | )" 18 | ht.splitAdd(keys,vals) ; split by line break (default) 19 | ht.delete("key2") ; Delete key2 20 | ht.toTree() 21 | exitapp() -------------------------------------------------------------------------------- /examples/example2.ahk: -------------------------------------------------------------------------------- 1 | ; for loop example. 2 | #include ..\hashTable.ahk 3 | ht := new hashTable 4 | keys:="key1|key2|key3|key4" 5 | vals:="val1|val2|val3|val4" 6 | ht.splitAdd(keys,vals, "|") ; split by pipe 7 | ht.forEach("myFunc") ; Note the order of the pairs 8 | ht.toTree() ; View it. 9 | exitapp() 10 | 11 | myFunc(key,val){ 12 | msgbox(key "`t=`t" val) 13 | if val == "val4" 14 | return -1 ; Return -1 means delete and continue. The key/value pair is deleted if val == "val4" 15 | else if key == "key2" 16 | return 0 ; Return 0 means break. The loop is stopped if key == "val2" 17 | return 1 ; Return 1 means continue 18 | } -------------------------------------------------------------------------------- /examples/example2_v1.ahk: -------------------------------------------------------------------------------- 1 | ; for loop example. 2 | 3 | #include ..\hashTable_v1.ahk 4 | ht := new hashTable 5 | keys:="key1|key2|key3|key4" 6 | vals:="val1|val2|val3|val4" 7 | ht.splitAdd(keys,vals, "|") ; split by pipe 8 | ht.forEach("myFunc") ; Note the order of the pairs 9 | msgbox % ht.toString() ; View it. 10 | exitapp 11 | 12 | myFunc(key,val){ 13 | msgbox % key "`t=`t" val 14 | if (val == "val4") 15 | return -1 ; Return -1 means delete and continue. The key/value pair is deleted if val == "val4" 16 | else if (key == "key2") 17 | return 0 ; Return 0 means break. The loop is stopped if key == "val2" 18 | return 1 ; Return 1 means continue 19 | } -------------------------------------------------------------------------------- /examples/example_v1.ahk: -------------------------------------------------------------------------------- 1 | ; Simplest example. Creating a hashTable and adding a key/value pair. Shows hasKey, hasVal splitAdd and finally toString() to view the result. 2 | #include ..\hashTable_v1.ahk 3 | ht := new hashTable 4 | ht["hello"] := "hash" 5 | msgbox,, % "Hash table example.", % "hasKey(""hello"") = " ht.hasKey("hello") "`nhasVal(""hash"") = " ht.hasVal("hash") 6 | keys:=" 7 | ( 8 | key1 9 | key2 10 | key3 11 | )" 12 | vals:=" 13 | ( 14 | val1 15 | val2 16 | val3 17 | )" 18 | ht.splitAdd(keys,vals) ; split by line break (default) 19 | ht.delete("key2") ; Delete key2 20 | msgbox % ht.toString() 21 | exitapp -------------------------------------------------------------------------------- /examples/persistentExample.ahk: -------------------------------------------------------------------------------- 1 | ; Rough example to showcase persistent tables. 2 | ; This example is not available for v1. 3 | #include ..\hashTable.ahk 4 | 5 | ht:=new hashTable(,"exampleTable") ; Specifying a path (name) for the table, is all it takes to make it persistent. 6 | ; Nothing else in this code is required to make a persistent table. 7 | 8 | if !ht.loadedFromFile(){ ; The first time this codes runs, the file doesn't exist, hence the table is not loaded from file. 9 | msgbox("New table created!","Hash table example", 0x40) 10 | ht["Hello"]:= "and welcome" ; Adding a key value/pair to the new table 11 | } 12 | ; 13 | ; Use the gui to add and delete key/value pairs to the table. Reload the script to see that your changes persisted. 14 | ; You can delete the file from the Delete file button. 15 | ; Script exit on gui-close 16 | makeGui(ht) 17 | return 18 | ; Gui code. 19 | deleteFromHt(ht,btn){ 20 | if winExist("Hash table - tree view") 21 | winClose() 22 | ht.delete(btn.gui.control["key"].value) 23 | local f:=objbindmethod(ht,"toTree", "R20") 24 | setTimer(f,-1) 25 | } 26 | addToHt(ht, btn){ 27 | if winExist("Hash table - tree view") 28 | winClose() 29 | ht[btn.gui.control["key"].value]:=btn.gui.control["val"].value 30 | local f:=objbindmethod(ht,"toTree", "R20") 31 | setTimer(f,-1) 32 | } 33 | deleteFromDisk(ht){ 34 | if ht.deletePersistentFile() 35 | msgbox("File deleted!","Hash table example", 0x40) 36 | else 37 | msgbox("File not deleted!","Hash table example", 0x10) 38 | ht.makeNotPersistent() 39 | return 40 | } 41 | guiClose(hgui){ 42 | try 43 | hgui.destroy() 44 | exitapp() 45 | } 46 | makeGui(ht){ 47 | local gui,add,del,tvb,rem 48 | gui:=guiCreate(,"Hash table editor") 49 | gui.addEdit("w250","Key").name:="key" 50 | gui.addEdit("w250","Val").name:="val" 51 | gui.onEvent("close","guiClose") 52 | add:=gui.addButton("w250","Add") 53 | add.onEvent("click", func("addToHt").bind(ht)) 54 | del:=gui.addButton("w250","Delete") 55 | del.onEvent("click", func("deleteFromHt").bind(ht)) 56 | tvb:=gui.addButton("w250","Open Treeview") 57 | tvb.onEvent("click",hashTable.toTree.bind(ht,"R20")) 58 | rem:=gui.addButton("w250","Delete file") 59 | rem.onEvent("click",func("deleteFromDisk").bind(ht)) 60 | onExit(func("guiClose").bind(gui)) 61 | gui.show() 62 | } -------------------------------------------------------------------------------- /hashTable.ahk: -------------------------------------------------------------------------------- 1 | ; TODO: 2 | ; Count delimiter pre splitAdd and rehash to the correct size beforehand. This will improve performance. 3 | class hashTable{ 4 | ; User methods 5 | hasKey(byref k){ 6 | return this[6].call(k, "Cdecl ptr") ? true : false 7 | } 8 | hasVal(byref v){ 9 | return this[9].call(v, "cdecl ptr") ? true : false 10 | } 11 | valGetKey(byref v){ 12 | return this[9].call(v, "cdecl str") 13 | } 14 | delete(byref k){ 15 | return this[4].call(k, "Cdecl") 16 | } 17 | clone(){ 18 | ; Use: clonedHt := ht.clone() 19 | local clone := this[14].call() 20 | return new hashTable(this.length(),,clone) 21 | } 22 | forEach(udfn,uParams:=0){ 23 | ; accepts function name, func / bound func obj. 24 | ; binary code address, eg callbackcreate("f", "cdecl fast") <- cdecl needed on 32bit ahk. Fast option recommended if ok. 25 | local cbid,r,cbfn 26 | this.setUpcalloutFunctions(udfn, cbfn, cbid) 27 | r:=this[8].call(cbfn, "uint", cbid, "Ptr", uParams, "cdecl") 28 | this.calloutFunctions.Delete(cbid) 29 | return r 30 | } 31 | forEachVal(byref val,udfn,uParams:=0){ 32 | local cbid,r,cbfn 33 | this.setUpcalloutFunctions(udfn, cbfn, cbid) 34 | r:=this[13].call(val, "ptr", cbfn, "uint", cbid, "Ptr", uParams, "cdecl") 35 | this.calloutFunctions.Delete(cbid) 36 | return r 37 | } 38 | count(){ 39 | local table := NumGet(this.table,0,"Ptr") 40 | return numget(table, A_PtrSize*2+12,"uint") 41 | } 42 | length(){ 43 | local table := NumGet(this.table+0,0,"Ptr") 44 | return numget(table, A_PtrSize*2+08,"uint") 45 | } 46 | getMaxload(){ 47 | return this.maxLoad 48 | } 49 | setMaxload(newMax){ 50 | local prevLoad 51 | local table := NumGet(this.table,0,"Ptr") 52 | prevLoad := this.getMaxload() 53 | numput(newMax, table, A_PtrSize*2,"double") 54 | this.maxLoad:=newMax 55 | return prevLoad 56 | } 57 | splitAdd(keys,vals, del:="`n",constVal:=false,isByref:=false){ 58 | if del == "" 59 | return this.splitAddNoDel(keys,vals,constVal,isByref) 60 | if isByref ; For very large input, pass keys and vals by address and specify true. Improves performance. 61 | return this[constVal ? 11 : 10].call("ptr", keys, "ptr", vals, "wstr", del, "cdecl") 62 | return this[constVal ? 11 : 10].call("wstr", keys, "wstr", vals, "wstr", del, "cdecl") 63 | } 64 | splitAddNoDel(byref keys, byref vals, constVal, isByref){ ; Call splitAdd, specifing del:="", instead of calling this directly 65 | if isByref ; For very large input, pass keys and vals by address and specify true. Improves performance. 66 | return this[12].call("ptr", keys, "ptr", vals, "int", (constVal?1:0), "cdecl") 67 | return this[12].call("wstr", keys, "wstr", vals, "int", (constVal?1:0), "cdecl") 68 | } 69 | addFromFile(path){ 70 | ; See toFile for file layout. 71 | local keyBytes, valBytes, error, success 72 | local keyBuf, valBuf, nKeys 73 | local fo := fileOpen(path,"r") 74 | if !fo 75 | throw exception("failed to open file: " path) 76 | try 77 | keyBytes := fo.readuint() ; Read length of keyBuf, in bytes 78 | catch error 79 | throw (fo.close(), error) 80 | try 81 | nKeys := fo.readuint() ; get number of key/value pairs 82 | catch error 83 | throw (fo.close(), error) 84 | success := keyBytes == fo.rawRead(keyBuf,keyBytes) ; read the keys 85 | try 86 | valBytes := fo.readuint() ; Read length of valBuf, in bytes 87 | catch error 88 | throw (fo.close(), error) 89 | success *= valBytes == fo.rawRead(valBuf,valBytes) ; read the values 90 | fo.close() 91 | if !success 92 | throw exception(A_ThisFunc " failed for path: " path ".") 93 | this.checkIfNeedRehash(nKeys) 94 | if !this[15].call(&keyBuf, "ptr", &valBuf, "uint", nKeys, "Cdecl") ; add to table, addNullDel.c 95 | return 0 96 | return keyBytes+valBytes ; return number of bytes in the added data. (only includes key/val bytes) 97 | } 98 | copyFrom(ht){ 99 | ; Adds all key value pairs in hashTable ht, to "this" 100 | /* 101 | typedef struct copyParams { 102 | tableData** destTable; 103 | pfnLib lib; 104 | put pput; 105 | } *pparams; 106 | */ 107 | ; Set up copyParams, these are uParams for ht.forEach(...) 108 | local uParams 109 | varSetCapacity(uParams, 3*A_PtrSize) 110 | numPut(this.table, uParams, 0, "Ptr") ; hash.h 111 | numPut(hashTable.fnLib, uParams, A_PtrSize, "Ptr") ; hash.h 112 | numPut(hashTable[5], uParams, A_PtrSize*2, "Ptr") ; hashPut.c 113 | this.checkIfNeedRehash(ht.count()) 114 | ht.forEach(this[16], &uParams) ; this[16] is copyFromHashTable.c, see initBin() and initBoundFuncs() (in the last it is just a comment) 115 | return 116 | } 117 | toFile(path){ 118 | ; File layout: 119 | ; bytes 0 - 3, uint: keyBytes, number of bytes for keys 120 | ; bytes 4 - 7, uint: count, number of keys (and values) 121 | ; bytes 8 - 8+keyBytes-1, keyBuf, all keys, '\0' delimited 122 | ; bytes 8+keyBytes - 8+keyBytes+3, uint: valBytes, number of bytes for values 123 | ; 8+keyBytes+4 - 8+keyBytes+4+valBytes-1, valBuf, all values, '\0' delimited 124 | ; 125 | local raw, success 126 | local fo := fileOpen(path,"w") 127 | if !fo 128 | throw exception("failed to create file: " path) 129 | raw := this._toString("","",1,true) ; get keys 130 | fo.writeuint(raw.bytes) ; write length of keys 131 | fo.writeuint(this.count()) ; write count 132 | success := raw.bytes == fo.rawWrite(raw.buf, raw.bytes) ; write keys 133 | this.free(raw.buf) 134 | raw := this._toString("","",2,true) ; get vals 135 | fo.writeuint(raw.bytes) ; write length of vals 136 | success *= raw.bytes == fo.rawWrite(raw.buf, raw.bytes) ; write vals 137 | this.free(raw.buf) 138 | fo.close() 139 | if !success 140 | throw exception("Failed to save table to file. ( " path " )") 141 | return raw.bytes 142 | } 143 | rehash(newLength:=0){ 144 | ; "Manual" rehash. Typical usage, when removed many values, shrink the table. 145 | local newTable 146 | local prevLength:=this.length() 147 | local table := NumGet(this.table,0,"Ptr") 148 | if newLength==0 149 | newLength:= (this.count() / this.maxLoad) * 2 ; If new length is 0, choose the new length to be half way from reaching the maxLoad. 150 | if newLength == prevLength ; No need to rehash if already at desired length 151 | return prevLength 152 | this.initSize(newLength) 153 | numput(this.nextSize-1, table, A_PtrSize*2+16,"uint") 154 | newTable:=this[3].call() ; rehash. 155 | if !newTable { 156 | this.initSize(prevLength) ; updates this.nextSize 157 | numput(this.nextSize, table+0, A_PtrSize*2+16,"uint") 158 | throw exception("Rehash failed. New length: " newLength) 159 | } 160 | NumPut(newTable, this.table, 0, "Ptr") 161 | this.size:=this.length() ; not really needed. 162 | return this.size 163 | } 164 | ; Persistent related 165 | deletePersistentFile(){ 166 | ; Deletes the file in this.path 167 | ; Note: you should also call makeNotPersistent() if you do not want the table to be saved when exiting the script 168 | ; Returns true on successful deletion. 169 | return fileExist(this.path) ? fileDelete(this.path) : false 170 | } 171 | makePersistent(path:=0){ 172 | ; Specify a path / file name where the table will be saved upon release. 173 | this.path := this.path && !path ? this.path : path ; Update path if specified 174 | this._isPersistent:=true 175 | } 176 | makeNotPersistent(){ 177 | ; Unflag the table as persistent. 178 | return this._isPersistent:=false ; keep path 179 | } 180 | getPath(){ 181 | ; Returns the path of a persistent table 182 | return this.path 183 | } 184 | _isPersistent:=false 185 | isPersistent(){ 186 | ; returns true if persistent, else false 187 | return this._isPersistent 188 | } 189 | _loadedFromFile:=false 190 | loadedFromFile(){ 191 | ; returns true if the table was loaded from file, else false. 192 | return this._loadedFromFile 193 | } 194 | ; Methods for viewing the table. 195 | toString(del1:="`t=`t",del2:="`n"){ 196 | return this._toString(del1,del2,0) 197 | } 198 | keysToString(del:="`n"){ 199 | return this._toString(del,0,1) 200 | } 201 | valsToString(del:="`n"){ 202 | return this._toString(0,del,2) 203 | } 204 | toTree(opt:=""){ 205 | local gui,tv,parents,cbfn 206 | if opt == "" 207 | opt:="R20 w400" 208 | gui:=guiCreate(,"Hash table - tree view") 209 | 210 | tv:=gui.addTreeView(opt) 211 | gui.addText(,"Number of key/value pairs: " this.count() ". Table length: " this.length() ".") 212 | 213 | parents:=[] 214 | cbfn:=ObjBindMethod(this,"_toTree",tv,parents) 215 | this.forEach(cbfn) 216 | gui.show() 217 | WinWaitClose("ahk_id " gui.hwnd) 218 | gui.destroy() 219 | return 220 | } 221 | ; Print tableData struct. 222 | printTableData(show:=true, extra:=""){ 223 | local table := NumGet(this.table,0,"Ptr") 224 | local outstr 225 | outstr:= "Buckets: " . numget(table, A_PtrSize*0+00,"ptr ") . "`n" ; Buckets (the address) 226 | . "tableSizes: " . numget(table, A_PtrSize*1+00,"ptr ") . "`n" ; tableSizes (the address) 227 | . "maxLoad: " . numget(table, A_PtrSize*2+00,"double") . "`n" ; maxLoad 228 | . "length: " . numget(table, A_PtrSize*2+08,"uint") . "`n" ; length 229 | . "numKeys: " . numget(table, A_PtrSize*2+12,"uint") . "`n" ; numKeys 230 | . "nextLenInd: " . numget(table, A_PtrSize*2+16,"uint") ; nextLenInd 231 | . "`n`n" . extra 232 | if show 233 | msgbox(outstr,"Hash table data",0x40) 234 | return outstr 235 | } 236 | ; 237 | ; End user methods 238 | ; 239 | ; Nested class 240 | ; when making a new hashTable, a reference to a "router" is returned. the "router" contains the reference to the new hashTable object. See __new() 241 | class router { ; For familiar array syntax, i.e., [value := ] myHashTable[key] [ := value] 242 | __new(ht){ 243 | ObjRawSet(this,hashTable,ht) 244 | } 245 | __set(byref k, byref v){ 246 | this[hashTable,5].call(k, "wstr", v, "Cdecl") 247 | return v 248 | } 249 | __get(byref k){ 250 | return this[hashTable,6].call(k, "Cdecl str") 251 | } 252 | __call(f, p*){ 253 | return this[hashTable][f](p*) 254 | } 255 | __delete(){ 256 | static ht:=hashTable ; Because needs to call destroy() for persistent tables even if hashTable has been deleted. 257 | this[ht].destroy() 258 | } 259 | } 260 | ; Init methods. Most init methods are called by __new. NOTE: There is "static" init in maketableSizesArray() 261 | static init:= false 262 | maxLoad:=0.7 263 | __new(size:=23, path:=0, clone:=0){ 264 | ; The clone parameter is intended only for internal use. When cloning a hash table. 265 | if !hashTable.init 266 | hashTable.initBin(),hashTable.makeFnLib() 267 | this.icbfn:=callbackcreate(this.traversecalloutRouter.bind(this),"cdecl Fast",6) 268 | this.initSize(size) 269 | this.initTable(clone) 270 | this.initBoundFuncs() 271 | this.loadFromFileIfPersistent(path) 272 | return new hashTable.router(this) ; returns a "router" object, which has a reference to the new hashTable. Use all methods on the returned router object. 273 | } 274 | loadFromFileIfPersistent(path){ 275 | if path && fileExist(path) 276 | this.addFromFile(path), this._loadedFromFile:=true ; The file exists, load 277 | if path 278 | this.path:=path, this._isPersistent:=true ; If path is specified, set _isPersistent to true, for auto saving on delete. 279 | return 280 | } 281 | initBin(){ 282 | ; Can be freed via freeAllBins() (you shouldn't) 283 | ; See c source 284 | local pnewTable,pdestroy,prehash,remove,pput,pget,pfindKey,ptraverse,pfindVal,pmultPut,pmultPutConst 285 | local pmultPutNoDel,pforEachVal,pclone,paddNullDel,pcopyFromHT,pgetFromHash,pnext,j,raw 286 | if A_PtrSize == 4 { 287 | pnewTable := [2203276887,267526380,1009009680,807695499,874806411,539231431,4060086272,608440591,2245525272,2304275648,3036974531,0,4280550537,2311095767,2235855875,823424246,2332224466,2416232195,0,956416643,2347791830,4063765572,608964623,276007192,1328071,4060086272,139137295,2332312457,2302944324,3632863299,1528874115,834887518,2432035776,2425393296,2425393296,2425393296] 288 | pdestroy := [1398167381,2334977155,2336236612,2336498780,608471312,273320732,1165281669,2422669105,747307659,1961723320,649366833,0,2332317067,344522869,72613668,2299024779,1409229844,606898436,1409283465,1979090180,608472031,2333117212,3347255370,1926183169,2298645439,1409229828,608471812,2298514204,2336236612,3296920643,1600019244,2430664541] 289 | prehash := [1398167381,2336025731,2337285188,71994128,2333622923,4286939452,673479817,18383887,3229810688,608471297,608471828,269480532,1284048962,267520036,203703313,1149829259,1149961252,76097572,608471844,273743700,3347693701,14713871,1149960192,9130020,2299809931,1351291991,265454864,39812,608487168,44,611617536,7769388,881526923,1962313137,649366898,0,2332317323,444206,251658240,2238057143,2407796681,2197815296,3224437442,443,3417247488,16958083,3252259272,3643344353,3071265673,2238119498,837187017,611645394,2500103464,0,143329027,74828165,3247001835,3229942155,831125621,4002016645,1150000757,9130020,2198884491,19670084,740586635,2182075961,4294967156,76087435,608471844,72417108,1344554123,76087435,608471844,72417108,2302461059,1600019448,814334813,3224483563,3296960235,1539322172,3277676382,2425393296,2425393296,2425393296] 290 | remove := [1398167381,2334977155,256386140,2238067639,3817082870,251658240,29349559,822083584,264843712,3246643119,153914625,4203335681,688251585,265783802,1716196535,3816149637,405040265,1076133003,1066127921,2333112311,2416217351,1149843595,4286913572,11109391,3979411456,1468778885,1714058244,812986937,1820966961,317396004,649366928,0,1127003919,1110194534,3229816437,1976056065,611093487,608471828,1015244312,427032578,4253616011,74760325,3102459785,3089941635,2,1566531163,2347599299,2304144391,1149960261,344540196,72417060,2299021195,1149969412,1358906404,608471812,607947076,2332315903,2336236612,342393600,751076097,440,1600019200,1153942365,6180,3224436736,971622705,2214592511,3224448196,1566531163,611617731,2332461340,2733311063] 291 | pput := [1398167381,2338122883,2340168788,2339644540,1719149684,251673219,82308,3955241216,2379778306,2204500312,1962957372,4492788,609519876,604277032,1418401791,3314100260,3071262769,2305180172,2197833036,3275293120,1150021747,1418555428,9128996,270816393,1210340493,203707529,2299547787,2298750068,2332566612,604276992,2198362111,21767292,874792073,12157967,80150528,3108,1712848640,2298494595,3414429633,822083584,2298670016,22580696,1581024102,2381608192,2298740804,2301109324,402596868,2422657585,1443673871,1342998886,956416643,2347857626,2301109324,1149961281,29838372,0,2231921033,2336978112,2301895748,608471816,608487280,44,2346397952,342919936,2366654603,1418264918,1351165988,611114772,608995624,610044200,611114796,138992680,3923757529,1316477149,3296968753,1600019292,1150010205,1418424356,9127972,210305163,2309680016,138447814,4280550537,1854473303,1556382472,440,1600019200,45663069,822083584,4274514395,45678591,822083584,4282247643,1150025727,2089381924,76088356,207093540,1881439371,4290250633,3959422975,2425393305,2425393296,2425393296,2425393296] 292 | pget := [2336025731,2369791044,2334925908,609519872,609520912,609519912,273713932,136598665,1210340491,69489801,76087435,608471844,139525956,2089013809,1963011108,139496195,3296972937,2425406268,2425393296,2425393296] 293 | pfindKey := [1398167381,2332355715,253502556,2238067639,3447984118,251658240,29218487,822083584,264843712,3246642607,154963201,3934900225,688251585,265652714,1716196535,3816149637,1962398257,76357668,149,611093248,5605668,673469579,711,1418395648,747313188,267224322,33924,7769344,1435224453,1713665028,645214777,2305212465,3942786164,884412170,876176963,2200008002,3359179200,3071274869,1711416436,3816579,1166749300,1958774016,3955591443,7769539,251676043,35943607,3983917189,673465483,131271,3901292544,1527039107,3277676382,673465483,65735,3296919552,1541966084,3277676382,3224502065,3375485489,4294925545,3955241471,2425393363,2425393296,2425393296] 294 | ptraverse := [1398167381,3677484593,2336025731,2337285188,273189632,2215627141,265,11867277,2298478592,2334925908,2990312208,2215640965,230,1150020913,3280166948,611617025,610044176,608471304,608471828,608471388,138906380,69485705,2298759051,1426007044,4169357348,2122151167,1958774041,33063791,126582389,3230006665,9667599,3347644416,4169381099,113150,1685389312,1284048779,1149839396,1200301092,604276996,1411662987,2332315903,76089415,608471844,72417108,1411662987,4280564873,3984917584,606356619,673467531,1166621300,609520384,2199030608,2231440490,3097457865,4294967294,1530709123,3277676382,2766915889,649366928,0,3347708041,4294917609,649367039,0,1344558219,740588683,311104139,3946448009,608471992,2332068688,3330478152,265173249,4294899586,112895,2968190976,2425393296] 295 | pfindVal := [1398167381,2333142147,254551132,2238069687,2844004351,822083584,29459401,1262256998,153914624,1150022517,9118756,2232438923,609520082,2338944008,608487168,4,608471296,608471820,609520396,2419362564,1031075461,1452001669,1713992712,729102905,881442865,2299783972,666668534,0,1127528207,1110718822,3229824629,1976056065,607423471,708608870,2334815232,1979090230,608469955,1149960452,1144587300,2775910436,823182467,1600019392,3062743901,0,3945018507,71732182,1527825539,3277676382,3375492401,4294925801,2425393407,2425393296] 296 | ; -O3: 297 | pmultPut := [4281423701,3968029526,615811964,160,3347645163,1711359885,4266032259,267613440,2626367159,38948,268403968,1059341461,807683271,0,673465543,0,874792135,0,649366928,0,874792075,673465347,256052365,2238054839,1712354496,2215635001,1243,673465475,1725819649,125169029,1059355776,2235004160,608487423,64,824931584,7769563,807683211,2619640971,16777216,1091341784,1711388431,678740101,266877286,278404,29590272,3224492779,673465345,1076118727,1,1989002731,666668288,0,1978500454,612139019,2232352831,1221,2232418181,1213,673475723,36521101,1210336393,2334393481,9708676,285147136,1149889925,2215589924,647,874792075,268457101,2314224269,55321668,9970820,3314089984,941900939,1143237769,957368461,3247640525,2357972361,38948,969998592,266897864,3356017043,81560591,1284177920,4186122276,3481669390,2332033028,2202281028,3906015200,3766737143,264780039,3375481159,2215624837,179,2552540299,2332033024,2201232460,3071214072,2332052812,1714955372,251678089,324228,613190400,152,251852931,4061220023,38635878,80708623,2357919744,38948,66618112,290240271,1300850420,2894335748,2332033028,9970828,4169334784,1287065348,2305226257,2215577165,1161,2552532107,2197815296,3071215096,1727533388,252202377,288388,613190400,152,252180611,4195437751,172853606,71533839,2357919744,38948,1421283072,129629201,1711276032,2332841353,690496596,2378170818,1418328170,3988870180,22383875,1143231625,2298733249,2337285204,2369266772,1141047852,3526446116,2552529923,1711276032,2197843727,3313697218,281051920,4031058191,1143231545,1150019959,3238088740,1411662907,2215627401,267,874792075,1143231625,1143229579,1149878785,2223721508,38948,23694592,673475641,1343534863,941900939,1209305446,2249190025,215,1277455499,1277449353,3506563465,2552534155,251658240,2336885943,1716266068,2337279113,2370053196,1413022289,1418274852,2249149476,163,3506563465,2552534155,251658240,2336885943,1716266068,2337279113,2370053196,1413022545,1418274852,2071350308,3506563465,2552534155,251658240,2336885943,1716266068,2337279113,2370053196,1413022801,1467361316,2894850441,38948,265355520,5065911,1342998886,1143229579,956649869,1982342228,608996150,265355572,5065911,1342998886,1143227531,956743811,1982342212,608996122,18124084,2552532107] 298 | pmultPut.push([251658240,2337346743,1714955340,2336298121,2335712324,826811468,458526189,1820943874,2223767048,37924,605325568,1143231625,1284182271,3314102308,2619638923,2365587456,3224455180,649366928,0,1091876623,1163168102,29393664,4034118457,874792075,1143231627,4160866609,673465347,357337446,608471550,608471860,33030448,610045400,608471404,612666160,144,1552482443,1552748580,1552508964,1552616484,1351301156,610044176,609519876,2298514184,2223711236,37924,139525888,1814330499,264472833,96132,612666112,148,203687111,4278190080,609520400,608996204,51000,2298478592,3531933800,251938953,50309,614238976,144,1747209355,311104395,2307523721,3339750360,2892868,822083584,339905499,2198882955,1149829568,1116284964,611114772,608995624,610044200,611114796,139123752,3923757529,2265962717,313,1076118667,2232402053,288,3341727503,2630724,2332033024,9970844,1776877568,2315255803,666668534,0,2215640965,4294966256,3062743089,0,251773059,1715541175,256250937,99461,264714496,97414,3531957760,3342459509,4223829007,1418461183,3531948068,8225807,3271622656,4294684649,2332264959,9446532,1122566144,2248146943,1753485311,822083585,29393856,1091876623,1175730534,3342409333,2238061174,971666898,608487367,64,1099239168,3925868539,4294966031,1153943353,16420,2215575552,4294966015,265454950,4294648708,608436735,614239016,152,4294618089,609520639,2243965248,2206430674,3224468676,1566531163,649366979,0,2299019403,2223711236,37924,72417024,941900939,2334393481,9708676,1358888960,608471812,141265216,2215624837,4294967008,3095184515,1,1566531163,612666307,148,69485705,2418312331,2298478592,2223711236,37924,206634752,2418318475,2298478592,4271565059,1284243455,1821059108,3526440996,1143227531,1277451401,2520205,1344059151,1432127846,29524736,4034253113,1277451403,4294785769,440831,3370713088,3120562171,5,4294688489,309759,3035168768,3120562171,3,4294683369,178687,2699624448,3120562171,1,4294678249,264714751,4294593412,3531958015,4269835279,3230007295,441,3242462976,3655975681,3355443193,4203588,3909091328,4294965703,2425393296,2425393296,2425393296]*) 299 | pmultPutConst := [4281423701,3967898454,172,3357842571,2332033024,13640884,116064256,2520205,1200473993,2088986113,1962999366,2311074291,824976508,2345109961,13378732,82509824,3515467657,2365736845,2204500305,16647548,76410485,612141330,612141908,2311751980,13640884,1284046848,1149845540,3071237156,2245953798,608487423,56,614238464,200,608474383,1149855315,2223714340,52260,266371840,3640125649,956817539,3242659784,1149879689,3364450340,2223630377,32804,4164979968,2198071489,1149829568,3770774564,608471299,4282551676,1149888553,1150118948,3979411501,2015642761,3424945155,2298478592,8660100,2223702016,52260,281051904,1612989577,649366928,0,941900939,210626561,28774214,1958774118,1144743440,2215587876,1397,3942761859,2088986335,1962946596,612139019,2232352851,1824,740574347,2232402053,1812,1009009863,0,36521101,1143227529,2334393481,12854404,285147136,1149889925,2215587876,510,941913227,1334691721,911510800,4030893328,1277445257,3357836291,956301312,613190600,200,608473871,1555435336,3506522148,2467286841,264964289,425860,251495168,108430863,3766681600,608487183,72,4159230208,132154328,1192224825,264275397,36996,614238976,200,251787395,1718815927,2215579529,1790,3357838475,2197815296,3071214328,1727140172,251809673,448644,615811840,200,251918467,4095102135,72321382,112362511,3071213568,2213942860,2305164536,2215577167,1683,374126351,100172792,139430246,108299279,3071213568,2214205004,2305165304,2232355407,1621,374650639,608487420,1864,1468622336,2347469068,2337023060,690758780,2378170819,1552545867,3254872100,807683075,3357840387,3238002688,1502413801,2378772737,56628,1552482304,2626377764,51236,611617024,615811940,208,40832870,2197930371,3229814978,1074859792,608975856,2313777752,13640884,1149960192,1955285028,2089378852,2626235428,51236,1005584640,258483316,34180,2346682624,2335712348,2368742516,3071214356,2305185556,1351435796,1993685249,319589737,1326233359,1443662182,956453005,2371319509,3071218444,2305183500,1351439884,1993685251,319589701,1326233359,1443662182,956584077,2368960213,3071218444,2305183500,1351439884,1993685253,319589665,956743811,213323717,210331215,2333046358,2369266780,3071214356,2305185556,1149978132,1955278884,4281418788,813468006,608472062,604277084,3290727563,4278190080,2344716560,2235573316] 300 | pmultPutConst.push([3749973952,989855745,2371888204,2467237953,612645314,204,146838287,813961154,2197815300,239084668,69568015,1552613376,3682955300,63013903,2223702016,52260,33260288,1711322895,2215575945,1191,3424945291,2197815296,3071214331,2305163840,2215576129,1157,3424945291,2197815296,3071214587,2305164352,2215576641,1123,3424945291,2197815296,3071214843,2305164864,2215577153,1089,3424945291,2197815296,3071215099,2305165376,2215577665,1115,3424945291,2197815296,3071215611,2305165888,2232355393,1081,3424945291,251658240,1712079031,3087810953,7,1814330499,2339468806,829957236,611092955,608471364,613714760,132,2089539721,2626366500,51236,2311979264,615812085,208,175050598,2197930115,3263369413,1292963600,608451056,2347333492,2303206468,13116572,1552613376,1821080612,2089370660,3028888612,53284,1004011776,8397980,2215575552,146,3424957579,251658240,1715868855,2202080393,1144586688,2054570020,1175762703,1076130955,1091864934,956387469,2338813654,13378716,3071213568,2305184540,1351438620,1993750786,614239057,204,1394390799,1360824678,956518541,2335930070,13378716,3071213568,2305184540,1351438620,1993750788,614239013,204,956678275,481759174,478766675,2333046353,13378716,3071213568,2305180436,1149976852,3677443108,2619651213,2298478592,1715741772,2332105865,2369266756,9970844,1141047296,3892390948,941900937,3223618699,2332033024,611617024,610044176,611617548,273713968,69497993,136598665,76087435,612666148,196,2198360319,10233020,2298544128,608996293,1619267396,2332033025,12854404,1284046848,80167972,3108,2333146880,2336498764,3341821044,0,138971392,2619640971,2298478592,3380937840,18515215,3029008384,49188,613190400,152,311105163,2307523721,3339750384,3417156,822083584,339905526,2198887051,1149829568,1116287012,611114772,610044208,611617072,611114804,139123760,3923757529,2265962717,330,1009013899,2232406661,259,3492054155,822083584,615812077,200,1711322895,807683209,4294602729,608472063,264275244,4294615940,2347993599,2334925948,13640884,3224436736,2520205,251773059,1715541175,1967526969,1992767811,3531957823,3342461557,740588681,3357842569,2298478592,13640884,1153892352,15396,2215575552,4294965856,1153942785,80932,1374224384,2315255802,666668534,0,2089404217,2626235428,51236,615811328,208,4196828175,2238119935]*) 301 | pmultPutConst.push([29979858,3923675589,4294965720,649366928,0,2332050825,12592260,4008247296,2348810238,1284048960,76104740,612666148,196,2332315903,2301633604,2223711236,50212,72417024,1009013899,1143229579,1300877957,4253290248,2181038078,44228,112640,1583022080,834887007,612139968,2265908844,4294966491,3424945291,2332033024,13378740,3071213568,25781760,440,4249282816,2223767551,50212,608471296,612666116,192,2334393481,12854404,1358888960,615811852,192,2313750153,2315255806,2336498796,824976508,609520576,615287616,204,3492066443,2415919104,2520205,1163704079,478766592,29393729,4034249273,1143237771,740588681,3492066441,3909091328,4294966606,740588683,807685259,3029062193,53284,481758976,478766672,29524817,4051031353,740588681,3492066441,3909091328,4294966034,1153941553,80932,3305177088,4294501353,309503,4192796672,3103784955,3,4294701033,178431,3857252352,3103784955,1,4294695913,440575,3521708032,3103784955,5,4294690793,608487423,1608,4189055232,1153957887,346148,2733178880,3355443193,71836740,3909091328,4294965653,1210336455,3,4294543593,608487423,584,4185647360,1153957887,84004,1860763648,2432696313]*) 302 | pmultPutNoDel := [1398167381,2340220035,10495148,3029008384,39972,608487168,1076,1961723136,2210410775,2204500416,16664188,1149891957,3221303332,874792073,2089545865,3766693924,4159230223,132154328,1192228921,2314023367,608471489,704153916,608471496,4164980040,2198071489,1149829568,3770762276,608471299,2214103372,3358130664,1076118665,2299069581,22291524,608471536,273059152,941900937,2552530059,1711276032,6831235,22774799,3163226112,40996,268403968,89989,1015244288,2215575662,996,2485421195,3338665984,271364,285147136,1150011273,76100644,612666148,148,3280539903,2552530059,822083584,79106002,126445160,2305212465,3071214151,2305191428,2305163859,612666115,144,1814318221,1747211405,2332149123,608995584,609519888,273713932,69500041,136598665,76087435,612666148,148,2198360319,23864444,2215625353,652,673465481,2485421195,3338665984,795652,285147136,2332579977,3345753180,0,75008256,673469579,2232408965,588,2418326667,2332033024,2338858060,2299693847,4169763332,1153896587,11300,3677421568,2333360779,3229814858,608471297,339904808,673475807,673467529,740580489,673475807,3641199324,3723091913,3448115160,2348810238,9708676,1149829120,2223703076,36900,604276992,2485421195,4278190080,3163229264,36900,2332526848,9970820,2204499968,251684924,4294878597,2093253631,440,1600019200,3062743901,0,2485421195,3338665984,271364,285147136,1150011273,76100644,612666148,148,3280539903,2552530059,822083584,610024393,79105848,1334404712,3264417538,2366081382,3325628483,146838287,3246657474,2197815297,238036092,28739087,1284177920,3380952100,25854991,3071213568,33129222,251890022,134020,1186402048,49906434,37980518,32146447,3071213568,4186113094,1133078019,3380875012,251658241,2198226615,2305164537,2215577155,424,138852111,1711667587,252199817,100228,1186402048,133792522,172198246,23758095,3071213568,2305166406,129502275,2197815296,104866940,1284194934,1149850660,3224447012,2332759181,1716528204,2197909263,3246588352,281182992,4030861583,1143227451,1284237682,1149979684,3355519012,1210338361,4258759695,3062759423,0,1175762703,1125419366,956416131,254813252,4294818950,347541503,344548934,22056259,807687225,4255614479,3071279103,2305185292,1351439116,609499394,2458259248,268435453,1716915383,2371030153,1413022544,2249142308] 303 | pmultPutNoDel.push([4294966653,1443673871,1393330534,956584077,254813268,4294797446,213323775,96502614,807683129,1393330534,4250109455,3071279103,2305181204,1189692180,2432696317,2520205,2223702665,36900,4256884992,2422669311,2299019403,2301109332,2223711236,37924,72417024,2485421195,2298478592,1358898236,609520388,140151080,4294743017,7769599,2089009201,252067876,4294893959,112660479,3087239526,1,4294912233,7769599,807685259,1989001265,666668288,0,1175762703,1125419366,956416131,3924915649,4294966461,1720,4271499520,2422669311,1464,4270713088,3062759423,0,1208,4269664512,3062759423,0,952,4268615936,3062759423,0,696,4267567360,3062759423,0,440,4266518784,3062759423,0,830260355,1600019392,2425406301,2425393296]*) 304 | ; -Ofast: 305 | pforEachVal := [1398167381,2337074307,1718101100,32131,26772495,3677421568,1711391619,6126723,456428800,1150022261,4281425956,740574407,0,9171593,2232436875,2373481673,48436,1955135488,814429220,2243835019,3344790774,3155012,2415919104,2520205,1317788549,255030280,1711293879,829751609,1418313777,401287204,649366928,0,1163179791,339305984,2441416513,2197815296,3627614656,1418455669,2204510244,1946161468,2234944291,2344187382,2338333764,273189632,956417923,3095950031,1,1531757699,3277676382,673469577,1948537995,740574339,612141313,608471824,608995628,609519876,609520404,608471408,609519880,71731980,4280550537,2204902484,1418461176,2215585828,143,3229950846,4169380468,1300565761,2315255807,2335188084,2424892214,2520205,673469579,4294932713,4277699583,673465543,1,4280714511,109838335,1009013897,941900937,2298758795,1149969412,1358914596,138840836,2334393481,4284752964,1149961296,881419300,72417060,807695499,941900939,1009013899,628422277,1955268233,1284202532,915089444,18116227,729139589,283756169,3355443199,2630724,3942645760,611617693,608996192,2335607604,235178294,4130458859,1877596977,2214592510,4273491140,1543503871,3277676382,2425393296,2425393296,2425393296] 306 | pclone := [1398167381,2338122883,2339382340,2339644540,407931648,337925257,1074794482,286257672,2332828740,1418265680,394987556,69489801,2299543691,1476338692,2311095568,608471495,4119072572,2332033028,2339382340,340822784,2333366153,3531935824,81036303,1153892352,19492,2089484288,143346724,12399757,2298478592,2335450228,3984963884,63144975,1820917760,1988961316,666668288,0,1948533899,203687111,822083584,2299592667,2334663748,2334401604,3062694976,0,1711391619,4267211907,2348119296,824452164,138447862,1711392387,4268784771,2381673728,76094212,608471844,2299592564,906268103,2334393481,4285801540,2344978704,2334401604,1116537936,2378643728,2467237959,264387009,3238576275,56132623,4219666432,1334185742,2298478595,608487376,48,266371840,3640125649,956817539,3276214232,1953808517,2198517519,2305163768,2424573711,251658243,2197965495,2305164024,2215576143,882,72005391,1711536259,251940745,218244,1253510912,83395334,105875814,53904399,3071213568,4169336906,1334404613,1719930632,251658243,2198489783,2305165304,2232355407,840,206223119,807683271,7,206539110,1153948041,11300,1418264576,3240708132,1284096001,3917692964,65650952,2298593667,3241681996,1284047841,210584612,1727529218,2198433551,1149440192,2197892132,1418399937,286207012,1413214280,3815913508,1143229579,807683211,1210340491,1278855169,2054438948,1108129551,740574345,1192003942,956385421,258438859,1716126903,2337211529,2368480324,3409510984,3071235190,2305182212,1149980420,1217211428,1993029891,79105857,76113482,608471887,71863596,779537209,1241822991,1325697382,740574347,956647565,253458123,1716126903,2337211529,2200708164,3275294400,3071215734,2305180180,1149978388,1351296036,272993544,1116586553,3247640336,2467284281,264308928,123780,251560704,31098383,3498639360,3507478659,2212034536,4030269408,835077903,1958774235,179769202,1711405187,251678089,154500,1253510912,49840898,38635878,37782543,3071213568,4169335882,1300850179,629411588,251658242,2198227639,2305164536,2215577165,522,139114255,1711667331,252202377,126852,1253510912,133726986,172853606,30704911,3071213568,129698890,1711276032,2299284873,608487409,44,609519872,29436228,608995776,149521216,2198071745,1284047297,3787534372,608995587,34377016,258402305,3229815151,608469776,3246588204,609520400,1343295276] 307 | pclone.push([609499632,2346940208,2335712332,2302944340,1004011976,1950360652,213323625,1284073026,1217200197,1993226497,481759065,1552508490,1217200205,1993226498,481759049,1552508490,1217200205,1993226499,481759033,1552508490,1217200205,1993226500,481759017,1552508490,1217200205,1993226501,481759001,113279818,2305214009,1979731292,347541257,1418290754,1149960261,13051940,0,2298771593,1149962344,2089493540,9124900,606356617,874792075,277546755,74830469,3263790827,3229942411,1150023797,42543140,606356619,2232402053,4294966356,1881425035,1351286923,608469776,2089484620,3610856484,4229202447,1150025727,3296934948,1600019292,3224486749,1108129551,1192003942,956416131,3924915651,4294966790,649366928,0,3071262769,2305180172,2197833036,4030267840,1609166965,2315255807,666668534,0,673479819,2297116809,807683271,4,4294766569,608487423,816,4242729216,1153957887,143396,3588816896,3355443196,19932228,3909091328,4294966472,807683271,6,4294753257,608487423,1328,4239321344,112984063,3909091328,4294966831,1467,4263897344,79429631,3909091328,4294966811,955,4262586624,45875199,3909091328,4294966791,443,4261275904,3296985087,1543014748,3277676382,828163203,1600019392,2425406301,2425393296,2425393296]*) 308 | ; -O3 (paddNullDel) 309 | paddNullDel := [1398167381,9235585,3029008384,45092,267814144,365700,615287552,168,941900999,0,1076118727,0,1009009863,0,649366928,0,1009009803,822086797,223645120,981689856,3910104320,1601,649366928,0,1485691017,1015244289,4101308506,2298658947,2301109340,21767236,608471488,48792400,1411662985,1076118667,2888088715,16777216,2311520704,1715741764,251674499,381828,2344628480,3945276508,649366793,0,1888350345,1015244289,4101308535,2298658947,2301109340,2301895796,22553668,608471488,48792412,1612989577,1344554123,1210340489,807685257,2334393481,10757252,285147136,807685259,1150141065,3258519565,2467287177,254813252,807689398,2299576451,2335188052,961029204,3230863298,2215625480,1296,673471627,252640131,328582,3352725760,4727876,2197815296,4035514342,3640125649,956817539,3276214232,2215624837,130,2333259535,2200970332,2305163768,3968077587,251658245,34428087,1711470723,251810697,379268,1421283072,4169335821,1401513475,2793672452,251658245,101536951,1711601795,252072841,361348,1421283072,4169336845,1401513477,1619267336,251658245,168645815,1711798403,252334985,343429,1421283072,1153895437,477220,2305163264,1552616531,3733530660,3221341737,2314753677,3243254900,1921844202,18124033,807683075,1955186993,3871418404,2313814275,2338595956,1714693236,2197974799,3263365569,281051920,4030730511,673467451,1284237682,1149985828,1552500772,1955145764,3355522084,1344556089,10716175,1284177920,1955281956,344797220,1421283073,2305163349,1351435796,609499393,2189823784,2298478592,265355723,5065911,1443662182,956453005,1982342228,31033708,1287065553,2305163341,1351439884,609499395,2304144936,265355737,5065911,1443662182,956584077,1982342228,31033664,1287065553,2305163341,1351439884,609499397,2301261352,113279961,1144639745,3071223844,1711295820,1985350793,608996116,18124092,807685259,1431615247,344548864,608471873,608996144,1725641044,2332564617,2304517188,2223711236,42020,2333146880,11281548,1955266560,3280552996,2366657421,957362500,3230863299,2467288889,264374466,211844,609520384,251298612,53380623,4186505216,2299519363,4159230408,132154328,1192218681,2244555202,2156138432,251658240,4169340855,327771649,59409423,2357919744,44068,49840896,3071276937,1711419732,251810697,222596,1421283072,4169335865,1401513475,1233391364,251658243,104420535] 310 | paddNullDel.push([1711601795,252072841,208260,1421283072,4169336889,1401513477,1300500232,251658243,171529399,1711798403,252334985,209285,1421283072,129567801,1711276032,2332840841,2301895796,29829623,4166487488,1344568457,2365844161,3526427002,673479817,2298734529,2370315388,1141048124,2214806564,44068,1863280128,29524744,2198914947,286200000,1413083215,3916900388,1210350731,874804361,3355572361,1344568379,10781711,2089484288,3029024804,44068,118787328,1444198159,1125419366,956387469,255075412,33158,386698496,1309456143,1393330534,956453005,1983128660,973901165,1309456143,1393330534,956518541,1983128660,386698585,1309456143,1393330534,956584077,1983128660,386698565,1309456143,874804363,1393330534,956649613,2368698070,3163232012,44068,113279744,3071264313,2305183500,376853260,1076133003,2332497037,11281596,3071213568,2305185556,1149977364,3375456292,1277457547,2082765965,1009021953,2015655053,51153254,2686747787,2332033024,22553676,2336236620,608996096,611617072,612141324,273713936,69487753,136598665,76087435,612666148,164,2198360319,24913020,2215626377,172,2753856651,3338665984,795652,285147136,2082755723,807685259,199,1485373440,2312275208,1953825864,2686762123,2332033024,2339906636,2299693847,4169763332,1153896587,11300,3677421568,2333360779,3229814858,608471297,339904808,673475807,673467529,740580489,673475807,3641199324,3723091913,2204727256,20456516,941900939,2955183161,251658240,4294611845,2361688575,3087007744,1,1566531163,7769539,2223703689,40996,2425744128,2520205,2299019403,2223711236,42020,72417024,807683211,2334393481,10757252,1358888960,140413188,1988993515,666668288,0,2753856651,2298478592,2332304452,10495108,76087296,612666148,164,2332840191,10495164,126418944,4294929129,7769599,673471627,807685259,3062743089,0,1110750991,1093962086,956416131,3924915651,4294966401,874804363,3062743089,0,1192539919,1125419366,956416131,3924915654,4294966866,1612989639,2,1545880775,4,1478771911,2,874792135,1,4294590441,608487423,596,608487168,1104,608487168,588,608487168,296,4190562560,79298559,3909091328,4294966523,953,4243712256,45744127,3909091328,4294966503,441,4242401536,112852991,3909091328,4294966483,1465,4241090816,1153957887,411684,1552613376,3353946148,3355443194,88613956,2332033024,3911722076,4294965942,1210336455,4,673471627,4294616553,608487423,840,610044672,4204063016,1153957887,149540,1552613376,2213095460,3355443194,21505092,2332033024,3911722076,4294965874]*) 311 | pcopyFromHT := [2333928579,2334401620,2301895748,2332828756,2300585044,2332566612,1418265680,277546020,4280554633,28837968,2197815296,2428705988] 312 | pgetFromHash := [609520467,608471820,610044680,2416216848,896843909,1946286979,2231405360,2200728768,662045179,442,2416700160,2520205,192207417,143378569,2231485059,972125641,47827,1158610944,834886594,2428722112] 313 | pnext := [1398167381,2333928579,2335188060,2335450220,2335712380,2335974516,4232416019,1913668155,3342723865,130119,1166737408,2199096316,1166606784,272775676,1334519414,608471548,608995588,2298645256,3607045124,3547644037,33310595,1528611971,3277676382,2520205,823968899,1600019392,2425406301,2425393296] 314 | } else { 315 | pnewTable := [1398167381,955024200,611592463,1221495072,2303513993,672097991,2669043,3539927040,1220576584,1786037129,3242783113,3590259681,1220576584,1517552521,678753925,838815373,3787540690,1712384771,8658703,0,1208191816,1208533635,3343436345,4100,3967090688,2149876875,4060086272,275976463,142313800,3340268425,7235,1133051904,3632875552,611592207,3296938016,1600019256,3224486749,2425417451,2425393296,2425393296] 316 | pdestroy := [1465209921,2202555222,2303205612,294340822,2345437513,3380942922,3979428724,4202255,2298645324,478890472,3682945216,2422614132,1211861832,4278733707,2336753750,1459556427,3649652744,4294674760,2236090454,1239512575,2334397579,3313702986,1926052097,176900291,1208506111,1225279115,1210322059,1528874115,1096638302,3774826588,2425393296,2425393296] 317 | prehash := [1413567809,1398167381,955024200,1222084936,2303201675,541756366,138578764,2283572033,2244512072,243535835,2197815297,267518400,2299550224,608471513,395003936,1210079231,2303246469,4001632197,1207959552,1250629259,474123032,1166657925,2927890204,1157627904,2337072177,3767092226,3222571853,265454925,35716,1787514112,445336840,182089,1090519040,5093135,264865126,42116,1103114496,440,3375449344,4202255,3250751812,255919586,692373679,3498656194,22121793,255969281,5590199,1725008201,3698706821,4093104689,3242774665,55051232,2336751685,3531950096,1424689525,4202255,1220708680,2236088971,1291154880,2236420745,3666431451,4286285071,2336817151,407538454,29655873,265042241,4294923650,176900351,1208506367,1476333195,3901310984,952402760,1566531163,1564564545,2149519299,0,3943729484,3955241401,1220555157,1530446979,1096638302,3277668700,2425393296,2425393296] 318 | remove := [1413567809,1398167381,686588744,414650181,1221495112,1164367753,2215631749,231,3551989569,441,1170223360,2422657585,30519055,3251276240,3391686114,2369900937,2303263058,747456722,3071230226,2238074900,1222473170,3526430347,2300080631,294340816,3257699660,6130505,266044744,41604,3828434176,1221756229,1946700683,960783916,825062681,3956421056,2149519128,0,1287065412,2202534401,1164313280,1962937403,29524751,1976711492,1015244519,578027561,1224969032,2236144777,1208317120,3035349897,696,3296937984,1600019240,1096565085,2236466013,59459812,2303281268,1476338692,1267419144,139984656,4292446536,2336753751,476611334,112641,2202533888,1583032516,1547787615,834886977,1170223597,1089065521,838860799,3296938176,1600019240,1096565085,2303312733,2336751685,3001747531,2425393296] 319 | pput := [1430345281,1465209921,2202555222,1097220332,1207974275,2303250313,3314109654,265128269,84612,3955241216,2149519113,0,1351473289,2202101249,21884,1976797512,38309359,4291363144,3297331478,2422652977,3229860489,3071230209,956323148,2302764760,3967177740,1208453960,1009013901,608996684,1082868792,1418283032,2303205412,143345898,2198886143,20718716,264603977,49028,1620224,385810432,8225638,3330885888,13992975,3224436736,258345195,17439,1351473289,2088986113,1207959637,4034253705,1208109197,385861889,258396721,17439,3263418761,3071230977,956321092,2302961370,3967174660,138840393,1009009803,444233,1291845632,2232444553,1296397504,1207989641,258348939,258392303,1116457455,29393692,705644786,474122688,4061676171,3358199624,1247350770,789538320,828143553,3296938176,1600019264,1096565085,3277734237,4202255,2332527432,1211638868,2303459467,2951467060,273189704,3087554303,1,275089741,1086620488,1566531163,1564564545,3116588609,2,3437878065,3120562174,2,1072290609,1224736767,2303259273,408354809,3087501640,4294967295,2425394155,2425393296] 320 | pget := [1223459656,1208060744,1009011853,1288866121,941902989,1153599820,1209548939,539249801,1091078984,823153407,612139986,74776892,273713992,1221626184,3276326019,2425393296] 321 | pfindKey := [1398167381,1209710351,1210348683,1725139273,2215631749,172,3218323215,1,826654769,3618574290,4203335681,688251585,1104644602,1224823437,2370359945,255922732,1716720823,3715486341,4148286001,1221626352,1208213697,1090585739,113709449,0,1958774088,3531949418,138971980,1097214836,762648891,3375485489,258349035,17439,1152847685,2202534417,1164313282,1964180539,29459216,1976645956,2202101479,1946167612,277563416,1959953736,3498657797,113752043,2,1566531163,17221571,1526726656,3277676382,3224497457,826659377,830794706,2430725056,2425393296,2425393296,2425393296] 322 | ptraverse := [1447122753,1413567809,1398167381,1491895112,4130462513,1222084936,2303267211,3314109903,2345437509,3380942922,18056207,2337013760,1290832130,12915853,1224736768,1287662731,1210340489,267224392,59780,4130424064,612666184,192,1208075139,1209030027,1158172043,1955193225,2302746660,1149847768,4282460196,4294476757,8750095,578682880,1853145221,251787395,33669,1166755840,4001974528,264275272,37764,3314108416,4169379563,28852734,1962934272,1166755939,1149846528,2336769060,2303199309,4281869380,2336753751,1476333645,3918088200,1292392447,2336814725,1144529988,1143227531,2303276916,395004166,18639491,1958774085,4294883495,2202599423,1583044804,1547787615,1581342017,1170431809,2783690801,8658703,0,3957885256,395004296,608996168,311117896,168069448,778484715,8658703,0,2333576009,3330480202,265173249,4294897026,112895,2867527680,2425393296,2425393296] 323 | pfindVal := [1398167381,414650177,266044774,37252,3526444288,21138753,1015234918,2303262784,881674434,1223521536,1116410251,1958774040,982206561,1208084611,147287181,1293912908,1165286277,1305642309,1947224971,960587308,825128217,3956421056,2149519128,0,1287065409,2202534401,1097204416,1962937403,29524752,1976711492,2202101479,1946169660,462114072,1977320781,3347269819,4013508616,3224480373,1566531163,1133201859,1600019208,4130456413,3922866501,4294967163,2425393296] 324 | pmultPut := [1447122753,1413567809,1398167381,2028766024,2336807729,14689468,2303197184,12592268,2303197184,13116564,2303524864,3465104580,3548971755,1401804937,1015244289,4067754055,608472392,3071231080,266044735,992232597,114241,3979411456,608471368,1150109776,826633252,3979429312,608471368,2035544,88378691,3246999808,79105857,3229967940,1147539572,2215639097,638,29393729,1164369643,192282501,992246912,4068806400,2231369729,608487387,60,3800370944,822083585,356814290,3263777024,1174714127,1958774118,960783901,3783528440,2197815297,1150091714,2303262741,79105986,3229967942,1164370805,192282501,992246912,2072317696,2231369730,1938100187,1207959554,3357836427,1124073472,33574029,1210340489,608471364,1141964608,1076118667,1221036361,1418445193,2302953508,3229959656,89951559,2417652736,2210498881,2202534336,256312001,1716260023,4266232132,1975728449,3230221543,608471364,3224454472,76105062,2223720519,51236,307006720,609519874,1141964608,1210336395,1076122763,834898249,2149519296,0,347277,213323588,2210498894,3258515904,210322790,2313777995,29962704,2302764765,2336768780,12592260,3573612544,609520456,1418544472,2303459357,1279272028,1344556171,1191217992,1141910669,1209548939,539251849,1224378700,2336753803,13116548,1358888960,612139792,2337014124,255861852,102276,1149847552,2336770084,13116548,414777344,1275068416,1076124809,1418399999,2337041444,1212163164,199,2303459328,3531933816,274237772,609520456,3548712776,1207959552,3223622795,2332033024,1214784588,2336756363,76105746,2223720650,49188,4010763776,4010763968,277563593,2199667339,1223819712,2311072271,1116412994,256438808,267569194,1712343641] 325 | pmultPut.push([264318735,88711,608471808,264275260,80005,3071230976,3224454463,4294826985,1103114751,1153941505,80932,216596480,1728053246,8658703,0,2215631749,4294966851,258392113,17439,21531972,168594755,264800588,1716391095,1326201154,19301647,960757760,495325131,1711276033,3631597957,264976708,4294838916,1284195583,2235907108,25130185,4261013954,2303262719,4282116354,3682992127,17597455,3224436736,1090603149,1208554637,255969417,1716786359,1968116793,1993029918,3531957786,3409568373,1009009863,0,4283794703,1827274751,973078525,608487363,60,1552158464,1728053245,2215629445,4294967095,255967365,21087812,4244826560,2336555007,826025036,3380954560,3224469877,2422622443,273189704,608471368,2223720512,51236,1552501760,1358907428,2223720456,51236,4186524672,2332578047,1211900996,1076122763,610044748,1287685448,252729993,4294887556,112895,2202533888,1583052996,1547787615,1581342017,1220763457,3357840523,1207959552,3223620747,4278190080,2336757842,12592276,2303197184,4270057730,258408447,17439,2215625529,4294966515,264865126,4294893700,1103136255,29770767,4237814210,1153957887,15396,2296971264,2432696316,2425393296]*) ; :( 326 | 327 | pmultPutConst := [1447122753,1413567809,1398167381,3102507336,822083584,3163244790,73764,2357807104,65572,3599321344,1304660300,49008521,4035565193,1711363725,4668547,826667637,1090776036,2302989449,1418543584,1097204004,4668547,822600,76409205,1157006610,2500846217,1216029764,1344556169,1224051021,1478771849,1157138764,2199369487,3511160800,3640084712,1141366915,255975481,826655815,703410624,2311162306,8397956,1116536832,613714424,156,2198071489,2223571392,33828,65061120,2552530057,1090519040,4280566925,3364471433,21545513,2223589568,34852,4160834560,2082755721,612665672,144,612666696,168,608471368,2223851616,44068,1149847552,2370398244,2303201351,1718625348,8658703,0,88378690,3246999808,1124382479,1958774118,960783888,92540880,1090519043,3942760579,2235918047,2148234706,8070268,67798287,4135911424,67273999,1153892352,15396,2369978368,1140981836,1076118665,5635905,608471876,3330885952,2311227720,3229959656,88902982,1713337344,8658703,0,3229860233,3263383553,213323522,1250518603,3359196414,2302995061,1149846720,826621988,2303026880,2336769540,1096295500,1157649919,2303321221,1149977794,2215591972,376,272665928,264714569,994886291,259007572,3255353491,56132623,2202075136,2249133308,846,2149878923,2231369728,25432009,1090519043,2198320911,1097204217,2215576201,888,1203179329,49906434,1116291430,2038697730,1090519043,71808783,1711536515,71469377,56394767,255918080,2198226871,1097204985,252068489,207748,3071230208,4186114119,2302764549,2215577666,782,1203179329,133792522,1116291430,260378378,1090519043,206026511,1116291430,505868,2088960000,1980136484,2357938245,34852,2626374656,36900,1305620736,822742157,255944393,2199061615,255918529,1209074705,957399683,8660108,3849781248,2552532107,16777216,613170120,156,3263789684,1090633859,1460451087,1724135745,1376553281,3263784566,213323585,2302764631,1351438860,3560521985,255939190,1716980919,1376553281,1090670733,1081529401,213323585,2302764631,1351438860,3560521987,255929974,1716980919,1376553281,1090801805,477549625,213323585,96502615,1724135745,1376553281,255920758,1715934391,1108642113,608471880,29962576,1418284277,21250084,1284197573,2303483940,2302764786,2336752140,16786564,2336751616,1214784588,2336489611,2303203392,1210065996,4282452107,3162706005,44068,2337014016,255861844] 328 | pmultPutConst.push([73604,1418284032,2303213604,3108512836,24,5635905,2888078475,1275068416,1076122763,51016,1275068416,2231922825,1351175378,1418414096,2232371236,220,613190472,256,2333182792,11019404,2336751616,76105746,2223720650,65572,4010763776,4010763968,277563593,2199667339,1223819712,2311072271,1116412994,256438808,267569194,1712343641,264318735,65159,608471808,264275260,47749,3071230976,3224454423,4294763497,2035711,2215638661,4294966546,258392113,17439,1090603149,1208554637,3071264905,963007252,745885460,678874681,1976730982,3352181219,3941444,251658240,4294763908,3221307903,1009009863,1,4294759913,2035711,2215626297,4294966466,1959953766,3133179360,1,1103250447,1911144449,2432696316,3909257544,4294967093,273189704,609519948,1149847624,4282466340,2303461461,1442791921,608471816,1418414140,2337030180,2236097620,1384729792,1183059728,3103784959,1,3099885896,1526726656,1096638302,1096630620,3277799774,2089009201,252083236,4294801543,3071230463,2302764551,112642,3219718144,1224736765,2395275,1275068417,4282509961,2336757845,16786572,2303197184,4276349185,3224502271,347541313,2302764615,2202550804,960561600,3924654020,4294966764,1153941553,80932,21037056,4227131840,96010239,3909091328,4294966538,1208,4244695296,112787455,3909091328,4294966518,440,4243384576,62455807,3909091328,4294966498,696,4242073856,2425421823,2425393296]*) 329 | pmultPutNoDel := [1447122753,1413567809,1398167381,2565636424,1140850688,2397323,1224736769,2303249801,2223590614,61476,3481881856,608487240,1080,3531949312,3224444020,4202255,2022556297,2202101249,2298500924,32601592,1149847744,2303539236,1308133884,2202140297,3511226340,3707193836,132416321,1157380417,837240591,3760801005,610568516,608471388,149455720,2198071489,1149829568,3770770468,608471299,4282879340,2313169220,1147151428,21553289,1149847744,21788708,1149847800,2370400292,2303201351,1213211716,2284094605,1207959552,1076118665,612666696,140,608471368,1223199048,2303246337,2483243202,61476,981689856,830738176,1140850691,2395275,1157627905,2232404357,256,103058765,1015234918,2215575588,816,609519944,309552,385810432,608996168,3347663160,2336757503,1211114580,3071263625,1725051138,822577473,2302764736,255918663,1713636535,1711428489,2336818057,2336751685,2202543180,2337014213,1279272012,2336553609,2303203392,1210065996,1459554443,616334096,140,3297331457,37913615,414777344,4278190080,2223719446,35876,13060096,0,142117196,274237768,264275269,134021,1435191552,613190400,136,1209174856,1237976201,1711297931,1723920143,2345266959,3229817922,256438785,1116323882,407014172,705644786,1494217416,258347082,2249179439,4294967021,1290963272,1459612041,1166625048,4275824896,258408447,17439,609519944,309552,385810432,608996168,3347663160,2336757503,1211114580,3375481737,3071278981,2302764546,1097204303,2215577481,4294967062,610024264,1133332560,3264417552,264649033,3255353491] 330 | pmultPutNoDel.push([28476431,4286775296,2844135180,2332033025,2237408332,2105806793,1090519041,2198255375,2305163769,4253290243,1090519041,38188815,1711470979,251806601,134020,3071230208,4186113094,1133078019,3917745924,1090519041,105297679,1711602051,252068745,108420,3071230208,4186114118,1133078021,2307133192,1090519041,172406543,1711798659,252330889,103301,3071230208,2305166406,129502275,2197815296,106964092,2336767606,1282942028,1881427083,2370622001,3375434500,1863270758,3246592260,286212353,2202537988,1278939330,3899810852,1814318219,1278855169,2215602212,4294966830,4202255,3229860489,3071230209,3342423564,1393330534,4262757903,3263823871,213323585,210331222,22056275,2249185081,4294966782,213323585,210331222,38833491,2249185081,4294966762,213323585,210331222,55610707,2249185081,4294966742,213323585,210331222,72387923,2249185081,4294966722,213323585,96502614,2305214265,2249151244,4294966702,347541313,344548934,4255181123,258408447,17439,604277065,4294835945,2149519359,0,273189704,1275614975,1459616137,1552501000,4276686884,1728053244,8658703,0,2089009201,252076068,4294899079,3071230463,59336198,440,4281919744,2422669311,255967281,1715868855,1212355721,956416131,3924785095,4294966578,8658703,0,440,3296806912,152,1566531163,1564564545,1598119489,2149519299,0,3790323761,1464,4270713088,2422669311,1208,4269926656,258408447,17439,1720,4268878080,258408447,17439,440,4267829504,258408447,17439,952,4266780928,258408447,17439,696,4265732352,2425421823,2425393296]*) 331 | pforEachVal := [1447122753,1413567809,1398167381,1491895112,948126054,3481880832,613714248,168,1288079692,3089403017,251658240,110468,2379952384,2204500291,1207977532,2370356105,4017422380,1158122313,826663985,407407606,2215627141,144,616335692,160,1290242373,2686755979,1140850688,2337075849,1015891968,213,2089371648,2336831524,2236141628,1163425023,258403633,17439,2336807813,812912727,1711453967,812975673,3375480881,778443755,8658703,0,1152847684,2202534402,1147536064,1963328571,29459215,3900037433,708608870,2419028992,1212123976,3094740869,604277577,1092110475,1090635395,2205339193,440,3296937984,1600019288,1096565085,1096696157,2336801631,13116548,2202075136,2336752071,2336491599,12592268,2302935040,1159734388,2303260809,4280820804,12067988,4169334784,2206470143,2113929216,1958774037,33063860,4283335951,2303328255,1066092797,4169370091,113406,2232352768,4294967096,2298973000,1212949588,1208504203,1076118665,612666184,168,1208504575,2820965515,1207959552,4279259019,2336753744,11019396,2303197184,139526137,1223525709,1076118667,1277449355,2303270004,2336817221,1770202124,3531931932,2303207541,4280150471,3526492159,2336857835,2336760844,1211638908,2303199627,2336831748,1770202124,3531931932,4273526900,3925868543,4294967053,3677482289,4294859753,2425393407,2425393296] 332 | pclone := [1447122753,1413567809,1398167381,1491895112,1208060744,2686749833,1224736768,267573129,1276139536,2332573835,1082857544,608471328,311117856,542637889,1220576584,2303248009,255337540,339844,2223720448,40996,9127936,2333624459,3380943952,253515401,330628,608487168,76,4270411008,1277449355,1291881292,1221602443,13972621,1207959552,807695497,267224397,259204,1620224,826605568,385827327,139823945,3955525961,4287185155,1106807108,1711374221,4340867,2336878453,3677425749,2422605035,3632919433,1711371149,4340867,210629237,385827135,1211501709,4282500489,268403990,110468,1435191552,1250773000,3443083280,273517896,3230863169,264911176,138527123,3380875208,2197815299,2249133311,960,1104316745,1225777795,4148816593,3800252890,4198056199,3611758404,2235943217,259552466,2202077879,2305163770,2215575629,1062,38450959,49972033,38635878,67798031,3071213568,2202076234,2305164282,2215576653,1006,105559823,83526465,105744742,64128015,3071213568,2202077258,2305164794,2215577677,910,172668687,133858113,172853606,57836815,3071213568,2305166410,129567821,1090519040,692452233,3515434455,1171466565,1157120909,1143233673,65585473,29393729,117408577,3306982726,0,610044228,1295742536,826657025,3677439442,171740494,1726546249,74387267,3280158999,286212865,2202603780,960827586,1156084419,1210342539,1155072324,1143233593,8553487,2302738432,3071231688,1181106700,4541577,21073220,1992767812,3071231595,1181106700,4541577,37850436,1992767812,3071231575,1181106700,4541577,54627652,1992767812,3071231555,1181106700,4541577,71404868,1992767812,3071231535,1181106700,4541577,88182084,1992767812,3071231515,3246604812,1724856582,1162643782,252278272,1716130999,5067913,2215638661,400,274041673,273190216,1221212488,1091586701,1220580111,2467285049,3355984321,32670735,4269998080,3917877004,1224736769,2202129033,3511226338,3673639402,132285249,1156725057,836126479,3531949513,3071244148,4202905866,143222273,38306831,3071213568,2202075722,2305164026,2215576136,556,72005391,66749249,71862630,34636815,3071213568,2202076746,2305164538,2215577160,500,139114255,100303681,138971494,29656079,3071213568,2202077770,2305165306,2232355400,424,206223119,206080358,1977,1157073152,2303054633,3609806033,4165438788,65585473,29393729,1174862723,12926093,1979711488] 333 | pclone.push([3372305712,1171403077,2370493233,21563932,256009921,1091765359,1124189059,285479183,281183049,1925396805,4177609960,1962883393,3364438395,213323590,2303092290,2370060300,960758081,1181054662,1108129551,210323046,1099777088,3325641730,256266870,1715604663,1074563398,54627652,1992702276,3071231551,1181106700,1145048201,1141129613,745981497,213323590,2303092290,2370060300,960759105,1176073926,1108129551,956744067,2303092430,141967372,1242871567,1209305446,611617608,1149847864,2336755748,1227891780,2360519,1224736768,136604809,7179085,1208353608,2236092555,3909907922,148,4202255,1220708680,2236088971,1291154880,2236424841,444927981,1224736764,2686747787,1207959552,1217069195,608469784,1955266892,3459861540,4225401359,2336817151,1211638852,1532544131,1096638302,1096630620,3277799774,4202255,256166193,1716126903,1208256836,29459272,4000828985,4294927337,2149519359,0,256166193,1716126903,1296337220,3246606336,2010069249,4255836653,258408447,17439,3911223628,4294967158,1721,4267436288,96075775,3909091328,4294966865,1721,4237420800,96075775,3909091328,4294966407,1209,4264814848,62521343,3909091328,4294966825,697,4263504128,28966911,3909091328,4294966805,1209,4233488640,62521343,3909091328,4294966347,697,4232177920,28966911,3909091328,4294966327,3924855112,4294967075,485081137,2432696319]*) 334 | paddNullDel := [1447122753,1413567809,1398167381,2028766024,1154320717,3760491659,1207959552,3223620745,1207959552,3357840521,1291845632,2235942025,3951300553,1207959553,1747207309,3352791368,3155012,1157627904,826668593,1149847807,2370326564,1215046724,1478771849,4202255,838371652,2202101449,1962951740,30337287,3246981120,1174487437,1714947213,1144816451,3263777792,3230002293,28476431,21495808,40996288,608471368,4035527744,2088976742,2298478661,2369528948,2215589388,448,49011505,1133364105,210585089,2202232368,19836,1976076621,264275435,106372,46367488,2378170696,2303204140,1145578564,941900937,874796169,1418401791,2336502820,1211638852,2303248009,4169745601,4202255,2210498881,2202534336,256312001,1716260023,4266232132,3900035129,608471880,1149846592,826618916,3918088384,76104806,1142423302,874792075,1220905288,2302984841,2035696,3229860233,3263383553,3071230210,1711295820,1157515913,3900031033,608471880,1103704392,2336808449,1146627164,1009024003,1290963272,1344556171,88901990,2223720448,49188,9127936,406883140,610044232,143345696,2198886399,23864444,264472904,65412,1620224,402587648,1814320267,51016,1207959552,1208512649,2232445065,3448049618,1207959552,3223630987,2332033024,1214784588,2336757387,76105746,4035528906,1712360264,1723920143,2345266959,3229817922,256438785,1116323882,407014172,705644786,1494217416,258347082,2265956655,180,807683203,608471809,612645168,224,4265510159,28901375,1207959552,1534641283,1096638302,1096630620,3277799774,8658703,0,1223723332,1076118727,2,1209,2202101248,17788,1009009863,2,22515009,4266034447,258408447,17439,608487240,584,310528,45809664,1157627904,3909174925,4294966867,4202255,1208191304,3223618699,3909091328,4294967100,273189704,1208506367,1476391305,1804158984,4283885840,778502143,8658703,0,1224378696,3223620747,4278190080,2336757847,12592308,2303197184,4281264390,2425421823] 335 | pcopyFromHT := [686588744,608471880,3364440408,1221691721,2336753803,1358891088,112656,2202533888,2428709060,2425393296,2425393296,2425393296] 336 | pgetFromHash := [2336805513,2236141828,1095201984,1946286211,9128001,1958774088,4169351479,3123803649,1,778441451,8658703,0,1958885700,3364440078,2198375240,2236088770,1106081225,12243001,1207959552,3284288783,3287531569,2425393296,2425393296,2425393296] 337 | pnext := [1398167381,686588744,1208060744,1384896137,3481880828,1287883084,1346096521,3944378904,4232300339,1,2382120587,2336751952,4233529607,1981304889,1133200411,143345916,2236143103,2212132032,1208089667,1529398403,3277676382,2202583089,1583032516,2428722527] 338 | } 339 | for j, raw in [pnewTable,pdestroy,prehash,remove,pput,pget,pfindKey,ptraverse,pfindVal,pmultPut,pmultPutConst,pmultPutNoDel,pforEachVal,pclone,paddNullDel,pcopyFromHT,pgetFromHash,pnext] ; The order matters. 340 | hashTable[j]:=hashTable.rawPut(raw) 341 | hashTable.init:=true 342 | return 343 | } 344 | initTable(clone:=0){ 345 | this.table:=this.globalAlloc(A_PtrSize) 346 | NumPut(clone ? clone : this.newTable(this.size), this.table, 0, "Ptr") 347 | return 348 | } 349 | initBoundFuncs(){ 350 | ; pnewTable (01) (internal use) 351 | ; pdestroy (02) (use destory()) 352 | ; prehash (03) (use rehash()) 353 | ; remove (04) (use remove(key)) 354 | ; pput (05) (use myHashTable[key]:=value) 355 | ; pget (06) (use value := myHashTable[key]) 356 | ; pfindKey (07) (use HasKey()) 357 | ; ptraverse (08) (use forEach(fn)) 358 | ; pfindVal (09) (use hasVal() or valGetKey(value)) 359 | ; pmultPut (10) (use splitAdd()) 360 | ; pmultPutCV (11) (use splitAdd()) 361 | ; pmultPutND (12) (use splitAdd()) 362 | ; forEachVal (13) (use forEachVal()) 363 | ; clone (14) (use clone()) 364 | ; addNullDel (15) (use addFromFile()) 365 | ; copyFromHT (16) (use copyFromHashTable()) 366 | ; getFromHash (17) (enum) 367 | ; next (18) (enum) 368 | ; 369 | this[2] := func("dllCall").bind(hashTable[2], "Ptr", this.table, "Ptr", hashTable.fnLib, "Cdecl") ; destroy 370 | this[3] := func("dllCall").bind(hashTable[3], "Ptr", this.table, "Ptr", hashTable.fnLib, "Cdecl Ptr") ; rehash 371 | this[4] := func("dllCall").bind(hashTable[4], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; , key, "Cdecl") ; remove 372 | this[5] := func("dllCall").bind(hashTable[5], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; , key, "wstr", val, "Cdecl") ; put 373 | this[6] := func("dllCall").bind(hashTable[6], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; , key, "Cdecl str") ; get 374 | ; 7 375 | this[8] := func("dllCall").bind(hashTable[8], "Ptr", this.table, "Ptr", hashTable.fnLib, "ptr") ; this.icbfn/udfn, "uint", cbid,"ptr",uParams, "Cdecl") ; traverse 376 | this[9] := func("dllCall").bind(hashTable[9], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; val, "Cdecl ptr") ; findVal 377 | this[10] := func("dllCall").bind(hashTable[10], "Ptr", this.table, "Ptr", hashTable.fnLib) ; "wstr", keys, "wstr", vals, "wstr", del,"Cdecl") ; multPut 378 | this[11] := func("dllCall").bind(hashTable[11], "Ptr", this.table, "Ptr", hashTable.fnLib) ; "wstr", keys, "wstr", vals, "wstr", del,"Cdecl") ; multPutConstVal 379 | this[12] := func("dllCall").bind(hashTable[12], "Ptr", this.table, "Ptr", hashTable.fnLib) ; "wstr", keys, "wstr", vals, "int", constVal, "Cdecl") ; multPutNoDel 380 | this[13] := func("dllCall").bind(hashTable[13], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; val, "ptr", this.icbfn/udfn, "uint", cbid,"ptr",uParams, "Cdecl") ; forEachVal 381 | this[14] := func("dllCall").bind(hashTable[14], "Ptr", this.table, "Ptr", hashTable.fnLib, "Cdecl Ptr") ; clone 382 | this[15] := func("dllCall").bind(hashTable[15], "Ptr", this.table, "Ptr", hashTable.fnLib, "ptr") ; keys, "ptr", vals, "uint", nKeys, "Cdecl") ; addNullDel 383 | ; 16 384 | ; 17 385 | this[18] := func("dllCall").bind(hashTable[18], "ptr") 386 | return 387 | } 388 | newTable(sz){ ; Called by initTable() 389 | static pmalloc:=DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "malloc", "Ptr") 390 | return DllCall(hashTable[1], "Uint", sz, "Ptr", pmalloc, "Ptr", hashTable.tableSizes, "double", this.maxLoad, "Uint", this.nextSize, "Cdecl ptr") 391 | } 392 | 393 | ; Growing list of array sizes 394 | ; Each size is approximately double the previous size. 395 | ; All sizes are prime 396 | ; maketableSizesArray() relies on this array being assigned above it. 397 | static arraySizes:= [2 398 | ,5 399 | ,11 400 | ,23 401 | ,53 402 | ,113 403 | ,251 404 | ,509 405 | ,1019 406 | ,2039 407 | ,4079 408 | ,8179 409 | ,16369 410 | ,32749 411 | ,65521 412 | ,131063 413 | ,262133 414 | ,524269 415 | ,1048571 416 | ,2097143 417 | ,4194287 418 | ,8388587 419 | ,16777183 420 | ,33554393 421 | ,67108837 ; tested, 500 mb empty. 350 ms. 422 | ,134217689 423 | ,268435399 424 | ,536870879 425 | ,1073741789 426 | ,2147483629 427 | ,4294967291] 428 | maketableSizesArray(){ 429 | static init := hashTable.maketableSizesArray() 430 | local tableSizes, k, sz 431 | tableSizes := hashTable.globalAlloc(this.arraySizes.length()*4) 432 | for k, sz in hashTable.arraySizes 433 | NumPut(sz, tableSizes,(k-1)*4, "int") 434 | hashTable.tableSizes:=tableSizes 435 | return 436 | } 437 | makeFnLib(){ 438 | ; See hash.h 439 | /* 440 | typedef struct functionLib { 441 | _malloc pmalloc; 442 | _free pfree; 443 | findKey pfindKey; 444 | _rehash prehash; 445 | _newHashTable pnewHashTable; 446 | //mb pmb; // db 447 | } fnLib, *pfnLib; 448 | */ 449 | 450 | local fnLib := hashTable.globalAlloc(5*A_PtrSize) ; Set to 6*A_PtrSize when using db. Can be freed via freeFnLib() (you shouldn't) 451 | local pmalloc:=DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "malloc", "Ptr") 452 | local pfree:=DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "free", "Ptr") 453 | NumPut(pmalloc, fnLib, A_PtrSize*0, "Ptr") 454 | NumPut(pfree, fnLib, A_PtrSize*1, "Ptr") 455 | NumPut(hashTable[7], fnLib, A_PtrSize*2, "Ptr") 456 | NumPut(hashTable[3], fnLib, A_PtrSize*3, "Ptr") 457 | NumPut(hashTable[1], fnLib, A_PtrSize*4, "Ptr") 458 | ;NumPut(callbackcreate("mb","Cdecl"), fnLib, A_PtrSize*5, "Ptr") ; db 459 | hashTable.fnLib:=fnLib 460 | return 461 | } 462 | initSize(target:=0){ 463 | ; Picks the closest available size greater or equal to target. 464 | local k, sz 465 | for k, sz in hashTable.arraySizes { 466 | if sz >= target { 467 | this.size:=sz 468 | this.nextSize:=k 469 | return this.size 470 | } 471 | } 472 | ; this should be rare. Allocating max size might not even succeed. Not tested. 473 | ; Indicies in c source are unsigned int, hence max index is 2**32 (4294967296). 474 | throw Exception("The requested size (" target ") is to large. Maximum size is: " hashTable.arraySizes[hashTable.arraySizes.length()] ".",-1) 475 | return 476 | } 477 | rawPut(raw){ ; Called by initBin, for writing binary code to memory. 478 | ; Url: 479 | ; - https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx (VirtualAlloc function) 480 | ; - https://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx (Memory Protection Constants) 481 | local k, i, bin 482 | static flProtect:=0x40, flAllocationType:=0x1000 ; PAGE_EXECUTE_READWRITE ; MEM_COMMIT 483 | 484 | bin:=DllCall("Kernel32.dll\VirtualAlloc", "Uptr",0, "Ptr", raw.length()*4, "Uint", flAllocationType, "Uint", flProtect, "Ptr") 485 | for k, i in raw 486 | NumPut(i,bin+(k-1)*4,"Int") 487 | return bin 488 | } 489 | ; For forEach/Val 490 | calloutFunctions:=[] 491 | traversecalloutRouter(key,val,ind,cbid,hash,uParams){ 492 | ; typedef int __cdecl (*calloutFn)(unsigned short*,unsigned short*,unsigned int,unsigned int,unsigned int,void*); 493 | ; traversecalloutRouter(key,val,ind,cbid,hash,uParams) 494 | return this.calloutFunctions[cbid].call(StrGet(key), StrGet(val), ind, hash, uParams) 495 | } 496 | setUpcalloutFunctions(udfn,byref cbfn, byref cbid){ ; Used in forEach/Val 497 | if type(udfn) == "Integer" 498 | cbfn:=udfn 499 | else 500 | cbfn:=this.icbfn 501 | if !isObject(udfn) && isFunc(udfn) 502 | udfn:=func(udfn) 503 | cbid:=this.calloutFunctions.push(udfn) 504 | return 505 | } 506 | ; Memory functions 507 | freeAllBins(){ 508 | ; Probably never wanted. 509 | loop 18 510 | hashTable.globalFree(hashTable[A_Index]) 511 | return 512 | } 513 | freeFnLib(){ 514 | ; Probably never wanted. 515 | this.globalFree(hashTable.fnLib) 516 | return 517 | } 518 | globalAlloc(dwBytes){ 519 | ; URL: 520 | ; - https://msdn.microsoft.com/en-us/library/windows/desktop/aa366574(v=vs.85).aspx (GlobalAlloc function) 521 | ;static GMEM_ZEROINIT:=0x0040 ; Zero fill memory 522 | ;static uFlags:=GMEM_ZEROINIT ; For clarity. 523 | local hMem 524 | if !(hMem:=DllCall("Kernel32.dll\GlobalAlloc", "Uint", 0x0040, "Ptr", dwBytes, "Ptr")) 525 | throw exception("GlobalAlloc failed for dwBytes: " dwBytes, -2) 526 | return hMem 527 | } 528 | globalFree(hMem){ 529 | ; URL: 530 | ; - https://msdn.microsoft.com/en-us/library/windows/desktop/aa366579(v=vs.85).aspx (GlobalFree function) 531 | local h 532 | if h:=DllCall("Kernel32.dll\GlobalFree", "Ptr", hMem, "Ptr") 533 | throw exception("GlobalFree failed at hMem: " hMem, -2) 534 | return h 535 | } 536 | free(buf){ 537 | return DllCall("MSVCRT.dll\free", "Ptr", buf, "Cdecl") 538 | } 539 | ; Destructor 540 | wasFreed:=false 541 | destroy(){ ; This is automatically called when the last reference to the table is released, eg, myHashTable:="" 542 | if !this.wasFreed && this._isPersistent 543 | this.toFile(this.path) 544 | if this.wasFreed 545 | return 546 | this.wasFreed:=true 547 | this[2].call() ; pdestroy 548 | this.globalFree(this.table) 549 | callbackfree(this.icbfn) 550 | } 551 | ; Internal toTree and toString methods. 552 | _toTree(tv,parents,key,val,i,h,uParams){ 553 | local id 554 | if !parents.haskey(h) { 555 | id:=tv.add(h) 556 | parents[h]:=id 557 | } 558 | id:=tv.add(key,parents[h]) 559 | tv.add(val,id) 560 | return 1 561 | } 562 | checkIfNeedRehash(n){ 563 | ; Make one rehash if it will be needed, to avoid multiple rehashes. 564 | if this.count()+n > this.getMaxload() * this.length() 565 | this.rehash((this.count()+n) / this.getMaxload()) 566 | } 567 | _toString(del1,del2,what,toBuf:=false){ 568 | ; This is also for writing to buffer, 569 | /* 570 | typedef struct toStringParams { 571 | unsigned short* buf; // string buffer. 572 | unsigned short* del1; // key val delimiter 573 | unsigned short* del2; // pair delimiter 574 | realloc prealloc; // realloc fn 575 | memcpy pmemcpy; // memccpy fn 576 | unsigned int len; // buffer length 577 | unsigned int o; // buffer offset 578 | unsigned int dellen1; // delimiter 1 length 579 | unsigned int dellen2; // delimiter 2 length 580 | int what; // what to get, 0 indicates both key and val, 1, only key, 2, only val. 581 | } *pparams; 582 | */ 583 | static prealloc := DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "realloc", "Ptr") 584 | static pmemcpy := DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "memcpy", "Ptr") 585 | 586 | static bin 587 | local dellen1, dellen2 588 | if toBuf { ; Use '\0' as delimiter for buffer write 589 | varSetCapacity(del1,2,0) 590 | varSetCapacity(del2,2,0) 591 | dellen1 := what == 1 ? 1 : 0 592 | dellen2 := what == 2 ? 1 : 0 593 | } else { ; Use string as delimiter. 594 | dellen1:= what <= 1 ? strlen(del1) : 0 595 | dellen2:= what == 1 ? 0 : strlen(del2) 596 | } 597 | local uParams ; params to be passed to the calloutFunction, see forEach. 598 | varSetCapacity(uParams,5*A_PtrSize+24,0) 599 | ; buf 600 | numput(&del1, uParams, A_PtrSize*1, "Ptr") ; del1 601 | numput(&del2, uParams, A_PtrSize*2, "Ptr") ; del2 602 | numput(prealloc, uParams, A_PtrSize*3, "Ptr") ; prealloc 603 | numput(pmemcpy, uParams, A_PtrSize*4, "Ptr") ; pmemcpy 604 | ; len 605 | ; o 606 | numput(dellen1, uParams, A_PtrSize*5+8, "uint") ; dellen1 607 | numput(dellen2, uParams, A_PtrSize*5+12,"uint") ; dellen2 608 | numput(what, uParams, A_PtrSize*5+16, "int") ; what 609 | if !bin ; note, using "this" here because needs to be able to access rawPut if hashTable has been deleted, typically after exitApp() 610 | bin := this.rawPut(A_PtrSize == 4 ? [3526448981,3968029526,611617580,612141908,608996164,608602944,2298607747,252978244,36750,2311074048,666668534,0,747488137,21007616,1199342438,4034199806,405040265,2333625995,3355515974,18892291,1003487704,2198803526,132,337935491,252087041,44942,609520384,1208257816,69500041,2300839049,4278723668,1577259094,541494040,1586085889,608471320,138840840,69485705,76351115,604277080,2333103871,1174478918,112664,3296919552,1600019244,3263808349,1711358605,4265704579,2213770496,18097276,4284187919,1153957887,6180,3677421568,4294929385,649367039,0,3238005901,1418265312,1317608484,608471316,2298907396,1459561476,1958774028,609127288,1418397321,1284054052,2088965156,2332103716,2400131150,4294967121,2299669645,2333353044,2369791060,1820936196,1418266660,76088356,274136868,2333886091,51651668,3221297238,2300073609,2332566596,1149830214,109773860,2303722637,1459561476,474909456,52709003,4169341006,407800065,4282156047,109838335,4294898921,3921687039,4294967086,2425393296] 611 | : [1465209921,2202555222,2336760044,829957236,3431549439,2346027336,4186126414,829718017,2298670043,2379778515,2204500307,17788,1452011893,809929516,1174654977,30933300,675691512,4186139251,109791233,8949263,2370043904,2370312964,2303217676,542572522,53757579,2336762974,2370048086,2336751620,744392966,1477217608,2334152447,1174484038,112684,2202533888,1583030468,1547787615,2312604099,22515192,1015234918,4050976836,251787651,4294932101,3957010943,2035589,1207964813,1451822731,2232716584,0,1209554687,1484046469,1211649675,1451951753,33129260,4286091023,2370109439,2370322180,2303479820,542572514,53495435,2336763006,2370046038,2336751620,746490118,2014088520,2334152447,1183526998,743834424,2298607747,2215586902,4294967150,3909520200,4294967090,1609154609,2432696319,2425393296,2425393296]) 612 | 613 | ; bin is toString.c 614 | 615 | local r := this.forEach(bin, &uParams) ; For loop. 616 | 617 | local buf:=numget(&uParams,"ptr") 618 | local o:=numget(&uParams,A_PtrSize*5+4,"uint") ; the offset 619 | if r && toBuf ; Caller frees buf. 620 | return {buf:buf, bytes:o*2} ; the offset is at the end of the buffer, the buffer is of type short, hence multiply by 2 to get bytes. Now keeps the trailing '\0', it is probably safest because addNullDel searches for '\0' which is not guaranteed to exist at the end of the buffer unless put there. 621 | 622 | local str ; return 623 | if r && o 624 | str := strGet(buf,o - (what == 1 ? dellen1 : dellen2)) ; Removes the trailing delimiter 625 | if buf 626 | this.free(buf) 627 | return str 628 | } 629 | _newEnum(){ 630 | return new hashTable.enum(this) 631 | } 632 | class enum { 633 | __new(r){ 634 | this[1]:=r ; reference 635 | this[2]:=1 ; get n:th node in bucket hash 636 | this[3]:=0 ; "bucket" 637 | } 638 | next(byref k, byref v:=""){ 639 | ; Making this ugly improves performance. (a lot) 640 | static hash, n 641 | static dummy := varSetCapacity(hash, 4) + varSetCapacity(n, 4) 642 | static ps := a_ptrsize 643 | static ps2 := a_ptrsize*2 644 | static ps2_8 := ps2+8 645 | local node 646 | return (node := dllcall(hashTable[18] 647 | , "ptr", this[1].table ; tableData** table 648 | , "ptr", numput(this[3], hash, "uint") ; uint* hash note: numput returns the "wrong" address, compiled code does hash-=1 (uint) 649 | , "ptr", numput(this[2], n, "uint") ; uint* n note: as above for n-=1 650 | , "ptr", hashTable[17] ; pgetFromHash 651 | , "cdecl ptr")) ; if node!=0, return true and set key and val 652 | ? (k := strget(numget(node+ps, "ptr")) ; set key 653 | , (isbyref(v)? v := strget(numget(node+ps2, "ptr")):"") ; set val 654 | , this[3] := numget(hash, "uint") ; update this.hash (this[3]) 655 | , this[2] := numget(n, "uint") ; update this.n (this[2]) 656 | , 1) ; return true 657 | : 0 ; else return false 658 | } 659 | } 660 | } -------------------------------------------------------------------------------- /hashTable_v1.ahk: -------------------------------------------------------------------------------- 1 | class hashTable{ 2 | ; User methods 3 | hasKey(byref k){ 4 | return this[6].call(k, "Cdecl ptr") ? true : false 5 | } 6 | hasVal(byref v){ 7 | return this[9].call(v, "cdecl ptr") ? true : false 8 | } 9 | valGetKey(byref v){ 10 | return this[9].call(v, "cdecl str") 11 | } 12 | delete(byref k){ 13 | return this[4].call(k, "Cdecl") 14 | } 15 | clone(){ 16 | ; Use: clonedHt := ht.clone() 17 | local clone := this[14].call() 18 | return new hashTable(this.length(),, clone) 19 | } 20 | forEach(udfn,uParams:=0){ 21 | ; accepts function name, func / bound func obj. 22 | ; binary code address, eg registercallback("f", "cdecl fast") <- cdecl needed on 32bit ahk. Fast option recommended if ok. 23 | local cbid,r,cbfn 24 | this.setUpcalloutFunctions(udfn, cbfn, cbid) 25 | r:=this[8].call(cbfn, "uint", cbid, "Ptr", uParams, "cdecl") 26 | this.calloutFunctions.Delete(cbid) 27 | return r 28 | } 29 | forEachVal(byref val,udfn,uParams:=0){ 30 | local cbid,r,cbfn 31 | this.setUpcalloutFunctions(udfn, cbfn, cbid) 32 | r:=this[13].call(val, "ptr", cbfn, "uint", cbid, "Ptr", uParams, "cdecl") 33 | this.calloutFunctions.Delete(cbid) 34 | return r 35 | } 36 | count(){ 37 | local table := NumGet(this.table+0,0,"Ptr") 38 | return numget(table+0, A_PtrSize*2+12,"uint") 39 | } 40 | length(){ 41 | local table := NumGet(this.table+0,0,"Ptr") 42 | return numget(table+0, A_PtrSize*2+08,"uint") 43 | } 44 | getMaxload(){ 45 | return this.maxLoad 46 | } 47 | setMaxload(newMax){ 48 | local prevLoad 49 | local table := NumGet(this.table+0,0,"Ptr") 50 | prevLoad := this.getMaxload() 51 | numput(newMax, table+0, A_PtrSize*2,"double") 52 | this.maxLoad:=newMax 53 | return prevLoad 54 | } 55 | splitAdd(keys,vals, del:="`n",constVal:=false,isByref:=false){ 56 | if (del == "") 57 | return this.splitAddNoDel(keys,vals,constVal,isByref) 58 | if isByref ; For very large input, pass keys and vals by address and specify true. Improves performance. 59 | return this[constVal ? 11 : 10].call("ptr", keys, "ptr", vals, "wstr",del, "cdecl") 60 | return this[constVal ? 11 : 10].call("wstr", keys, "wstr", vals, "wstr",del, "cdecl") 61 | } 62 | splitAddNoDel(byref keys, byref vals, constVal, isByref){ ; Call splitAdd, specifing del:="", instead of calling this directly 63 | if isByref ; For very large input, pass keys and vals by address and specify true. Improves performance. 64 | return this[12].call("ptr", keys, "ptr", vals, "int", (constVal?1:0), "cdecl") 65 | return this[12].call("wstr", keys, "wstr", vals, "int", (constVal?1:0), "cdecl") 66 | } 67 | addFromFile(path){ 68 | ; See toFile for file layout. 69 | local keyBytes, valBytes, error, success 70 | local keyBuf, valBuf, nKeys 71 | local fo := fileOpen(path,"r") 72 | if !fo 73 | throw exception("failed to open file: " path) 74 | try 75 | keyBytes := fo.readuint() ; Read length of keyBuf, in bytes 76 | catch error 77 | throw (fo.close(), error) 78 | try 79 | nKeys := fo.readuint() ; get number of key/value pairs 80 | catch error 81 | throw (fo.close(), error) 82 | success := keyBytes == fo.rawRead(keyBuf,keyBytes) ; read the keys 83 | try 84 | valBytes := fo.readuint() ; Read length of valBuf, in bytes 85 | catch error 86 | throw (fo.close(), error) 87 | success *= valBytes == fo.rawRead(valBuf,valBytes) ; read the values 88 | fo.close() 89 | if !success 90 | throw exception(A_ThisFunc " failed for path: " path ".") 91 | this.checkIfNeedRehash(nKeys) 92 | if !this[15].call(&keyBuf, "ptr", &valBuf, "uint", nKeys, "Cdecl") ; add to table, addNullDel.c 93 | return 0 94 | return keyBytes+valBytes ; return number of bytes in the added data. (only includes key/val bytes) 95 | } 96 | copyFrom(ht){ 97 | ; Adds all key value pairs in hashTable ht, to "this" 98 | /* 99 | typedef struct copyParams { 100 | tableData** destTable; 101 | pfnLib lib; 102 | put pput; 103 | } *pparams; 104 | */ 105 | ; Set up copyParams, these are uParams for ht.forEach(...) 106 | local uParams 107 | varSetCapacity(uParams, 3*A_PtrSize) 108 | numPut(this.table, uParams, 0, "Ptr") ; hash.h 109 | numPut(hashTable.fnLib, uParams, A_PtrSize, "Ptr") ; hash.h 110 | numPut(hashTable[5], uParams, A_PtrSize*2, "Ptr") ; hashPut.c 111 | this.checkIfNeedRehash(ht.count()) 112 | ht.forEach(this[16], &uParams) ; this[16] is copyFromHashTable.c, see initBin() and initBoundFuncs() (in the last it is just a comment) 113 | return 114 | } 115 | toFile(path){ 116 | ; File layout: 117 | ; bytes 0 - 3, uint: keyBytes, number of bytes for keys 118 | ; bytes 4 - 7, uint: count, number of keys (and values) 119 | ; bytes 8 - 8+keyBytes-1, keyBuf, all keys, '\0' delimited 120 | ; bytes 8+keyBytes - 8+keyBytes+3, uint: valBytes, number of bytes for values 121 | ; 8+keyBytes+4 - 8+keyBytes+4+valBytes-1, valBuf, all values, '\0' delimited 122 | ; 123 | local raw, success 124 | local fo := fileOpen(path,"w") 125 | if !fo 126 | throw exception("failed to create file: " path) 127 | raw := this._toString("","",1,true) ; get keys 128 | fo.writeuint(raw.bytes) ; write length of keys 129 | fo.writeuint(this.count()) ; write count 130 | success := raw.bytes == fo.rawWrite(raw.buf, raw.bytes) ; write keys 131 | this.free(raw.buf) 132 | raw := this._toString("","",2,true) ; get vals 133 | fo.writeuint(raw.bytes) ; write length of vals 134 | success *= raw.bytes == fo.rawWrite(raw.buf, raw.bytes) ; write vals 135 | this.free(raw.buf) 136 | fo.close() 137 | if !success 138 | throw exception("Failed to save table to file. ( " path " )") 139 | return raw.bytes 140 | } 141 | rehash(newLength:=0){ 142 | ; "Manual" rehash. Typical usage, when removed many values, shrink the table. 143 | local newTable 144 | local prevLength:=this.length() 145 | local table := NumGet(this.table+0,0,"Ptr") 146 | if (newLength==0) 147 | newLength:= (this.count() / this.maxLoad) * 2 ; If new length is 0, choose the new length to be half way from reaching the maxLoad. 148 | if (newLength == prevLength) ; No need to rehash if already at desired length 149 | return prevLength 150 | this.initSize(newLength) 151 | numput(this.nextSize-1, table+0, A_PtrSize*2+16,"uint") 152 | newTable:=this[3].call() ; rehash. 153 | if !newTable { 154 | this.initSize(prevLength) ; updates this.nextSize 155 | numput(this.nextSize, table+0, A_PtrSize*2+16,"uint") 156 | throw exception("Rehash failed. New length: " newLength) 157 | } 158 | NumPut(newTable, this.table+0, 0, "Ptr") 159 | this.size:=this.length() ; not really needed. 160 | return this.size 161 | } 162 | ; Persistent related 163 | deletePersistentFile(){ 164 | ; Deletes the file in this.path 165 | ; Note: you should also call makeNotPersistent() if you do not want the table to be saved when exiting the script 166 | ; Returns true on successful deletion. 167 | return fileExist(this.path) ? (!this.fileDelete(this.path)) : false 168 | } 169 | fileDelete(path){ ; help function for deletePersistentFile(). 170 | fileDelete, % path 171 | return errorlevel 172 | } 173 | makePersistent(path:=0){ 174 | ; Specify a path / file name where the table will be saved upon release. 175 | this.path := this.path && !path ? this.path : path ; Update path if specified 176 | this._isPersistent:=true 177 | } 178 | makeNotPersistent(){ 179 | ; Unflag the table as persistent. 180 | return this._isPersistent:=false ; keep path 181 | } 182 | getPath(){ 183 | ; Returns the path of a persistent table 184 | return this.path 185 | } 186 | _isPersistent:=false 187 | isPersistent(){ 188 | ; returns true if persistent, else false 189 | return this._isPersistent 190 | } 191 | _loadedFromFile:=false 192 | loadedFromFile(){ 193 | ; returns true if the table was loaded from file, else false. 194 | return this._loadedFromFile 195 | } 196 | ; Methods for viewing the table. 197 | toString(del1:="`t=`t",del2:="`n"){ 198 | return this._toString(del1,del2,0) 199 | } 200 | keysToString(del:="`n"){ 201 | return this._toString(del,0,1) 202 | } 203 | valsToString(del:="`n"){ 204 | return this._toString(0,del,2) 205 | } 206 | ; toTree not available in v1 version. 207 | /* 208 | toTree(opt:=""){ 209 | local gui,tv,parents,cbfn 210 | if (opt == "") 211 | opt:="R20 w400" 212 | gui:=guiCreate(,"Hash table - tree view") 213 | 214 | tv:=gui.addTreeView(opt) 215 | gui.addText(,"Number of key/value pairs: " this.count() ". Table length: " this.length() ".") 216 | 217 | parents:=[] 218 | cbfn:=ObjBindMethod(this,"buildTree",tv,parents) 219 | this.forEach(cbfn) 220 | gui.show() 221 | WinWaitClose("ahk_id " gui.hwnd) 222 | gui.destroy() 223 | return 224 | } 225 | */ 226 | ; Print tableData struct. 227 | printTableData(show:=true, extra:=""){ 228 | local table := NumGet(this.table+0,0,"Ptr") 229 | local outstr 230 | outstr:= "Buckets: " . numget(table+0, A_PtrSize*0+00,"ptr ") . "`n" ; Buckets (the address) 231 | . "tableSizes: " . numget(table+0, A_PtrSize*1+00,"ptr ") . "`n" ; tableSizes (the address) 232 | . "maxLoad: " . numget(table+0, A_PtrSize*2+00,"double") . "`n" ; maxLoad 233 | . "length: " . numget(table+0, A_PtrSize*2+08,"uint") . "`n" ; length 234 | . "numKeys: " . numget(table+0, A_PtrSize*2+12,"uint") . "`n" ; numKeys 235 | . "nextLenInd: " . numget(table+0, A_PtrSize*2+16,"uint") ; nextLenInd 236 | . "`n`n" . extra 237 | if show 238 | msgbox, 0x40, % "Hash table data", % outstr 239 | 240 | return outstr 241 | } 242 | ; 243 | ; End user methods 244 | ; 245 | ; Nested class 246 | ; when making a new hashTable, a reference to a "router" is returned. the "router" contains the reference to the new hashTable object. See __new() 247 | class router { ; For familiar array syntax, i.e., [value := ] myHashTable[key] [ := value] 248 | __new(ht){ 249 | ObjRawSet(this,hashTable,ht) 250 | } 251 | __set(byref k, byref v){ 252 | this[hashTable,5].call(k, "wstr", v, "Cdecl") 253 | return v 254 | } 255 | __get(byref k){ 256 | return this[hashTable,6].call(k, "Cdecl str") 257 | } 258 | __call(f, p*){ 259 | return this[hashTable][f](p*) 260 | } 261 | __delete(){ 262 | static ht:=hashTable ; Because needs to call destroy() for persistent tables even if hashTable has been deleted. 263 | this[ht].destroy() 264 | } 265 | } 266 | ; Init methods. Most init methods are called by __new. NOTE: There is "static" init in maketableSizesArray() 267 | static init:= false 268 | maxLoad:=0.7 269 | __new(size:=23, path:=0, clone:=0){ 270 | ; The clone parameter is intended only for internal use. When cloning a hash table. 271 | if !hashTable.init 272 | hashTable.initBin(),hashTable.makeFnLib() 273 | this.icbfn:=registercallback(this.traversecalloutRouter,"cdecl Fast",6,&this) 274 | this.initSize(size) 275 | this.initTable(clone) 276 | this.initBoundFuncs() 277 | this.loadFromFileIfPersistent(path) 278 | return new hashTable.router(this) ; returns a "router" object, which has a reference to the new hashTable. Use all methods on the returned router object. 279 | } 280 | loadFromFileIfPersistent(path){ 281 | if (path && fileExist(path)) 282 | this.addFromFile(path), this._loadedFromFile:=true ; The file exists, load 283 | if path 284 | this.path:=path, this._isPersistent:=true ; If path is specified, set _isPersistent to true, for auto saving on delete. 285 | return 286 | } 287 | initBin(){ 288 | ; Can be freed via freeAllBins() (you shouldn't) 289 | ; See c source 290 | local pnewTable,pdestroy,prehash,remove,pput,pget,pfindKey,ptraverse,pfindVal,pmultPut,pmultPutConst 291 | local pmultPutNoDel,pforEachVal,pclone,paddNullDel,pcopyFromHT,pgetFromHash,pnext,j,raw 292 | if (A_PtrSize == 4) { 293 | pnewTable := [2203276887,267526380,1009009680,807695499,874806411,539231431,4060086272,608440591,2245525272,2304275648,3036974531,0,4280550537,2311095767,2235855875,823424246,2332224466,2416232195,0,956416643,2347791830,4063765572,608964623,276007192,1328071,4060086272,139137295,2332312457,2302944324,3632863299,1528874115,834887518,2432035776,2425393296,2425393296,2425393296] 294 | pdestroy := [1398167381,2334977155,2336236612,2336498780,608471312,273320732,1165281669,2422669105,747307659,1961723320,649366833,0,2332317067,344522869,72613668,2299024779,1409229844,606898436,1409283465,1979090180,608472031,2333117212,3347255370,1926183169,2298645439,1409229828,608471812,2298514204,2336236612,3296920643,1600019244,2430664541] 295 | prehash := [1398167381,2336025731,2337285188,71994128,2333622923,4286939452,673479817,18383887,3229810688,608471297,608471828,269480532,1284048962,267520036,203703313,1149829259,1149961252,76097572,608471844,273743700,3347693701,14713871,1149960192,9130020,2299809931,1351291991,265454864,39812,608487168,44,611617536,7769388,881526923,1962313137,649366898,0,2332317323,444206,251658240,2238057143,2407796681,2197815296,3224437442,443,3417247488,16958083,3252259272,3643344353,3071265673,2238119498,837187017,611645394,2500103464,0,143329027,74828165,3247001835,3229942155,831125621,4002016645,1150000757,9130020,2198884491,19670084,740586635,2182075961,4294967156,76087435,608471844,72417108,1344554123,76087435,608471844,72417108,2302461059,1600019448,814334813,3224483563,3296960235,1539322172,3277676382,2425393296,2425393296,2425393296] 296 | remove := [1398167381,2334977155,256386140,2238067639,3817082870,251658240,29349559,822083584,264843712,3246643119,153914625,4203335681,688251585,265783802,1716196535,3816149637,405040265,1076133003,1066127921,2333112311,2416217351,1149843595,4286913572,11109391,3979411456,1468778885,1714058244,812986937,1820966961,317396004,649366928,0,1127003919,1110194534,3229816437,1976056065,611093487,608471828,1015244312,427032578,4253616011,74760325,3102459785,3089941635,2,1566531163,2347599299,2304144391,1149960261,344540196,72417060,2299021195,1149969412,1358906404,608471812,607947076,2332315903,2336236612,342393600,751076097,440,1600019200,1153942365,6180,3224436736,971622705,2214592511,3224448196,1566531163,611617731,2332461340,2733311063] 297 | pput := [1398167381,2338122883,2340168788,2339644540,1719149684,251673219,82308,3955241216,2379778306,2204500312,1962957372,4492788,609519876,604277032,1418401791,3314100260,3071262769,2305180172,2197833036,3275293120,1150021747,1418555428,9128996,270816393,1210340493,203707529,2299547787,2298750068,2332566612,604276992,2198362111,21767292,874792073,12157967,80150528,3108,1712848640,2298494595,3414429633,822083584,2298670016,22580696,1581024102,2381608192,2298740804,2301109324,402596868,2422657585,1443673871,1342998886,956416643,2347857626,2301109324,1149961281,29838372,0,2231921033,2336978112,2301895748,608471816,608487280,44,2346397952,342919936,2366654603,1418264918,1351165988,611114772,608995624,610044200,611114796,138992680,3923757529,1316477149,3296968753,1600019292,1150010205,1418424356,9127972,210305163,2309680016,138447814,4280550537,1854473303,1556382472,440,1600019200,45663069,822083584,4274514395,45678591,822083584,4282247643,1150025727,2089381924,76088356,207093540,1881439371,4290250633,3959422975,2425393305,2425393296,2425393296,2425393296] 298 | pget := [2336025731,2369791044,2334925908,609519872,609520912,609519912,273713932,136598665,1210340491,69489801,76087435,608471844,139525956,2089013809,1963011108,139496195,3296972937,2425406268,2425393296,2425393296] 299 | pfindKey := [1398167381,2332355715,253502556,2238067639,3447984118,251658240,29218487,822083584,264843712,3246642607,154963201,3934900225,688251585,265652714,1716196535,3816149637,1962398257,76357668,149,611093248,5605668,673469579,711,1418395648,747313188,267224322,33924,7769344,1435224453,1713665028,645214777,2305212465,3942786164,884412170,876176963,2200008002,3359179200,3071274869,1711416436,3816579,1166749300,1958774016,3955591443,7769539,251676043,35943607,3983917189,673465483,131271,3901292544,1527039107,3277676382,673465483,65735,3296919552,1541966084,3277676382,3224502065,3375485489,4294925545,3955241471,2425393363,2425393296,2425393296] 300 | ptraverse := [1398167381,3677484593,2336025731,2337285188,273189632,2215627141,265,11867277,2298478592,2334925908,2990312208,2215640965,230,1150020913,3280166948,611617025,610044176,608471304,608471828,608471388,138906380,69485705,2298759051,1426007044,4169357348,2122151167,1958774041,33063791,126582389,3230006665,9667599,3347644416,4169381099,113150,1685389312,1284048779,1149839396,1200301092,604276996,1411662987,2332315903,76089415,608471844,72417108,1411662987,4280564873,3984917584,606356619,673467531,1166621300,609520384,2199030608,2231440490,3097457865,4294967294,1530709123,3277676382,2766915889,649366928,0,3347708041,4294917609,649367039,0,1344558219,740588683,311104139,3946448009,608471992,2332068688,3330478152,265173249,4294899586,112895,2968190976,2425393296] 301 | pfindVal := [1398167381,2333142147,254551132,2238069687,2844004351,822083584,29459401,1262256998,153914624,1150022517,9118756,2232438923,609520082,2338944008,608487168,4,608471296,608471820,609520396,2419362564,1031075461,1452001669,1713992712,729102905,881442865,2299783972,666668534,0,1127528207,1110718822,3229824629,1976056065,607423471,708608870,2334815232,1979090230,608469955,1149960452,1144587300,2775910436,823182467,1600019392,3062743901,0,3945018507,71732182,1527825539,3277676382,3375492401,4294925801,2425393407,2425393296] 302 | ; -O3: 303 | pmultPut := [4281423701,3968029526,615811964,160,3347645163,1711359885,4266032259,267613440,2626367159,38948,268403968,1059341461,807683271,0,673465543,0,874792135,0,649366928,0,874792075,673465347,256052365,2238054839,1712354496,2215635001,1243,673465475,1725819649,125169029,1059355776,2235004160,608487423,64,824931584,7769563,807683211,2619640971,16777216,1091341784,1711388431,678740101,266877286,278404,29590272,3224492779,673465345,1076118727,1,1989002731,666668288,0,1978500454,612139019,2232352831,1221,2232418181,1213,673475723,36521101,1210336393,2334393481,9708676,285147136,1149889925,2215589924,647,874792075,268457101,2314224269,55321668,9970820,3314089984,941900939,1143237769,957368461,3247640525,2357972361,38948,969998592,266897864,3356017043,81560591,1284177920,4186122276,3481669390,2332033028,2202281028,3906015200,3766737143,264780039,3375481159,2215624837,179,2552540299,2332033024,2201232460,3071214072,2332052812,1714955372,251678089,324228,613190400,152,251852931,4061220023,38635878,80708623,2357919744,38948,66618112,290240271,1300850420,2894335748,2332033028,9970828,4169334784,1287065348,2305226257,2215577165,1161,2552532107,2197815296,3071215096,1727533388,252202377,288388,613190400,152,252180611,4195437751,172853606,71533839,2357919744,38948,1421283072,129629201,1711276032,2332841353,690496596,2378170818,1418328170,3988870180,22383875,1143231625,2298733249,2337285204,2369266772,1141047852,3526446116,2552529923,1711276032,2197843727,3313697218,281051920,4031058191,1143231545,1150019959,3238088740,1411662907,2215627401,267,874792075,1143231625,1143229579,1149878785,2223721508,38948,23694592,673475641,1343534863,941900939,1209305446,2249190025,215,1277455499,1277449353,3506563465,2552534155,251658240,2336885943,1716266068,2337279113,2370053196,1413022289,1418274852,2249149476,163,3506563465,2552534155,251658240,2336885943,1716266068,2337279113,2370053196,1413022545,1418274852,2071350308,3506563465,2552534155,251658240,2336885943,1716266068,2337279113,2370053196,1413022801,1467361316,2894850441,38948,265355520,5065911,1342998886,1143229579,956649869,1982342228,608996150,265355572,5065911,1342998886,1143227531,956743811,1982342212,608996122,18124084,2552532107] 304 | pmultPut.push([251658240,2337346743,1714955340,2336298121,2335712324,826811468,458526189,1820943874,2223767048,37924,605325568,1143231625,1284182271,3314102308,2619638923,2365587456,3224455180,649366928,0,1091876623,1163168102,29393664,4034118457,874792075,1143231627,4160866609,673465347,357337446,608471550,608471860,33030448,610045400,608471404,612666160,144,1552482443,1552748580,1552508964,1552616484,1351301156,610044176,609519876,2298514184,2223711236,37924,139525888,1814330499,264472833,96132,612666112,148,203687111,4278190080,609520400,608996204,51000,2298478592,3531933800,251938953,50309,614238976,144,1747209355,311104395,2307523721,3339750360,2892868,822083584,339905499,2198882955,1149829568,1116284964,611114772,608995624,610044200,611114796,139123752,3923757529,2265962717,313,1076118667,2232402053,288,3341727503,2630724,2332033024,9970844,1776877568,2315255803,666668534,0,2215640965,4294966256,3062743089,0,251773059,1715541175,256250937,99461,264714496,97414,3531957760,3342459509,4223829007,1418461183,3531948068,8225807,3271622656,4294684649,2332264959,9446532,1122566144,2248146943,1753485311,822083585,29393856,1091876623,1175730534,3342409333,2238061174,971666898,608487367,64,1099239168,3925868539,4294966031,1153943353,16420,2215575552,4294966015,265454950,4294648708,608436735,614239016,152,4294618089,609520639,2243965248,2206430674,3224468676,1566531163,649366979,0,2299019403,2223711236,37924,72417024,941900939,2334393481,9708676,1358888960,608471812,141265216,2215624837,4294967008,3095184515,1,1566531163,612666307,148,69485705,2418312331,2298478592,2223711236,37924,206634752,2418318475,2298478592,4271565059,1284243455,1821059108,3526440996,1143227531,1277451401,2520205,1344059151,1432127846,29524736,4034253113,1277451403,4294785769,440831,3370713088,3120562171,5,4294688489,309759,3035168768,3120562171,3,4294683369,178687,2699624448,3120562171,1,4294678249,264714751,4294593412,3531958015,4269835279,3230007295,441,3242462976,3655975681,3355443193,4203588,3909091328,4294965703,2425393296,2425393296,2425393296]*) 305 | pmultPutConst := [4281423701,3967898454,172,3357842571,2332033024,13640884,116064256,2520205,1200473993,2088986113,1962999366,2311074291,824976508,2345109961,13378732,82509824,3515467657,2365736845,2204500305,16647548,76410485,612141330,612141908,2311751980,13640884,1284046848,1149845540,3071237156,2245953798,608487423,56,614238464,200,608474383,1149855315,2223714340,52260,266371840,3640125649,956817539,3242659784,1149879689,3364450340,2223630377,32804,4164979968,2198071489,1149829568,3770774564,608471299,4282551676,1149888553,1150118948,3979411501,2015642761,3424945155,2298478592,8660100,2223702016,52260,281051904,1612989577,649366928,0,941900939,210626561,28774214,1958774118,1144743440,2215587876,1397,3942761859,2088986335,1962946596,612139019,2232352851,1824,740574347,2232402053,1812,1009009863,0,36521101,1143227529,2334393481,12854404,285147136,1149889925,2215587876,510,941913227,1334691721,911510800,4030893328,1277445257,3357836291,956301312,613190600,200,608473871,1555435336,3506522148,2467286841,264964289,425860,251495168,108430863,3766681600,608487183,72,4159230208,132154328,1192224825,264275397,36996,614238976,200,251787395,1718815927,2215579529,1790,3357838475,2197815296,3071214328,1727140172,251809673,448644,615811840,200,251918467,4095102135,72321382,112362511,3071213568,2213942860,2305164536,2215577167,1683,374126351,100172792,139430246,108299279,3071213568,2214205004,2305165304,2232355407,1621,374650639,608487420,1864,1468622336,2347469068,2337023060,690758780,2378170819,1552545867,3254872100,807683075,3357840387,3238002688,1502413801,2378772737,56628,1552482304,2626377764,51236,611617024,615811940,208,40832870,2197930371,3229814978,1074859792,608975856,2313777752,13640884,1149960192,1955285028,2089378852,2626235428,51236,1005584640,258483316,34180,2346682624,2335712348,2368742516,3071214356,2305185556,1351435796,1993685249,319589737,1326233359,1443662182,956453005,2371319509,3071218444,2305183500,1351439884,1993685251,319589701,1326233359,1443662182,956584077,2368960213,3071218444,2305183500,1351439884,1993685253,319589665,956743811,213323717,210331215,2333046358,2369266780,3071214356,2305185556,1149978132,1955278884,4281418788,813468006,608472062,604277084,3290727563,4278190080,2344716560,2235573316] 306 | pmultPutConst.push([3749973952,989855745,2371888204,2467237953,612645314,204,146838287,813961154,2197815300,239084668,69568015,1552613376,3682955300,63013903,2223702016,52260,33260288,1711322895,2215575945,1191,3424945291,2197815296,3071214331,2305163840,2215576129,1157,3424945291,2197815296,3071214587,2305164352,2215576641,1123,3424945291,2197815296,3071214843,2305164864,2215577153,1089,3424945291,2197815296,3071215099,2305165376,2215577665,1115,3424945291,2197815296,3071215611,2305165888,2232355393,1081,3424945291,251658240,1712079031,3087810953,7,1814330499,2339468806,829957236,611092955,608471364,613714760,132,2089539721,2626366500,51236,2311979264,615812085,208,175050598,2197930115,3263369413,1292963600,608451056,2347333492,2303206468,13116572,1552613376,1821080612,2089370660,3028888612,53284,1004011776,8397980,2215575552,146,3424957579,251658240,1715868855,2202080393,1144586688,2054570020,1175762703,1076130955,1091864934,956387469,2338813654,13378716,3071213568,2305184540,1351438620,1993750786,614239057,204,1394390799,1360824678,956518541,2335930070,13378716,3071213568,2305184540,1351438620,1993750788,614239013,204,956678275,481759174,478766675,2333046353,13378716,3071213568,2305180436,1149976852,3677443108,2619651213,2298478592,1715741772,2332105865,2369266756,9970844,1141047296,3892390948,941900937,3223618699,2332033024,611617024,610044176,611617548,273713968,69497993,136598665,76087435,612666148,196,2198360319,10233020,2298544128,608996293,1619267396,2332033025,12854404,1284046848,80167972,3108,2333146880,2336498764,3341821044,0,138971392,2619640971,2298478592,3380937840,18515215,3029008384,49188,613190400,152,311105163,2307523721,3339750384,3417156,822083584,339905526,2198887051,1149829568,1116287012,611114772,610044208,611617072,611114804,139123760,3923757529,2265962717,330,1009013899,2232406661,259,3492054155,822083584,615812077,200,1711322895,807683209,4294602729,608472063,264275244,4294615940,2347993599,2334925948,13640884,3224436736,2520205,251773059,1715541175,1967526969,1992767811,3531957823,3342461557,740588681,3357842569,2298478592,13640884,1153892352,15396,2215575552,4294965856,1153942785,80932,1374224384,2315255802,666668534,0,2089404217,2626235428,51236,615811328,208,4196828175,2238119935]*) 307 | pmultPutConst.push([29979858,3923675589,4294965720,649366928,0,2332050825,12592260,4008247296,2348810238,1284048960,76104740,612666148,196,2332315903,2301633604,2223711236,50212,72417024,1009013899,1143229579,1300877957,4253290248,2181038078,44228,112640,1583022080,834887007,612139968,2265908844,4294966491,3424945291,2332033024,13378740,3071213568,25781760,440,4249282816,2223767551,50212,608471296,612666116,192,2334393481,12854404,1358888960,615811852,192,2313750153,2315255806,2336498796,824976508,609520576,615287616,204,3492066443,2415919104,2520205,1163704079,478766592,29393729,4034249273,1143237771,740588681,3492066441,3909091328,4294966606,740588683,807685259,3029062193,53284,481758976,478766672,29524817,4051031353,740588681,3492066441,3909091328,4294966034,1153941553,80932,3305177088,4294501353,309503,4192796672,3103784955,3,4294701033,178431,3857252352,3103784955,1,4294695913,440575,3521708032,3103784955,5,4294690793,608487423,1608,4189055232,1153957887,346148,2733178880,3355443193,71836740,3909091328,4294965653,1210336455,3,4294543593,608487423,584,4185647360,1153957887,84004,1860763648,2432696313]*) 308 | pmultPutNoDel := [1398167381,2340220035,10495148,3029008384,39972,608487168,1076,1961723136,2210410775,2204500416,16664188,1149891957,3221303332,874792073,2089545865,3766693924,4159230223,132154328,1192228921,2314023367,608471489,704153916,608471496,4164980040,2198071489,1149829568,3770762276,608471299,2214103372,3358130664,1076118665,2299069581,22291524,608471536,273059152,941900937,2552530059,1711276032,6831235,22774799,3163226112,40996,268403968,89989,1015244288,2215575662,996,2485421195,3338665984,271364,285147136,1150011273,76100644,612666148,148,3280539903,2552530059,822083584,79106002,126445160,2305212465,3071214151,2305191428,2305163859,612666115,144,1814318221,1747211405,2332149123,608995584,609519888,273713932,69500041,136598665,76087435,612666148,148,2198360319,23864444,2215625353,652,673465481,2485421195,3338665984,795652,285147136,2332579977,3345753180,0,75008256,673469579,2232408965,588,2418326667,2332033024,2338858060,2299693847,4169763332,1153896587,11300,3677421568,2333360779,3229814858,608471297,339904808,673475807,673467529,740580489,673475807,3641199324,3723091913,3448115160,2348810238,9708676,1149829120,2223703076,36900,604276992,2485421195,4278190080,3163229264,36900,2332526848,9970820,2204499968,251684924,4294878597,2093253631,440,1600019200,3062743901,0,2485421195,3338665984,271364,285147136,1150011273,76100644,612666148,148,3280539903,2552530059,822083584,610024393,79105848,1334404712,3264417538,2366081382,3325628483,146838287,3246657474,2197815297,238036092,28739087,1284177920,3380952100,25854991,3071213568,33129222,251890022,134020,1186402048,49906434,37980518,32146447,3071213568,4186113094,1133078019,3380875012,251658241,2198226615,2305164537,2215577155,424,138852111,1711667587,252199817,100228,1186402048,133792522,172198246,23758095,3071213568,2305166406,129502275,2197815296,104866940,1284194934,1149850660,3224447012,2332759181,1716528204,2197909263,3246588352,281182992,4030861583,1143227451,1284237682,1149979684,3355519012,1210338361,4258759695,3062759423,0,1175762703,1125419366,956416131,254813252,4294818950,347541503,344548934,22056259,807687225,4255614479,3071279103,2305185292,1351439116,609499394,2458259248,268435453,1716915383,2371030153,1413022544,2249142308] 309 | pmultPutNoDel.push([4294966653,1443673871,1393330534,956584077,254813268,4294797446,213323775,96502614,807683129,1393330534,4250109455,3071279103,2305181204,1189692180,2432696317,2520205,2223702665,36900,4256884992,2422669311,2299019403,2301109332,2223711236,37924,72417024,2485421195,2298478592,1358898236,609520388,140151080,4294743017,7769599,2089009201,252067876,4294893959,112660479,3087239526,1,4294912233,7769599,807685259,1989001265,666668288,0,1175762703,1125419366,956416131,3924915649,4294966461,1720,4271499520,2422669311,1464,4270713088,3062759423,0,1208,4269664512,3062759423,0,952,4268615936,3062759423,0,696,4267567360,3062759423,0,440,4266518784,3062759423,0,830260355,1600019392,2425406301,2425393296]*) 310 | ; -Ofast: 311 | pforEachVal := [1398167381,2337074307,1718101100,32131,26772495,3677421568,1711391619,6126723,456428800,1150022261,4281425956,740574407,0,9171593,2232436875,2373481673,48436,1955135488,814429220,2243835019,3344790774,3155012,2415919104,2520205,1317788549,255030280,1711293879,829751609,1418313777,401287204,649366928,0,1163179791,339305984,2441416513,2197815296,3627614656,1418455669,2204510244,1946161468,2234944291,2344187382,2338333764,273189632,956417923,3095950031,1,1531757699,3277676382,673469577,1948537995,740574339,612141313,608471824,608995628,609519876,609520404,608471408,609519880,71731980,4280550537,2204902484,1418461176,2215585828,143,3229950846,4169380468,1300565761,2315255807,2335188084,2424892214,2520205,673469579,4294932713,4277699583,673465543,1,4280714511,109838335,1009013897,941900937,2298758795,1149969412,1358914596,138840836,2334393481,4284752964,1149961296,881419300,72417060,807695499,941900939,1009013899,628422277,1955268233,1284202532,915089444,18116227,729139589,283756169,3355443199,2630724,3942645760,611617693,608996192,2335607604,235178294,4130458859,1877596977,2214592510,4273491140,1543503871,3277676382,2425393296,2425393296,2425393296] 312 | pclone := [1398167381,2338122883,2339382340,2339644540,407931648,337925257,1074794482,286257672,2332828740,1418265680,394987556,69489801,2299543691,1476338692,2311095568,608471495,4119072572,2332033028,2339382340,340822784,2333366153,3531935824,81036303,1153892352,19492,2089484288,143346724,12399757,2298478592,2335450228,3984963884,63144975,1820917760,1988961316,666668288,0,1948533899,203687111,822083584,2299592667,2334663748,2334401604,3062694976,0,1711391619,4267211907,2348119296,824452164,138447862,1711392387,4268784771,2381673728,76094212,608471844,2299592564,906268103,2334393481,4285801540,2344978704,2334401604,1116537936,2378643728,2467237959,264387009,3238576275,56132623,4219666432,1334185742,2298478595,608487376,48,266371840,3640125649,956817539,3276214232,1953808517,2198517519,2305163768,2424573711,251658243,2197965495,2305164024,2215576143,882,72005391,1711536259,251940745,218244,1253510912,83395334,105875814,53904399,3071213568,4169336906,1334404613,1719930632,251658243,2198489783,2305165304,2232355407,840,206223119,807683271,7,206539110,1153948041,11300,1418264576,3240708132,1284096001,3917692964,65650952,2298593667,3241681996,1284047841,210584612,1727529218,2198433551,1149440192,2197892132,1418399937,286207012,1413214280,3815913508,1143229579,807683211,1210340491,1278855169,2054438948,1108129551,740574345,1192003942,956385421,258438859,1716126903,2337211529,2368480324,3409510984,3071235190,2305182212,1149980420,1217211428,1993029891,79105857,76113482,608471887,71863596,779537209,1241822991,1325697382,740574347,956647565,253458123,1716126903,2337211529,2200708164,3275294400,3071215734,2305180180,1149978388,1351296036,272993544,1116586553,3247640336,2467284281,264308928,123780,251560704,31098383,3498639360,3507478659,2212034536,4030269408,835077903,1958774235,179769202,1711405187,251678089,154500,1253510912,49840898,38635878,37782543,3071213568,4169335882,1300850179,629411588,251658242,2198227639,2305164536,2215577165,522,139114255,1711667331,252202377,126852,1253510912,133726986,172853606,30704911,3071213568,129698890,1711276032,2299284873,608487409,44,609519872,29436228,608995776,149521216,2198071745,1284047297,3787534372,608995587,34377016,258402305,3229815151,608469776,3246588204,609520400,1343295276] 313 | pclone.push([609499632,2346940208,2335712332,2302944340,1004011976,1950360652,213323625,1284073026,1217200197,1993226497,481759065,1552508490,1217200205,1993226498,481759049,1552508490,1217200205,1993226499,481759033,1552508490,1217200205,1993226500,481759017,1552508490,1217200205,1993226501,481759001,113279818,2305214009,1979731292,347541257,1418290754,1149960261,13051940,0,2298771593,1149962344,2089493540,9124900,606356617,874792075,277546755,74830469,3263790827,3229942411,1150023797,42543140,606356619,2232402053,4294966356,1881425035,1351286923,608469776,2089484620,3610856484,4229202447,1150025727,3296934948,1600019292,3224486749,1108129551,1192003942,956416131,3924915651,4294966790,649366928,0,3071262769,2305180172,2197833036,4030267840,1609166965,2315255807,666668534,0,673479819,2297116809,807683271,4,4294766569,608487423,816,4242729216,1153957887,143396,3588816896,3355443196,19932228,3909091328,4294966472,807683271,6,4294753257,608487423,1328,4239321344,112984063,3909091328,4294966831,1467,4263897344,79429631,3909091328,4294966811,955,4262586624,45875199,3909091328,4294966791,443,4261275904,3296985087,1543014748,3277676382,828163203,1600019392,2425406301,2425393296,2425393296]*) 314 | ; -O3 (paddNullDel) 315 | paddNullDel := [1398167381,9235585,3029008384,45092,267814144,365700,615287552,168,941900999,0,1076118727,0,1009009863,0,649366928,0,1009009803,822086797,223645120,981689856,3910104320,1601,649366928,0,1485691017,1015244289,4101308506,2298658947,2301109340,21767236,608471488,48792400,1411662985,1076118667,2888088715,16777216,2311520704,1715741764,251674499,381828,2344628480,3945276508,649366793,0,1888350345,1015244289,4101308535,2298658947,2301109340,2301895796,22553668,608471488,48792412,1612989577,1344554123,1210340489,807685257,2334393481,10757252,285147136,807685259,1150141065,3258519565,2467287177,254813252,807689398,2299576451,2335188052,961029204,3230863298,2215625480,1296,673471627,252640131,328582,3352725760,4727876,2197815296,4035514342,3640125649,956817539,3276214232,2215624837,130,2333259535,2200970332,2305163768,3968077587,251658245,34428087,1711470723,251810697,379268,1421283072,4169335821,1401513475,2793672452,251658245,101536951,1711601795,252072841,361348,1421283072,4169336845,1401513477,1619267336,251658245,168645815,1711798403,252334985,343429,1421283072,1153895437,477220,2305163264,1552616531,3733530660,3221341737,2314753677,3243254900,1921844202,18124033,807683075,1955186993,3871418404,2313814275,2338595956,1714693236,2197974799,3263365569,281051920,4030730511,673467451,1284237682,1149985828,1552500772,1955145764,3355522084,1344556089,10716175,1284177920,1955281956,344797220,1421283073,2305163349,1351435796,609499393,2189823784,2298478592,265355723,5065911,1443662182,956453005,1982342228,31033708,1287065553,2305163341,1351439884,609499395,2304144936,265355737,5065911,1443662182,956584077,1982342228,31033664,1287065553,2305163341,1351439884,609499397,2301261352,113279961,1144639745,3071223844,1711295820,1985350793,608996116,18124092,807685259,1431615247,344548864,608471873,608996144,1725641044,2332564617,2304517188,2223711236,42020,2333146880,11281548,1955266560,3280552996,2366657421,957362500,3230863299,2467288889,264374466,211844,609520384,251298612,53380623,4186505216,2299519363,4159230408,132154328,1192218681,2244555202,2156138432,251658240,4169340855,327771649,59409423,2357919744,44068,49840896,3071276937,1711419732,251810697,222596,1421283072,4169335865,1401513475,1233391364,251658243,104420535] 316 | paddNullDel.push([1711601795,252072841,208260,1421283072,4169336889,1401513477,1300500232,251658243,171529399,1711798403,252334985,209285,1421283072,129567801,1711276032,2332840841,2301895796,29829623,4166487488,1344568457,2365844161,3526427002,673479817,2298734529,2370315388,1141048124,2214806564,44068,1863280128,29524744,2198914947,286200000,1413083215,3916900388,1210350731,874804361,3355572361,1344568379,10781711,2089484288,3029024804,44068,118787328,1444198159,1125419366,956387469,255075412,33158,386698496,1309456143,1393330534,956453005,1983128660,973901165,1309456143,1393330534,956518541,1983128660,386698585,1309456143,1393330534,956584077,1983128660,386698565,1309456143,874804363,1393330534,956649613,2368698070,3163232012,44068,113279744,3071264313,2305183500,376853260,1076133003,2332497037,11281596,3071213568,2305185556,1149977364,3375456292,1277457547,2082765965,1009021953,2015655053,51153254,2686747787,2332033024,22553676,2336236620,608996096,611617072,612141324,273713936,69487753,136598665,76087435,612666148,164,2198360319,24913020,2215626377,172,2753856651,3338665984,795652,285147136,2082755723,807685259,199,1485373440,2312275208,1953825864,2686762123,2332033024,2339906636,2299693847,4169763332,1153896587,11300,3677421568,2333360779,3229814858,608471297,339904808,673475807,673467529,740580489,673475807,3641199324,3723091913,2204727256,20456516,941900939,2955183161,251658240,4294611845,2361688575,3087007744,1,1566531163,7769539,2223703689,40996,2425744128,2520205,2299019403,2223711236,42020,72417024,807683211,2334393481,10757252,1358888960,140413188,1988993515,666668288,0,2753856651,2298478592,2332304452,10495108,76087296,612666148,164,2332840191,10495164,126418944,4294929129,7769599,673471627,807685259,3062743089,0,1110750991,1093962086,956416131,3924915651,4294966401,874804363,3062743089,0,1192539919,1125419366,956416131,3924915654,4294966866,1612989639,2,1545880775,4,1478771911,2,874792135,1,4294590441,608487423,596,608487168,1104,608487168,588,608487168,296,4190562560,79298559,3909091328,4294966523,953,4243712256,45744127,3909091328,4294966503,441,4242401536,112852991,3909091328,4294966483,1465,4241090816,1153957887,411684,1552613376,3353946148,3355443194,88613956,2332033024,3911722076,4294965942,1210336455,4,673471627,4294616553,608487423,840,610044672,4204063016,1153957887,149540,1552613376,2213095460,3355443194,21505092,2332033024,3911722076,4294965874]*) 317 | pcopyFromHT := [2333928579,2334401620,2301895748,2332828756,2300585044,2332566612,1418265680,277546020,4280554633,28837968,2197815296,2428705988] 318 | pgetFromHash := [609520467,608471820,610044680,2416216848,896843909,1946286979,2231405360,2200728768,662045179,442,2416700160,2520205,192207417,143378569,2231485059,972125641,47827,1158610944,834886594,2428722112] 319 | pnext := [1398167381,2333928579,2335188060,2335450220,2335712380,2335974516,4232416019,1913668155,3342723865,130119,1166737408,2199096316,1166606784,272775676,1334519414,608471548,608995588,2298645256,3607045124,3547644037,33310595,1528611971,3277676382,2520205,823968899,1600019392,2425406301,2425393296] 320 | } else { 321 | pnewTable := [1398167381,955024200,611592463,1221495072,2303513993,672097991,2669043,3539927040,1220576584,1786037129,3242783113,3590259681,1220576584,1517552521,678753925,838815373,3787540690,1712384771,8658703,0,1208191816,1208533635,3343436345,4100,3967090688,2149876875,4060086272,275976463,142313800,3340268425,7235,1133051904,3632875552,611592207,3296938016,1600019256,3224486749,2425417451,2425393296,2425393296] 322 | pdestroy := [1465209921,2202555222,2303205612,294340822,2345437513,3380942922,3979428724,4202255,2298645324,478890472,3682945216,2422614132,1211861832,4278733707,2336753750,1459556427,3649652744,4294674760,2236090454,1239512575,2334397579,3313702986,1926052097,176900291,1208506111,1225279115,1210322059,1528874115,1096638302,3774826588,2425393296,2425393296] 323 | prehash := [1413567809,1398167381,955024200,1222084936,2303201675,541756366,138578764,2283572033,2244512072,243535835,2197815297,267518400,2299550224,608471513,395003936,1210079231,2303246469,4001632197,1207959552,1250629259,474123032,1166657925,2927890204,1157627904,2337072177,3767092226,3222571853,265454925,35716,1787514112,445336840,182089,1090519040,5093135,264865126,42116,1103114496,440,3375449344,4202255,3250751812,255919586,692373679,3498656194,22121793,255969281,5590199,1725008201,3698706821,4093104689,3242774665,55051232,2336751685,3531950096,1424689525,4202255,1220708680,2236088971,1291154880,2236420745,3666431451,4286285071,2336817151,407538454,29655873,265042241,4294923650,176900351,1208506367,1476333195,3901310984,952402760,1566531163,1564564545,2149519299,0,3943729484,3955241401,1220555157,1530446979,1096638302,3277668700,2425393296,2425393296] 324 | remove := [1413567809,1398167381,686588744,414650181,1221495112,1164367753,2215631749,231,3551989569,441,1170223360,2422657585,30519055,3251276240,3391686114,2369900937,2303263058,747456722,3071230226,2238074900,1222473170,3526430347,2300080631,294340816,3257699660,6130505,266044744,41604,3828434176,1221756229,1946700683,960783916,825062681,3956421056,2149519128,0,1287065412,2202534401,1164313280,1962937403,29524751,1976711492,1015244519,578027561,1224969032,2236144777,1208317120,3035349897,696,3296937984,1600019240,1096565085,2236466013,59459812,2303281268,1476338692,1267419144,139984656,4292446536,2336753751,476611334,112641,2202533888,1583032516,1547787615,834886977,1170223597,1089065521,838860799,3296938176,1600019240,1096565085,2303312733,2336751685,3001747531,2425393296] 325 | pput := [1430345281,1465209921,2202555222,1097220332,1207974275,2303250313,3314109654,265128269,84612,3955241216,2149519113,0,1351473289,2202101249,21884,1976797512,38309359,4291363144,3297331478,2422652977,3229860489,3071230209,956323148,2302764760,3967177740,1208453960,1009013901,608996684,1082868792,1418283032,2303205412,143345898,2198886143,20718716,264603977,49028,1620224,385810432,8225638,3330885888,13992975,3224436736,258345195,17439,1351473289,2088986113,1207959637,4034253705,1208109197,385861889,258396721,17439,3263418761,3071230977,956321092,2302961370,3967174660,138840393,1009009803,444233,1291845632,2232444553,1296397504,1207989641,258348939,258392303,1116457455,29393692,705644786,474122688,4061676171,3358199624,1247350770,789538320,828143553,3296938176,1600019264,1096565085,3277734237,4202255,2332527432,1211638868,2303459467,2951467060,273189704,3087554303,1,275089741,1086620488,1566531163,1564564545,3116588609,2,3437878065,3120562174,2,1072290609,1224736767,2303259273,408354809,3087501640,4294967295,2425394155,2425393296] 326 | pget := [1223459656,1208060744,1009011853,1288866121,941902989,1153599820,1209548939,539249801,1091078984,823153407,612139986,74776892,273713992,1221626184,3276326019,2425393296] 327 | pfindKey := [1398167381,1209710351,1210348683,1725139273,2215631749,172,3218323215,1,826654769,3618574290,4203335681,688251585,1104644602,1224823437,2370359945,255922732,1716720823,3715486341,4148286001,1221626352,1208213697,1090585739,113709449,0,1958774088,3531949418,138971980,1097214836,762648891,3375485489,258349035,17439,1152847685,2202534417,1164313282,1964180539,29459216,1976645956,2202101479,1946167612,277563416,1959953736,3498657797,113752043,2,1566531163,17221571,1526726656,3277676382,3224497457,826659377,830794706,2430725056,2425393296,2425393296,2425393296] 328 | ptraverse := [1447122753,1413567809,1398167381,1491895112,4130462513,1222084936,2303267211,3314109903,2345437509,3380942922,18056207,2337013760,1290832130,12915853,1224736768,1287662731,1210340489,267224392,59780,4130424064,612666184,192,1208075139,1209030027,1158172043,1955193225,2302746660,1149847768,4282460196,4294476757,8750095,578682880,1853145221,251787395,33669,1166755840,4001974528,264275272,37764,3314108416,4169379563,28852734,1962934272,1166755939,1149846528,2336769060,2303199309,4281869380,2336753751,1476333645,3918088200,1292392447,2336814725,1144529988,1143227531,2303276916,395004166,18639491,1958774085,4294883495,2202599423,1583044804,1547787615,1581342017,1170431809,2783690801,8658703,0,3957885256,395004296,608996168,311117896,168069448,778484715,8658703,0,2333576009,3330480202,265173249,4294897026,112895,2867527680,2425393296,2425393296] 329 | pfindVal := [1398167381,414650177,266044774,37252,3526444288,21138753,1015234918,2303262784,881674434,1223521536,1116410251,1958774040,982206561,1208084611,147287181,1293912908,1165286277,1305642309,1947224971,960587308,825128217,3956421056,2149519128,0,1287065409,2202534401,1097204416,1962937403,29524752,1976711492,2202101479,1946169660,462114072,1977320781,3347269819,4013508616,3224480373,1566531163,1133201859,1600019208,4130456413,3922866501,4294967163,2425393296] 330 | pmultPut := [1447122753,1413567809,1398167381,2028766024,2336807729,14689468,2303197184,12592268,2303197184,13116564,2303524864,3465104580,3548971755,1401804937,1015244289,4067754055,608472392,3071231080,266044735,992232597,114241,3979411456,608471368,1150109776,826633252,3979429312,608471368,2035544,88378691,3246999808,79105857,3229967940,1147539572,2215639097,638,29393729,1164369643,192282501,992246912,4068806400,2231369729,608487387,60,3800370944,822083585,356814290,3263777024,1174714127,1958774118,960783901,3783528440,2197815297,1150091714,2303262741,79105986,3229967942,1164370805,192282501,992246912,2072317696,2231369730,1938100187,1207959554,3357836427,1124073472,33574029,1210340489,608471364,1141964608,1076118667,1221036361,1418445193,2302953508,3229959656,89951559,2417652736,2210498881,2202534336,256312001,1716260023,4266232132,1975728449,3230221543,608471364,3224454472,76105062,2223720519,51236,307006720,609519874,1141964608,1210336395,1076122763,834898249,2149519296,0,347277,213323588,2210498894,3258515904,210322790,2313777995,29962704,2302764765,2336768780,12592260,3573612544,609520456,1418544472,2303459357,1279272028,1344556171,1191217992,1141910669,1209548939,539251849,1224378700,2336753803,13116548,1358888960,612139792,2337014124,255861852,102276,1149847552,2336770084,13116548,414777344,1275068416,1076124809,1418399999,2337041444,1212163164,199,2303459328,3531933816,274237772,609520456,3548712776,1207959552,3223622795,2332033024,1214784588,2336756363,76105746,2223720650,49188,4010763776,4010763968,277563593,2199667339,1223819712,2311072271,1116412994,256438808,267569194,1712343641] 331 | pmultPut.push([264318735,88711,608471808,264275260,80005,3071230976,3224454463,4294826985,1103114751,1153941505,80932,216596480,1728053246,8658703,0,2215631749,4294966851,258392113,17439,21531972,168594755,264800588,1716391095,1326201154,19301647,960757760,495325131,1711276033,3631597957,264976708,4294838916,1284195583,2235907108,25130185,4261013954,2303262719,4282116354,3682992127,17597455,3224436736,1090603149,1208554637,255969417,1716786359,1968116793,1993029918,3531957786,3409568373,1009009863,0,4283794703,1827274751,973078525,608487363,60,1552158464,1728053245,2215629445,4294967095,255967365,21087812,4244826560,2336555007,826025036,3380954560,3224469877,2422622443,273189704,608471368,2223720512,51236,1552501760,1358907428,2223720456,51236,4186524672,2332578047,1211900996,1076122763,610044748,1287685448,252729993,4294887556,112895,2202533888,1583052996,1547787615,1581342017,1220763457,3357840523,1207959552,3223620747,4278190080,2336757842,12592276,2303197184,4270057730,258408447,17439,2215625529,4294966515,264865126,4294893700,1103136255,29770767,4237814210,1153957887,15396,2296971264,2432696316,2425393296]*) ; :( 332 | 333 | pmultPutConst := [1447122753,1413567809,1398167381,3102507336,822083584,3163244790,73764,2357807104,65572,3599321344,1304660300,49008521,4035565193,1711363725,4668547,826667637,1090776036,2302989449,1418543584,1097204004,4668547,822600,76409205,1157006610,2500846217,1216029764,1344556169,1224051021,1478771849,1157138764,2199369487,3511160800,3640084712,1141366915,255975481,826655815,703410624,2311162306,8397956,1116536832,613714424,156,2198071489,2223571392,33828,65061120,2552530057,1090519040,4280566925,3364471433,21545513,2223589568,34852,4160834560,2082755721,612665672,144,612666696,168,608471368,2223851616,44068,1149847552,2370398244,2303201351,1718625348,8658703,0,88378690,3246999808,1124382479,1958774118,960783888,92540880,1090519043,3942760579,2235918047,2148234706,8070268,67798287,4135911424,67273999,1153892352,15396,2369978368,1140981836,1076118665,5635905,608471876,3330885952,2311227720,3229959656,88902982,1713337344,8658703,0,3229860233,3263383553,213323522,1250518603,3359196414,2302995061,1149846720,826621988,2303026880,2336769540,1096295500,1157649919,2303321221,1149977794,2215591972,376,272665928,264714569,994886291,259007572,3255353491,56132623,2202075136,2249133308,846,2149878923,2231369728,25432009,1090519043,2198320911,1097204217,2215576201,888,1203179329,49906434,1116291430,2038697730,1090519043,71808783,1711536515,71469377,56394767,255918080,2198226871,1097204985,252068489,207748,3071230208,4186114119,2302764549,2215577666,782,1203179329,133792522,1116291430,260378378,1090519043,206026511,1116291430,505868,2088960000,1980136484,2357938245,34852,2626374656,36900,1305620736,822742157,255944393,2199061615,255918529,1209074705,957399683,8660108,3849781248,2552532107,16777216,613170120,156,3263789684,1090633859,1460451087,1724135745,1376553281,3263784566,213323585,2302764631,1351438860,3560521985,255939190,1716980919,1376553281,1090670733,1081529401,213323585,2302764631,1351438860,3560521987,255929974,1716980919,1376553281,1090801805,477549625,213323585,96502615,1724135745,1376553281,255920758,1715934391,1108642113,608471880,29962576,1418284277,21250084,1284197573,2303483940,2302764786,2336752140,16786564,2336751616,1214784588,2336489611,2303203392,1210065996,4282452107,3162706005,44068,2337014016,255861844] 334 | pmultPutConst.push([73604,1418284032,2303213604,3108512836,24,5635905,2888078475,1275068416,1076122763,51016,1275068416,2231922825,1351175378,1418414096,2232371236,220,613190472,256,2333182792,11019404,2336751616,76105746,2223720650,65572,4010763776,4010763968,277563593,2199667339,1223819712,2311072271,1116412994,256438808,267569194,1712343641,264318735,65159,608471808,264275260,47749,3071230976,3224454423,4294763497,2035711,2215638661,4294966546,258392113,17439,1090603149,1208554637,3071264905,963007252,745885460,678874681,1976730982,3352181219,3941444,251658240,4294763908,3221307903,1009009863,1,4294759913,2035711,2215626297,4294966466,1959953766,3133179360,1,1103250447,1911144449,2432696316,3909257544,4294967093,273189704,609519948,1149847624,4282466340,2303461461,1442791921,608471816,1418414140,2337030180,2236097620,1384729792,1183059728,3103784959,1,3099885896,1526726656,1096638302,1096630620,3277799774,2089009201,252083236,4294801543,3071230463,2302764551,112642,3219718144,1224736765,2395275,1275068417,4282509961,2336757845,16786572,2303197184,4276349185,3224502271,347541313,2302764615,2202550804,960561600,3924654020,4294966764,1153941553,80932,21037056,4227131840,96010239,3909091328,4294966538,1208,4244695296,112787455,3909091328,4294966518,440,4243384576,62455807,3909091328,4294966498,696,4242073856,2425421823,2425393296]*) 335 | pmultPutNoDel := [1447122753,1413567809,1398167381,2565636424,1140850688,2397323,1224736769,2303249801,2223590614,61476,3481881856,608487240,1080,3531949312,3224444020,4202255,2022556297,2202101249,2298500924,32601592,1149847744,2303539236,1308133884,2202140297,3511226340,3707193836,132416321,1157380417,837240591,3760801005,610568516,608471388,149455720,2198071489,1149829568,3770770468,608471299,4282879340,2313169220,1147151428,21553289,1149847744,21788708,1149847800,2370400292,2303201351,1213211716,2284094605,1207959552,1076118665,612666696,140,608471368,1223199048,2303246337,2483243202,61476,981689856,830738176,1140850691,2395275,1157627905,2232404357,256,103058765,1015234918,2215575588,816,609519944,309552,385810432,608996168,3347663160,2336757503,1211114580,3071263625,1725051138,822577473,2302764736,255918663,1713636535,1711428489,2336818057,2336751685,2202543180,2337014213,1279272012,2336553609,2303203392,1210065996,1459554443,616334096,140,3297331457,37913615,414777344,4278190080,2223719446,35876,13060096,0,142117196,274237768,264275269,134021,1435191552,613190400,136,1209174856,1237976201,1711297931,1723920143,2345266959,3229817922,256438785,1116323882,407014172,705644786,1494217416,258347082,2249179439,4294967021,1290963272,1459612041,1166625048,4275824896,258408447,17439,609519944,309552,385810432,608996168,3347663160,2336757503,1211114580,3375481737,3071278981,2302764546,1097204303,2215577481,4294967062,610024264,1133332560,3264417552,264649033,3255353491] 336 | pmultPutNoDel.push([28476431,4286775296,2844135180,2332033025,2237408332,2105806793,1090519041,2198255375,2305163769,4253290243,1090519041,38188815,1711470979,251806601,134020,3071230208,4186113094,1133078019,3917745924,1090519041,105297679,1711602051,252068745,108420,3071230208,4186114118,1133078021,2307133192,1090519041,172406543,1711798659,252330889,103301,3071230208,2305166406,129502275,2197815296,106964092,2336767606,1282942028,1881427083,2370622001,3375434500,1863270758,3246592260,286212353,2202537988,1278939330,3899810852,1814318219,1278855169,2215602212,4294966830,4202255,3229860489,3071230209,3342423564,1393330534,4262757903,3263823871,213323585,210331222,22056275,2249185081,4294966782,213323585,210331222,38833491,2249185081,4294966762,213323585,210331222,55610707,2249185081,4294966742,213323585,210331222,72387923,2249185081,4294966722,213323585,96502614,2305214265,2249151244,4294966702,347541313,344548934,4255181123,258408447,17439,604277065,4294835945,2149519359,0,273189704,1275614975,1459616137,1552501000,4276686884,1728053244,8658703,0,2089009201,252076068,4294899079,3071230463,59336198,440,4281919744,2422669311,255967281,1715868855,1212355721,956416131,3924785095,4294966578,8658703,0,440,3296806912,152,1566531163,1564564545,1598119489,2149519299,0,3790323761,1464,4270713088,2422669311,1208,4269926656,258408447,17439,1720,4268878080,258408447,17439,440,4267829504,258408447,17439,952,4266780928,258408447,17439,696,4265732352,2425421823,2425393296]*) 337 | pforEachVal := [1447122753,1413567809,1398167381,1491895112,948126054,3481880832,613714248,168,1288079692,3089403017,251658240,110468,2379952384,2204500291,1207977532,2370356105,4017422380,1158122313,826663985,407407606,2215627141,144,616335692,160,1290242373,2686755979,1140850688,2337075849,1015891968,213,2089371648,2336831524,2236141628,1163425023,258403633,17439,2336807813,812912727,1711453967,812975673,3375480881,778443755,8658703,0,1152847684,2202534402,1147536064,1963328571,29459215,3900037433,708608870,2419028992,1212123976,3094740869,604277577,1092110475,1090635395,2205339193,440,3296937984,1600019288,1096565085,1096696157,2336801631,13116548,2202075136,2336752071,2336491599,12592268,2302935040,1159734388,2303260809,4280820804,12067988,4169334784,2206470143,2113929216,1958774037,33063860,4283335951,2303328255,1066092797,4169370091,113406,2232352768,4294967096,2298973000,1212949588,1208504203,1076118665,612666184,168,1208504575,2820965515,1207959552,4279259019,2336753744,11019396,2303197184,139526137,1223525709,1076118667,1277449355,2303270004,2336817221,1770202124,3531931932,2303207541,4280150471,3526492159,2336857835,2336760844,1211638908,2303199627,2336831748,1770202124,3531931932,4273526900,3925868543,4294967053,3677482289,4294859753,2425393407,2425393296] 338 | pclone := [1447122753,1413567809,1398167381,1491895112,1208060744,2686749833,1224736768,267573129,1276139536,2332573835,1082857544,608471328,311117856,542637889,1220576584,2303248009,255337540,339844,2223720448,40996,9127936,2333624459,3380943952,253515401,330628,608487168,76,4270411008,1277449355,1291881292,1221602443,13972621,1207959552,807695497,267224397,259204,1620224,826605568,385827327,139823945,3955525961,4287185155,1106807108,1711374221,4340867,2336878453,3677425749,2422605035,3632919433,1711371149,4340867,210629237,385827135,1211501709,4282500489,268403990,110468,1435191552,1250773000,3443083280,273517896,3230863169,264911176,138527123,3380875208,2197815299,2249133311,960,1104316745,1225777795,4148816593,3800252890,4198056199,3611758404,2235943217,259552466,2202077879,2305163770,2215575629,1062,38450959,49972033,38635878,67798031,3071213568,2202076234,2305164282,2215576653,1006,105559823,83526465,105744742,64128015,3071213568,2202077258,2305164794,2215577677,910,172668687,133858113,172853606,57836815,3071213568,2305166410,129567821,1090519040,692452233,3515434455,1171466565,1157120909,1143233673,65585473,29393729,117408577,3306982726,0,610044228,1295742536,826657025,3677439442,171740494,1726546249,74387267,3280158999,286212865,2202603780,960827586,1156084419,1210342539,1155072324,1143233593,8553487,2302738432,3071231688,1181106700,4541577,21073220,1992767812,3071231595,1181106700,4541577,37850436,1992767812,3071231575,1181106700,4541577,54627652,1992767812,3071231555,1181106700,4541577,71404868,1992767812,3071231535,1181106700,4541577,88182084,1992767812,3071231515,3246604812,1724856582,1162643782,252278272,1716130999,5067913,2215638661,400,274041673,273190216,1221212488,1091586701,1220580111,2467285049,3355984321,32670735,4269998080,3917877004,1224736769,2202129033,3511226338,3673639402,132285249,1156725057,836126479,3531949513,3071244148,4202905866,143222273,38306831,3071213568,2202075722,2305164026,2215576136,556,72005391,66749249,71862630,34636815,3071213568,2202076746,2305164538,2215577160,500,139114255,100303681,138971494,29656079,3071213568,2202077770,2305165306,2232355400,424,206223119,206080358,1977,1157073152,2303054633,3609806033,4165438788,65585473,29393729,1174862723,12926093,1979711488] 339 | pclone.push([3372305712,1171403077,2370493233,21563932,256009921,1091765359,1124189059,285479183,281183049,1925396805,4177609960,1962883393,3364438395,213323590,2303092290,2370060300,960758081,1181054662,1108129551,210323046,1099777088,3325641730,256266870,1715604663,1074563398,54627652,1992702276,3071231551,1181106700,1145048201,1141129613,745981497,213323590,2303092290,2370060300,960759105,1176073926,1108129551,956744067,2303092430,141967372,1242871567,1209305446,611617608,1149847864,2336755748,1227891780,2360519,1224736768,136604809,7179085,1208353608,2236092555,3909907922,148,4202255,1220708680,2236088971,1291154880,2236424841,444927981,1224736764,2686747787,1207959552,1217069195,608469784,1955266892,3459861540,4225401359,2336817151,1211638852,1532544131,1096638302,1096630620,3277799774,4202255,256166193,1716126903,1208256836,29459272,4000828985,4294927337,2149519359,0,256166193,1716126903,1296337220,3246606336,2010069249,4255836653,258408447,17439,3911223628,4294967158,1721,4267436288,96075775,3909091328,4294966865,1721,4237420800,96075775,3909091328,4294966407,1209,4264814848,62521343,3909091328,4294966825,697,4263504128,28966911,3909091328,4294966805,1209,4233488640,62521343,3909091328,4294966347,697,4232177920,28966911,3909091328,4294966327,3924855112,4294967075,485081137,2432696319]*) 340 | paddNullDel := [1447122753,1413567809,1398167381,2028766024,1154320717,3760491659,1207959552,3223620745,1207959552,3357840521,1291845632,2235942025,3951300553,1207959553,1747207309,3352791368,3155012,1157627904,826668593,1149847807,2370326564,1215046724,1478771849,4202255,838371652,2202101449,1962951740,30337287,3246981120,1174487437,1714947213,1144816451,3263777792,3230002293,28476431,21495808,40996288,608471368,4035527744,2088976742,2298478661,2369528948,2215589388,448,49011505,1133364105,210585089,2202232368,19836,1976076621,264275435,106372,46367488,2378170696,2303204140,1145578564,941900937,874796169,1418401791,2336502820,1211638852,2303248009,4169745601,4202255,2210498881,2202534336,256312001,1716260023,4266232132,3900035129,608471880,1149846592,826618916,3918088384,76104806,1142423302,874792075,1220905288,2302984841,2035696,3229860233,3263383553,3071230210,1711295820,1157515913,3900031033,608471880,1103704392,2336808449,1146627164,1009024003,1290963272,1344556171,88901990,2223720448,49188,9127936,406883140,610044232,143345696,2198886399,23864444,264472904,65412,1620224,402587648,1814320267,51016,1207959552,1208512649,2232445065,3448049618,1207959552,3223630987,2332033024,1214784588,2336757387,76105746,4035528906,1712360264,1723920143,2345266959,3229817922,256438785,1116323882,407014172,705644786,1494217416,258347082,2265956655,180,807683203,608471809,612645168,224,4265510159,28901375,1207959552,1534641283,1096638302,1096630620,3277799774,8658703,0,1223723332,1076118727,2,1209,2202101248,17788,1009009863,2,22515009,4266034447,258408447,17439,608487240,584,310528,45809664,1157627904,3909174925,4294966867,4202255,1208191304,3223618699,3909091328,4294967100,273189704,1208506367,1476391305,1804158984,4283885840,778502143,8658703,0,1224378696,3223620747,4278190080,2336757847,12592308,2303197184,4281264390,2425421823] 341 | pcopyFromHT := [686588744,608471880,3364440408,1221691721,2336753803,1358891088,112656,2202533888,2428709060,2425393296,2425393296,2425393296] 342 | pgetFromHash := [2336805513,2236141828,1095201984,1946286211,9128001,1958774088,4169351479,3123803649,1,778441451,8658703,0,1958885700,3364440078,2198375240,2236088770,1106081225,12243001,1207959552,3284288783,3287531569,2425393296,2425393296,2425393296] 343 | pnext := [1398167381,686588744,1208060744,1384896137,3481880828,1287883084,1346096521,3944378904,4232300339,1,2382120587,2336751952,4233529607,1981304889,1133200411,143345916,2236143103,2212132032,1208089667,1529398403,3277676382,2202583089,1583032516,2428722527] 344 | } 345 | for j, raw in [pnewTable,pdestroy,prehash,remove,pput,pget,pfindKey,ptraverse,pfindVal,pmultPut,pmultPutConst,pmultPutNoDel,pforEachVal,pclone,paddNullDel,pcopyFromHT,pgetFromHash,pnext] ; The order matters. 346 | hashTable[j]:=hashTable.rawPut(raw) 347 | hashTable.init:=true 348 | return 349 | } 350 | initTable(clone:=0){ 351 | this.table:=this.globalAlloc(A_PtrSize) 352 | NumPut(clone ? clone : this.newTable(this.size), this.table+0, 0, "Ptr") 353 | return 354 | } 355 | initBoundFuncs(){ 356 | ; pnewTable (01) (internal use) 357 | ; pdestroy (02) (use destory()) 358 | ; prehash (03) (use rehash()) 359 | ; remove (04) (use remove(key)) 360 | ; pput (05) (use myHashTable[key]:=value) 361 | ; pget (06) (use value := myHashTable[key]) 362 | ; pfindKey (07) (use HasKey()) 363 | ; ptraverse (08) (use forEach(fn)) 364 | ; pfindVal (09) (use hasVal() or valGetKey(value)) 365 | ; pmultPut (10) (use splitAdd()) 366 | ; pmultPutCV (11) (use splitAdd()) 367 | ; pmultPutND (12) (use splitAdd()) 368 | ; forEachVal (13) (use forEachVal()) 369 | ; clone (14) (use clone()) 370 | ; addNullDel (15) (use addFromFile()) 371 | ; copyFromHT (16) (use copyFromHashTable()) 372 | ; getFromHash (17) (enum) 373 | ; next (18) (enum) 374 | ; 375 | this[2] := func("dllCall").bind(hashTable[2], "Ptr", this.table, "Ptr", hashTable.fnLib, "Cdecl") ; destroy 376 | this[3] := func("dllCall").bind(hashTable[3], "Ptr", this.table, "Ptr", hashTable.fnLib, "Cdecl Ptr") ; rehash 377 | this[4] := func("dllCall").bind(hashTable[4], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; , key, "Cdecl") ; remove 378 | this[5] := func("dllCall").bind(hashTable[5], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; , key, "wstr", val, "Cdecl") ; put 379 | this[6] := func("dllCall").bind(hashTable[6], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; , key, "Cdecl str") ; get 380 | ; 7 381 | this[8] := func("dllCall").bind(hashTable[8], "Ptr", this.table, "Ptr", hashTable.fnLib, "ptr") ; this.icbfn/udfn, "uint", cbid,"ptr",uParams, "Cdecl") ; traverse 382 | this[9] := func("dllCall").bind(hashTable[9], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; val, "Cdecl ptr") ; findVal 383 | this[10] := func("dllCall").bind(hashTable[10], "Ptr", this.table, "Ptr", hashTable.fnLib) ; "wstr", keys, "wstr", vals, "wstr", del,"Cdecl") ; multPut 384 | this[11] := func("dllCall").bind(hashTable[11], "Ptr", this.table, "Ptr", hashTable.fnLib) ; "wstr", keys, "wstr", vals, "wstr", del,"Cdecl") ; multPutConstVal 385 | this[12] := func("dllCall").bind(hashTable[12], "Ptr", this.table, "Ptr", hashTable.fnLib) ; "wstr", keys, "wstr", vals, "int", constVal, "Cdecl") ; multPutNoDel 386 | this[13] := func("dllCall").bind(hashTable[13], "Ptr", this.table, "Ptr", hashTable.fnLib, "wstr") ; val, "ptr", this.icbfn/udfn, "uint", cbid,"ptr",uParams, "Cdecl") ; forEachVal 387 | this[14] := func("dllCall").bind(hashTable[14], "Ptr", this.table, "Ptr", hashTable.fnLib, "Cdecl Ptr") ; clone 388 | this[15] := func("dllCall").bind(hashTable[15], "Ptr", this.table, "Ptr", hashTable.fnLib, "ptr") ; keys, "ptr", vals, "uint", nKeys, "Cdecl") ; addNullDel 389 | ; 16 390 | ; 17 391 | this[18] := func("dllCall").bind(hashTable[18], "ptr") 392 | 393 | return 394 | } 395 | newTable(sz){ ; Called by initTable() 396 | static pmalloc:=DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "malloc", "Ptr") 397 | return DllCall(hashTable[1], "Uint", sz, "Ptr", pmalloc, "Ptr", hashTable.tableSizes, "double", this.maxLoad, "Uint", this.nextSize, "Cdecl ptr") 398 | } 399 | 400 | ; Growing list of array sizes 401 | ; Each size is approximately double the previous size. 402 | ; All sizes are prime 403 | ; maketableSizesArray() relies on this array being assigned above it. 404 | static arraySizes:= [2 405 | ,5 406 | ,11 407 | ,23 408 | ,53 409 | ,113 410 | ,251 411 | ,509 412 | ,1019 413 | ,2039 414 | ,4079 415 | ,8179 416 | ,16369 417 | ,32749 418 | ,65521 419 | ,131063 420 | ,262133 421 | ,524269 422 | ,1048571 423 | ,2097143 424 | ,4194287 425 | ,8388587 426 | ,16777183 427 | ,33554393 428 | ,67108837 ; tested, 500 mb empty. 350 ms. 429 | ,134217689 430 | ,268435399 431 | ,536870879 432 | ,1073741789 433 | ,2147483629 434 | ,4294967291] 435 | maketableSizesArray(){ 436 | static init := hashTable.maketableSizesArray() 437 | local tableSizes, k, sz 438 | tableSizes := hashTable.globalAlloc(this.arraySizes.length()*4) 439 | for k, sz in hashTable.arraySizes 440 | NumPut(sz, tableSizes+0,(k-1)*4, "int") 441 | hashTable.tableSizes:=tableSizes 442 | return 443 | } 444 | makeFnLib(){ 445 | ; See hash.h 446 | /* 447 | typedef struct functionLib { 448 | _malloc pmalloc; 449 | _free pfree; 450 | findKey pfindKey; 451 | _rehash prehash; 452 | _newHashTable pnewHashTable; 453 | //mb pmb; // db 454 | } fnLib, *pfnLib; 455 | */ 456 | 457 | local fnLib := hashTable.globalAlloc(5*A_PtrSize) ; Set to 6*A_PtrSize when using db. Can be freed via freeFnLib() (you shouldn't) 458 | local pmalloc:=DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "malloc", "Ptr") 459 | local pfree:=DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "free", "Ptr") 460 | NumPut(pmalloc, fnLib+0, A_PtrSize*0, "Ptr") 461 | NumPut(pfree, fnLib+0, A_PtrSize*1, "Ptr") 462 | NumPut(hashTable[7], fnLib+0, A_PtrSize*2, "Ptr") 463 | NumPut(hashTable[3], fnLib+0, A_PtrSize*3, "Ptr") 464 | NumPut(hashTable[1], fnLib+0, A_PtrSize*4, "Ptr") 465 | ;NumPut(registercallback("mb","Cdecl"), fnLib+0, A_PtrSize*5, "Ptr") ; db 466 | hashTable.fnLib:=fnLib 467 | return 468 | } 469 | initSize(target:=0){ 470 | ; Picks the closest available size greater or equal to target. 471 | local k, sz 472 | for k, sz in hashTable.arraySizes { 473 | if (sz >= target) { 474 | this.size:=sz 475 | this.nextSize:=k 476 | return this.size 477 | } 478 | } 479 | ; this should be rare. Allocating max size might not even succeed. Not tested. 480 | ; Indicies in c source are unsigned int, hence max index is 2**32 (4294967296). 481 | throw Exception("The requested size (" target ") is to large. Maximum size is: " hashTable.arraySizes[hashTable.arraySizes.length()] ".",-1) 482 | return 483 | } 484 | rawPut(raw){ ; Called by initBin, for writing binary code to memory. 485 | ; Url: 486 | ; - https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx (VirtualAlloc function) 487 | ; - https://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx (Memory Protection Constants) 488 | local k, i, bin 489 | static flProtect:=0x40, flAllocationType:=0x1000 ; PAGE_EXECUTE_READWRITE ; MEM_COMMIT 490 | 491 | bin:=DllCall("Kernel32.dll\VirtualAlloc", "Uptr",0, "Ptr", raw.length()*4, "Uint", flAllocationType, "Uint", flProtect, "Ptr") 492 | for k, i in raw 493 | NumPut(i,bin+(k-1)*4,"Int") 494 | return bin 495 | } 496 | ; For forEach/Val 497 | calloutFunctions:=[] 498 | traversecalloutRouter(val,ind,cbid,hash,uParams){ 499 | ; Note: this = key. the function is only called via registercallback address. see icbfn. 500 | ; typedef int __cdecl (*calloutFn)(unsigned short*,unsigned short*,unsigned int,unsigned int,unsigned int,void*); 501 | ; traversecalloutRouter(key,val,ind,cbid,hash,uParams) 502 | return object(A_EventInfo).calloutFunctions[cbid].call(StrGet(this,"utf-16"), StrGet(val,"utf-16"), ind, hash, uParams) 503 | } 504 | setUpcalloutFunctions(udfn,byref cbfn, byref cbid){ ; Used in forEach/Val 505 | if udfn is Integer 506 | cbfn:=udfn 507 | else 508 | cbfn:=this.icbfn 509 | if isFunc(udfn) && !isObject(udfn) 510 | udfn:=func(udfn) 511 | cbid:=this.calloutFunctions.push(udfn) 512 | return 513 | } 514 | ; Memory functions 515 | freeAllBins(){ 516 | ; Probably never wanted. 517 | loop 18 518 | hashTable.globalFree(hashTable[A_Index]) 519 | return 520 | } 521 | freeFnLib(){ 522 | ; Probably never wanted. 523 | this.globalFree(hashTable.fnLib) 524 | return 525 | } 526 | globalAlloc(dwBytes){ 527 | ; URL: 528 | ; - https://msdn.microsoft.com/en-us/library/windows/desktop/aa366574(v=vs.85).aspx (GlobalAlloc function) 529 | ;static GMEM_ZEROINIT:=0x0040 ; Zero fill memory 530 | ;static uFlags:=GMEM_ZEROINIT ; For clarity. 531 | local hMem 532 | if !(hMem:=DllCall("Kernel32.dll\GlobalAlloc", "Uint", 0x0040, "Ptr", dwBytes, "Ptr")) 533 | throw exception("GlobalAlloc failed for dwBytes: " dwBytes, -2) 534 | return hMem 535 | } 536 | globalFree(hMem){ 537 | ; URL: 538 | ; - https://msdn.microsoft.com/en-us/library/windows/desktop/aa366579(v=vs.85).aspx (GlobalFree function) 539 | local h 540 | if h:=DllCall("Kernel32.dll\GlobalFree", "Ptr", hMem, "Ptr") 541 | throw exception("GlobalFree failed at hMem: " hMem, -2) 542 | return h 543 | } 544 | free(buf){ 545 | return DllCall("MSVCRT.dll\free", "Ptr", buf, "Cdecl") 546 | } 547 | ;; Destructor 548 | wasFreed:=false 549 | destroy(){ ; This is automatically called when the last reference to the table is released, eg, myHashTable:="" 550 | if !this.wasFreed && this._isPersistent 551 | this.toFile(this.path) 552 | if this.wasFreed 553 | return 554 | this.wasFreed:=true 555 | this[2].call() ; pdestroy 556 | this.globalFree(this.table) 557 | this.globalFree(this.icbfn) 558 | } 559 | ; Internal tree/print methods. 560 | ; Not for v1: 561 | /* 562 | buildTree(tv,parents,key,val,i,h,uParams){ 563 | local id 564 | if !parents.haskey(h) { 565 | id:=tv.add(h) 566 | parents[h]:=id 567 | } 568 | id:=tv.add(key,parents[h]) 569 | tv.add(val,id) 570 | return 1 571 | } 572 | */ 573 | checkIfNeedRehash(n){ 574 | ; Make one rehash if it will be needed, to avoid multiple rehashes. 575 | if this.count()+n > this.getMaxload() * this.length() 576 | this.rehash((this.count()+n) / this.getMaxload()) 577 | } 578 | _toString(del1,del2,what,toBuf:=false){ 579 | ; This is also for writing to buffer, 580 | /* 581 | typedef struct toStringParams { 582 | unsigned short* buf; // string buffer. 583 | unsigned short* del1; // key val delimiter 584 | unsigned short* del2; // pair delimiter 585 | realloc prealloc; // realloc fn 586 | memcpy pmemcpy; // memccpy fn 587 | unsigned int len; // buffer length 588 | unsigned int o; // buffer offset 589 | unsigned int dellen1; // delimiter 1 length 590 | unsigned int dellen2; // delimiter 2 length 591 | int what; // what to get, 0 indicates both key and val, 1, only key, 2, only val. 592 | } *pparams; 593 | */ 594 | static prealloc := DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "realloc", "Ptr") 595 | static pmemcpy := DllCall("Kernel32.dll\GetProcAddress", "Ptr", DllCall("Kernel32.dll\GetModuleHandle", "Str", "MSVCRT.dll", "Ptr"), "AStr", "memcpy", "Ptr") 596 | 597 | static bin 598 | local dellen1, dellen2 599 | if toBuf { ; Use '\0' as delimiter for buffer write 600 | varSetCapacity(del1,2,0) 601 | varSetCapacity(del2,2,0) 602 | dellen1 := what == 1 ? 1 : 0 603 | dellen2 := what == 2 ? 1 : 0 604 | } else { ; Use string as delimiter. 605 | dellen1:= what <= 1 ? strlen(del1) : 0 606 | dellen2:= what == 1 ? 0 : strlen(del2) 607 | } 608 | local uParams ; params to be passed to the calloutFunction, see forEach. 609 | varSetCapacity(uParams,5*A_PtrSize+24,0) 610 | ; buf 611 | numput(&del1, uParams, A_PtrSize*1, "Ptr") ; del1 612 | numput(&del2, uParams, A_PtrSize*2, "Ptr") ; del2 613 | numput(prealloc, uParams, A_PtrSize*3, "Ptr") ; prealloc 614 | numput(pmemcpy, uParams, A_PtrSize*4, "Ptr") ; pmemcpy 615 | ; len 616 | ; o 617 | numput(dellen1, uParams, A_PtrSize*5+8, "uint") ; dellen1 618 | numput(dellen2, uParams, A_PtrSize*5+12,"uint") ; dellen2 619 | numput(what, uParams, A_PtrSize*5+16, "int") ; what 620 | if !bin ; note, using "this" here because needs to be able to access rawPut if hashTable has been deleted, typically after exitApp() 621 | bin := this.rawPut(A_PtrSize == 4 ? [3526448981,3968029526,611617580,612141908,608996164,608602944,2298607747,252978244,36750,2311074048,666668534,0,747488137,21007616,1199342438,4034199806,405040265,2333625995,3355515974,18892291,1003487704,2198803526,132,337935491,252087041,44942,609520384,1208257816,69500041,2300839049,4278723668,1577259094,541494040,1586085889,608471320,138840840,69485705,76351115,604277080,2333103871,1174478918,112664,3296919552,1600019244,3263808349,1711358605,4265704579,2213770496,18097276,4284187919,1153957887,6180,3677421568,4294929385,649367039,0,3238005901,1418265312,1317608484,608471316,2298907396,1459561476,1958774028,609127288,1418397321,1284054052,2088965156,2332103716,2400131150,4294967121,2299669645,2333353044,2369791060,1820936196,1418266660,76088356,274136868,2333886091,51651668,3221297238,2300073609,2332566596,1149830214,109773860,2303722637,1459561476,474909456,52709003,4169341006,407800065,4282156047,109838335,4294898921,3921687039,4294967086,2425393296] 622 | : [1465209921,2202555222,2336760044,829957236,3431549439,2346027336,4186126414,829718017,2298670043,2379778515,2204500307,17788,1452011893,809929516,1174654977,30933300,675691512,4186139251,109791233,8949263,2370043904,2370312964,2303217676,542572522,53757579,2336762974,2370048086,2336751620,744392966,1477217608,2334152447,1174484038,112684,2202533888,1583030468,1547787615,2312604099,22515192,1015234918,4050976836,251787651,4294932101,3957010943,2035589,1207964813,1451822731,2232716584,0,1209554687,1484046469,1211649675,1451951753,33129260,4286091023,2370109439,2370322180,2303479820,542572514,53495435,2336763006,2370046038,2336751620,746490118,2014088520,2334152447,1183526998,743834424,2298607747,2215586902,4294967150,3909520200,4294967090,1609154609,2432696319,2425393296,2425393296]) 623 | ; bin is toString.c 624 | local r := this.forEach(bin, &uParams) ; For loop. 625 | 626 | local buf:=numget(&uParams,"ptr") 627 | local o:=numget(&uParams,A_PtrSize*5+4,"uint") ; the offset 628 | if (r && toBuf) ; Caller frees buf. 629 | return {buf:buf, bytes:o*2} ; the offset is at the end of the buffer, the buffer is of type short, hence multiply by 2 to get bytes. Now keeps the trailing '\0', it is probably safest because addNullDel searches for '\0' which is not guaranteed to exist at the end of the buffer unless put there. 630 | 631 | local str ; return 632 | if (r && o) 633 | str := strGet(buf,o - (what == 1 ? dellen1 : dellen2)) ; Removes the trailing delimiter 634 | if buf 635 | this.free(buf) 636 | return str 637 | } 638 | _newEnum(){ 639 | return new hashTable.enum(this) 640 | } 641 | class enum { 642 | ; Making this ugly improves performance. (a lot) 643 | __new(r){ 644 | this[1]:=r ; reference 645 | this[2]:=1 ; get n:th node in bucket hash 646 | this[3]:=0 ; "bucket" 647 | } 648 | next(byref k, byref v:=""){ 649 | static hash, n 650 | static dummy := varSetCapacity(hash, 4) + varSetCapacity(n, 4) 651 | static phash := &hash 652 | static pn := &n 653 | static ps := a_ptrsize 654 | static ps2 := a_ptrsize*2 655 | static ps2_8 := ps2+8 656 | local node 657 | return (node := dllcall(hashTable[18] 658 | , "ptr", this[1].table ; tableData** table 659 | , "ptr", numput(this[3], hash, "uint") ; uint* hash note: numput returns the "wrong" address, compiled code does hash-=1 (uint) 660 | , "ptr", numput(this[2], n, "uint") ; uint* n note: as above for n-=1 661 | , "ptr", hashTable[17] ; pgetFromHash 662 | , "cdecl ptr")) ; if node!=0, return true and set key and val 663 | ? (k := strget(numget(node+ps, "ptr"),"UTF-16") ; set key 664 | , (isbyref(v)? v := strget(numget(node+ps2, "ptr"),"UTF-16"):"") ; set val 665 | , this[3] := numget(phash+0, "uint") ; update this.hash (this[3]) 666 | , this[2] := numget(pn+0, "uint") ; update this.n (this[2]) 667 | , 1) ; return true 668 | : 0 ; else return false 669 | } 670 | } 671 | } -------------------------------------------------------------------------------- /wikiImages/hash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelgeffegleH/hashTable/1b859320d744bfa765d57c2c092f8eacc62cac31/wikiImages/hash.png --------------------------------------------------------------------------------