1 module lincount;
2 
3 struct LPCounter
4 {
5 	import std.bitmanip: BitArray;
6 	import std.uuid: UUID;
7 
8 	private BitArray map;
9 	private size_t _length = 0;
10 
11 	@disable this();
12 
13 	private void set(size_t index)
14 	{
15 		if(map[index] == false)
16 		{
17 			map[index] = true;
18 			_length++;
19 		}
20 	}
21 
22 	this(size_t kilobytes)
23 	{
24 		map.length = 8 * 1024 * kilobytes;
25 		_length = 0;
26 	}
27 
28 	void put(uint data)
29 	{
30 		import lincount.internal: fmix;
31 		set(cast(size_t)(fmix(data) % map.length));
32 	}
33 
34 	void put(ulong data)
35 	{
36 		import lincount.internal: fmix;
37 		set(cast(size_t)(fmix(data) % map.length));
38 	}
39 
40 	void put(UUID data)
41 	{
42 		set(data.toHash % map.length);
43 	}
44 
45 	void put(in void[] data)
46 	{
47 		//hashOf(data);
48 		import std.digest.digest: digest;
49 		import lincount.internal: MurmurHash3_x64_128;
50 		auto hashed = cast(ulong[2])digest!MurmurHash3_x64_128(data);
51 		set((hashed[0] ^ hashed[1]) % map.length);
52 	}
53 
54 	ulong count()
55 	{
56 		import std.math: log, lround;
57 		if(map.length > _length)
58 			return lround(map.length * -log(real(map.length - _length) / map.length));
59 		else
60 			return map.length;
61 	}
62 
63 	//returns the size of the underlying BitArray in KB
64 	@property size_t size()
65 	{
66 		return map.length() / (8 * 1024);
67 	}
68 
69 }