Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ from attractivechaos' generic C approach: https://github.com/attractivechaos/kli

## Fast

Comparison with emsi_containers HashMap:
Comparison with [emsi containers](https://github.com/dlang-community/containers) HashMap:

Time, in msec, for n=500,000 operations benchmarked on linux VM; ldc2 -release

Expand All @@ -15,9 +15,50 @@ Time, in msec, for n=500,000 operations benchmarked on linux VM; ldc2 -release
| Retrieve (Serial) | 145 | 26 |
| Retrieve (Random) | 282 | 84 |


## Notes
Key type may be numeric, C style string, D style string.
If numeric, must be unsigned
If numeric, must be unsigned.

May be used as a hash map (default) or a hash set. To use as a hash set,
pass optional third template parameter `kh_is_map = false`.

By default, memory allocated by the hashmap will be scanned by the GC.
(pass optional fourth template parameter `useGC = false` to disable)

Can undergo static initialization (e.g. define as struct member
with no extra init code needed in struct ctor), unlike
[emsi containers](https://github.com/dlang-community/containers) HashMap.


## API

### Declaration
```D
auto map = khash!(keytype, valuetype);
```

### Assignment / Insert
```D
map["monty"] = "python";
```

### Retrieval
```D
auto val = map[key];
```

### Retrieve or Create
```D
auto val = map.require("fruit", "apple");
```

### Iteration
```D
foreach(x; map.byKey) {
...
}
```

## Examples

Expand Down Expand Up @@ -54,3 +95,9 @@ assert( kh_valstring[42] == "Adams" );
const auto fw = kh_string.require("flammenwerfer", 21);
assert(fw == 21);
```

## BUGS

Please let me know what you find.
There may be a double free bug when making a hashmap of hashmaps.

6 changes: 5 additions & 1 deletion dub.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@
"license": "MIT",
"dependencies": {
},
"excludedSourceFiles": ["source/dklib/benchmark_khash.d"]
"buildTypes": {
"unittest-inline": {
"buildOptions": ["unittests", "optimize", "inline"]
}
}
}
2 changes: 2 additions & 0 deletions dub.selections.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"fileVersion": 1,
"versions": {
"emsi_containers": "0.7.0",
"stdx-allocator": "2.77.5"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
dependency "emsi_containers" version="~>0.7"
dependency "dklib" path="../.."
+/
import khash;
import dklib.khash;
import dklib.khashl;
import containers;

import std.datetime.stopwatch : StopWatch, AutoStart;
Expand All @@ -17,9 +18,14 @@ int main()

enum NUMBER_OF_ITEMS = 500_000;

void testContainerInsert(alias Container, string ContainerName)()
void testContainerInsert(alias Container, string ContainerName, bool cached = false)()
{
auto c = Container!(string, int)();
static if(cached){
static assert(ContainerName == "khashl (cached)");
auto c = Container!(string, int,true,true,true)();
}else{
auto c = Container!(string, int)();
}

StopWatch sw = StopWatch(AutoStart.yes);
foreach (i; 0 .. NUMBER_OF_ITEMS)
Expand Down Expand Up @@ -61,9 +67,12 @@ int main()

testContainerInsert!(HashMap, "HashMap");
testContainerInsert!(khash, "khash");
testContainerInsert!(khashl, "khashl");
testContainerInsert!(khashl, "khashl (cached)",true);

testContainerLookup!(HashMap, "HashMap");
testContainerLookup!(khash, "khash");
testContainerLookup!(khashl, "khashl");

return 0;
}
39 changes: 21 additions & 18 deletions source/dklib/khash.d
Original file line number Diff line number Diff line change
Expand Up @@ -471,13 +471,6 @@ pragma(inline, true)
return cast(khint32_t) ((key)>>33^(key)^(key)<<11);
}

khint_t __ac_X31_hash_string(const(char)* s)
{
khint_t h = cast(khint_t)*s;
if (h) for (++s; *s; ++s) h = (h << 5) - h + cast(khint_t)*s;
return h;
}

auto kh_hash_func(T)(T* key)
if(is(T == char) || is(T == const(char)) || is(T == immutable(char)))
{
Expand All @@ -490,17 +483,6 @@ pragma(inline, true)
return (strcmp(a, b) == 0);
}

auto kh_hash_func(T)(T key)
if(isSomeString!T)
{
// rewrite __ac_X31_hash_string for D string/smart array
if (key.length == 0) return 0;
khint_t h = key[0];
for (int i=1; i<key.length; ++i)
h = (h << 5) - h + cast(khint_t) key[i];
return h;
}

bool kh_hash_equal(T)(T a, T b)
if(isSomeString!T)
{
Expand All @@ -523,6 +505,27 @@ pragma(inline, true)
alias kh_int_hash_func2 = __ac_Wang_hash;

} // end pragma(inline, true)

khint_t __ac_X31_hash_string(const(char)* s)
{
version (DigitalMars) {} else pragma(inline, true);
khint_t h = cast(khint_t)*s;
if (h) for (++s; *s; ++s) h = (h << 5) - h + cast(khint_t)*s;
return h;
}

auto kh_hash_func(T)(T key)
if(isSomeString!T)
{
// rewrite __ac_X31_hash_string for D string/smart array
version (DigitalMars) {} else pragma(inline, true);
if (key.length == 0) return 0;
khint_t h = key[0];
for (int i=1; i<key.length; ++i)
h = (h << 5) - h + cast(khint_t) key[i];
return h;
}

} // end template kh_hash

/* --- END OF HASH FUNCTIONS --- */
Expand Down
Loading