Simple dense bitmap index in Go with binary operators

kelindar/bitmap
Go Version PkgGoDev Go Report Card License Coverage

Zero-Allocation, SIMD Bitmap Index (Bitset) in Go

This package contains a bitmap index which is backed by uint64 slice, easily encodable to/from a []byte without copying memory around so it can be present in both disk and memory. As opposed to something as roaring bitmaps, this is a simple implementation designed to be used for small to medium dense collections.

I've used this package to build a columnar in-memory datastore, so if you want to see how it can be used for indexing, have a look at kelindar/column. I'd like to specifically point out the indexing part and how bitmaps can be used as a good alternative to B*Trees and Hash Maps.

Features

  • Zero-allocation (see benchmarks below) on almost all of the important APIs.
  • 1-2 nanosecond on single-bit operations (set/remove/contains).
  • SIMD enhanced and, and not, or and xor operations, specifically using AVX2 (256-bit).
  • Support for and, and not, or and xor which allows you to compute intersect, difference, union and symmetric difference between 2 bitmaps.
  • Support for min, max, count, and first-zero which is very useful for building free-lists using a bitmap index.
  • Reusable and can be pooled, providing clone with a destination and clear operations.
  • Can be encoded to binary without copy as well as optional stream WriteTo method.
  • Support for iteration via Range method and filtering via Filter method.

Example Usage

In its simplest form, you can use the bitmap as a bitset, set and remove bits. This is quite useful as an index (free/fill-list) for an array of data.

import "github.com/kelindar/bitmap"
bitmap := make(bitmap.Bitmap, 0, 8) // 8*64 = 512 elements pre-allocated
bitmap.Set(300)         // sets 300-th bit
bitmap.Set(400)         // sets 400-th bit
bitmap.Set(600)         // sets 600-th bit (auto-resized)
bitmap.Contains(300)    // returns true
bitmap.Contains(301)    // returns false
bitmap.Remove(400)      // clears 400-th bit

// Min, Max, Count
min, ok := bitmap.Min()  // returns 300
max, ok := bitmap.Max() // returns 600
count := bitmap.Count() // returns 2

The bits in the bitmap can also be iterated over using the Range method. It is a simple loop which iterates over and calls a callback. If the callback returns false, then the iteration is halted (similar to sync.Map).

// Iterate over the bits in the bitmap
bitmap.Range(func(x uint32) bool {
    println(x)
    return true
})

Another way of iterating is using the Filter method. It iterates similarly to Range but the callback returns a boolean value, and if it returns false then the current bit will be cleared in the underlying bitmap. You could accomplish the same using Range and Remove but Filter is significantly faster.

// Filter iterates over the bits and applies a callback
bitmap.Filter(func(x uint32) bool {
    return x % 2 == 0
})

Bitmaps are also extremely useful as they support boolean operations very efficiently. This library contains And, AndNot, Or and Xor.

// And computes the intersection between two bitmaps and stores the result in the current bitmap
a := Bitmap{0b0011}
a.And(Bitmap{0b0101})

// AndNot computes the difference between two bitmaps and stores the result in the current bitmap
a := Bitmap{0b0011}
a.AndNot(Bitmap{0b0101})

// Or computes the union between two bitmaps and stores the result in the current bitmap
a := Bitmap{0b0011}
a.Or(Bitmap{0b0101})

// Xor computes the symmetric difference between two bitmaps and stores the result in the current bitmap
a := Bitmap{0b0011}
a.Xor(Bitmap{0b0101})

Benchmarks

Benchmarks below were run on a large pre-allocated bitmap (slice of 100 pages, 6400 items).

cpu: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz
BenchmarkBitmap/set-8         	608127316     1.979 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/remove-8      	775627708     1.562 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/contains-8    	907577592     1.299 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/clear-8       	231583378     5.163 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/ones-8        	39476930      29.77 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/first-zero-8  	23612611      50.82 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/min-8         	415250632     2.916 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/max-8         	683142546     1.763 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/count-8       	33334074      34.88 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/clone-8       	100000000     11.46 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/simd-and-8    	74337927      15.47 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/simd-andnot-8 	80220294      14.92 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/simd-or-8     	81321524      14.81 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/simd-xor-8    	80181888      14.81 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/and-8         	29650201      41.68 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/andnot-8      	26496499      51.72 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/or-8          	20629934      50.83 ns/op     0 B/op    0 allocs/op
BenchmarkBitmap/xor-8         	23786632      51.46 ns/op     0 B/op    0 allocs/op
Owner
Roman Atachiants
As a hacker with a Ph.D., I'm scaling backend services for half a billion people in the Middle East.
Roman Atachiants
Comments
  • Kelindar fails under highload. 1-3/400k requests

    Kelindar fails under highload. 1-3/400k requests

    Hi, After upgrade from v1.1.4 to v1.2.1 I got errors under highload tests

    Test Case:

    git clone https://github.com/marniks7/bitmap-usage/
    cd bitmap-usage
    git checkout update-dependencies
    go test ./runner/... -run PerformanceWrkExperiments -covermode=atomic -short -test.v -count=1
    

    AR: (wrk, client side), 3 errors per 390k+ requests

      391214 requests in 10.10s, 76.38MB read
      Non-2xx or 3xx responses: 3
    

    ER: Non-2xx or 3xx responses should be absent

    AR: (errors on application side)

    2022-04-10T11:01:28-04:00 ERR Unable to find price id error="unable find price, no default and >1 found"
    2022-04-10T11:01:32-04:00 ERR Unable to find price id error="unable find price, no default and >1 found"
    2022-04-10T11:01:34-04:00 ERR Unable to find price id error="unable find price, no default and >1 found"
    

    ER: there should be 0 errors on application side

    Code: https://github.com/marniks7/bitmap-usage/blob/update-dependencies/index-kelindar/searchv2.go Code for breakpoint:

     else {
    		return 0, ErrUnableToFindPriceMoreThenOneNoDefault
    	}
    

    List of used operations:

    tx.index.And
    tx.index.Count()
    bm.Clone
    

    Debug:

    1. KELINDAR32=true FIBER=true go run main.go
    2. make wrk-kelindar-t2-c20
  • AVX2. And operation produce wrong result when bitmaps have different sizes. V2

    AVX2. And operation produce wrong result when bitmaps have different sizes. V2

    Hi, one more failing test: bigger, smaller, bigger

    func TestAnd_ConsecutiveAnd_DifferentBitmapSizes(t *testing.T) {
    	a, b, c := Bitmap{}, Bitmap{}, Bitmap{}
    	for i := uint32(0); i < 200; i += 2 {
    		a.Set(i)
    	}
    
    	for i := uint32(0); i < 100; i += 2 {
    		b.Set(i)
    	}
    
    	for i := uint32(0); i < 200; i += 2 {
    		c.Set(i)
    	}
    
    	a.And(b)
    	a.And(c)
    
    	for i := uint32(0); i < 200; i++ {
    		assert.Equal(t, a.Contains(i), b.Contains(i), "for "+strconv.Itoa(int(i)))
    	}
    	assert.Equal(t, 50, a.Count())
    }
    
      bitmap_test.go:380: 
            	Error Trace:	bitmap_test.go:380
            	Error:      	Not equal: 
            	            	expected: true
            	            	actual  : false
            	Test:       	TestAnd_DifferentBitmapSizes
            	Messages:   	for 128
        bitmap_test.go:380: 
            	Error Trace:	bitmap_test.go:380
            	Error:      	Not equal: 
            	            	expected: true
            	            	actual  : false
            	Test:       	TestAnd_DifferentBitmapSizes
            	Messages:   	for 130
    
  • Give credit to the original author?

    Give credit to the original author?

    Thanks for creating a usable Go bitmap index library! One thing I noticed while I was reading through the code: parts of the heavy lifting (AVX code generation) seems similar to code from a talk given by @mkevac (https://m.youtube.com/watch?v=WvlUH6MjUuI) and his examples https://github.com/mkevac/gopherconrussia2019/tree/master/simplesimd - with many identical lines (https://github.com/mkevac/gopherconrussia2019/blob/master/simplesimd/asm.go#L106 vs https://github.com/kelindar/bitmap/blob/main/generate/amd64.go#L104). If it was actually copied I think it would be fair to give the original author some credit, especially given that he has not put the code under any official licence and the files in this repo all contain Copyright (c) Roman Atachiants 😏. If it wasn't mea culpa.

  • Improved aggregations, rolled back popcount

    Improved aggregations, rolled back popcount

    This PR rolls back the vectorized popcount that have been added, as it seems to give me a address fault under certain conditions (only noticed in a test). Moreover, it improves the Sum(), Min() and Max() aggregates when traversing filled bitmaps, ~2x improvement over previous state.

  • Add filtered reduction functions

    Add filtered reduction functions

    This PR adds simple generic functions for filtered reduction specifically Sum([]T, Bitmap), Min([]T, Bitmap) and Max([]T, Bitmap). They are not the most optimized at the moment, but should be at least 2x better than the naive implementations using range or loop, as these reductions are done in a vectorized way.

  • Using vectorized popcount

    Using vectorized popcount

    This PR adds a vectorized population count implementation, described in the paper https://arxiv.org/pdf/1611.07612.pdf by W. Mula, N. Kurz and D. Lemire. The code itself is borrowed from https://github.com/viant/vec/tree/main/bits with few alteration and a toolchain, I have it working for amd64 but haven't implemented for arm64 yet.

    This results in a 50% improvement of performance for Count() operation and is especially useful for large bitmaps.

  • Add checks for From/ToBytes

    Add checks for From/ToBytes

    Add checks to FromBytes() and ToBytes() methods when the input is nil. FromBytes() will now panic if the input buffer provided is not a multiple of 8. Fixes https://github.com/kelindar/bitmap/issues/20

  • FromBytes() has bug about length of buffer

    FromBytes() has bug about length of buffer

    // FromBytes reads a bitmap from a byte buffer without copying the buffer.
    func FromBytes(buffer []byte) (out Bitmap) {
    	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&out))
    	hdr.Len = len(buffer) >> 3
    	hdr.Cap = hdr.Len
    	hdr.Data = uintptr(unsafe.Pointer(&(buffer)[0]))
    	return out
    }
    

    While length of buffer less than 8, hdr.Len is always 0. And length of buffer must be a multiple of 8.

  • Add batched And/AndN/Or/Xor

    Add batched And/AndN/Or/Xor

    This PR adds optimized code to perform And, And Not, Or and Xor operations on multiple bitmaps at once. The signature hence now adds a variadic parameter for extra bitmaps, as shown below.

    func (*Bitmap) And(other Bitmap, extra ...Bitmap)
    
    cpu: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz
    BenchmarkMany/and4-naive-8         	  100153	     12324 ns/op	       0 B/op	       0 allocs/op
    BenchmarkMany/and4-many-8          	  139195	      8709 ns/op	       0 B/op	       0 allocs/op
    

    The main difference is that SIMD code generated now performs multiple of these instructions at once, allowing us to make better use of the cached destination bitmap. Below are the comparison results between naive version which calls And() 4 times and the batched version which calls And() with 1 other bitmap and 3 extra.

    image

    image

    image

  • Smoother resize of bitmap

    Smoother resize of bitmap

    Instead of simply using next power of 2 to resize bitmaps, now after 256 elements we will use a formula that is similar to one used during slice append, which increases the slice gradually 25% at a time, saving space.

  • Implement ReaderFrom interface

    Implement ReaderFrom interface

    This PR adds a proper ReaderFrom (see https://pkg.go.dev/io#ReaderFrom) implementation on the bitmap itself, with a couple of more tests and benchmarks.

  • Bitmap.Or(shortBitmap, longBitmap) result length same as the first one

    Bitmap.Or(shortBitmap, longBitmap) result length same as the first one

    When using multiple bitmaps as Bitmap.Or() parameters, the length of destination Bitmap will be same to the first bitmap, if first one is shorter than others, the result will be truncate to start bytes of the result.

    Here is sample code to reproduce, see only in last case, call Or() one by one, get the right result.

    package main
    
    import (
    	"fmt"
    	"github.com/kelindar/bitmap"
    )
    
    func main() {
    	bm := new(bitmap.Bitmap)
    	bm1 := bitmap.FromBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
    	bm2 := bitmap.FromBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
    	bm3 := bitmap.FromBytes([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
    	bm.Or(bm1, bm2, bm3)
    	fmt.Println("Excepted:3, got:", bm.Count())
    	bm.Clear()
    	bm.Or(bm1, bm3, bm2)
    	fmt.Println("Excepted:3, got:", bm.Count())
    	bm.Clear()
    	bm.Or(bm3, bm2, bm1)
    	fmt.Println("Excepted:3, got:", bm.Count())
    	fmt.Printf("bm:%+v\n", bm.ToBytes())
    	bm.Clear()
    	bm.Or(bm3, bm1, bm2)
    	fmt.Println("Excepted:3, got:", bm.Count())
    	fmt.Printf("bm:%+v\n", bm.ToBytes())
    	bm.Clear()
    	bm.Or(bm2, bm3, bm1)
    	fmt.Println("Excepted:3, got:", bm.Count())
    	bm.Clear()
    	bm.Or(bm2, bm1, bm3)
    	fmt.Println("Excepted:3, got:", bm.Count())
    	bm.Clear()
    	bm.Or(bm3)
    	bm.Or(bm2)
    	bm.Or(bm1)
    	fmt.Println("Excepted:3, got:", bm.Count())
    }
    

    outputs,

    Excepted:3, got: 1
    Excepted:3, got: 1
    Excepted:3, got: 32
    bm:[0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 69 120 99 101 112 116 101 101]
    Excepted:3, got: 32
    bm:[0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 69 120 99 101 112 116 101 101]
    Excepted:3, got: 2
    Excepted:3, got: 2
    Excepted:3, got: 3
    

    Affected lib versions: v1.2.1, v1.4.1 (I found this issue on v1.2.1 and reproduced on v1.4.1) Affected Go versions: go1.17.6 darwin/amd64, go1.18.5 darwin/amd64 Affected OS: macOS Monterey 12.5.1

  • No benefit with new bulk approach for `And` ?

    No benefit with new bulk approach for `And` ?

    Hi, based on the release v1.2.0 i have tried to use bulk approach for And operation for 1 + 6 extra bitmaps. Usage: index.And(bms[0], bms[1:]...) I do understand that there is 1 + 3 extra handled in bulk, and all next extra are handled one-by-one, but still

    Timings for bitmap.And: 5.31s before vs 5.38s after (though this vary). I did few other tests and I don't see benefits.

    Another test:

    name              old time/op    new time/op    delta
    FindPriceV2_Real    10.4µs ± 3%    10.3µs ± 3%     ~     (p=1.000 n=5+5)
    
    name              old alloc/op   new alloc/op   delta
    FindPriceV2_Real      361B ± 0%      537B ± 0%  +48.75%  (p=0.008 n=5+5)
    
    name              old allocs/op  new allocs/op  delta
    FindPriceV2_Real      8.00 ± 0%      9.00 ± 0%  +12.50%  (p=0.008 n=5+5)
    

    Non-bulk approach: image

    Bulk approach: image

  • sync.Pool usage

    sync.Pool usage

    Hi, I was testing different bitmap libraries (by the way as a replacement for hash map) The results i received for 8 and operations for 500k entities where first bitmap has 10k entities in a row with 1 bit, Clone of the bitmap is used on each operation

    goos: linux
    goarch: amd64
    pkg: bitmap-usage/benchmark/500k-large-groups/kelindar
    cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    BenchmarkFindPriceV2_11position            	   26214	     41542 ns/op	   67760 B/op	       8 allocs/op
    BenchmarkFindPriceV2_3824position          	   45291	     40293 ns/op	   73904 B/op	       8 allocs/op
    BenchmarkFindPriceV2_3824position_OptStats 	   43438	     35956 ns/op	   73952 B/op	      13 allocs/op
    BenchmarkFindPriceV2_9701position          	   41796	     36919 ns/op	   65712 B/op	       7 allocs/op
    BenchmarkFindPriceV2_MultiplePricesErr     	   44133	     24858 ns/op	   73856 B/op	       6 allocs/op
    PASS
    ok  	bitmap-usage/benchmark/500k-large-groups/kelindar	51.610s
    

    This is what i received for https://github.com/kelindar/column

    goos: linux
    goarch: amd64
    pkg: bitmap-usage/benchmark/500k-large-groups/kelindar-column
    cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    BenchmarkFindPriceV2_11position            	   40641	     25217 ns/op	     216 B/op	       8 allocs/op
    BenchmarkFindPriceV2_3824position          	   45633	     25901 ns/op	     216 B/op	       8 allocs/op
    BenchmarkFindPriceV2_9701position          	   44162	     26637 ns/op	     217 B/op	       8 allocs/op
    BenchmarkFindPriceV2_MultiplePricesErr     	   48385	     24083 ns/op	     177 B/op	       6 allocs/op
    PASS
    ok  	bitmap-usage/benchmark/500k-large-groups/kelindar-column	107.145s
    

    In your kelindar-column you have fill bitmap.Bitmap // The fill-list and Txn with sync.Pool usage which allow to avoid bitmap allocation. I believe the technique is worth mentioning for potential users of this library

    Results with sync.Pool:

    goos: linux
    goarch: amd64
    pkg: bitmap-usage/benchmark/500k-large-groups/kelindar
    cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    BenchmarkFindPriceV2_11position            	   79882	     15122 ns/op	     176 B/op	       6 allocs/op
    BenchmarkFindPriceV2_3824position          	   85920	     14792 ns/op	     176 B/op	       6 allocs/op
    BenchmarkFindPriceV2_3824position_OptStats 	   68959	     15563 ns/op	     225 B/op	      11 allocs/op
    BenchmarkFindPriceV2_9701position          	   56557	     19224 ns/op	     177 B/op	       6 allocs/op
    BenchmarkFindPriceV2_MultiplePricesErr     	  106196	     11107 ns/op	     128 B/op	       4 allocs/op
    PASS
    ok  	bitmap-usage/benchmark/500k-large-groups/kelindar	61.455s
    

    if you are curious here is hashmap results - iteration and comparison for 10k entities

    goos: linux
    goarch: amd64
    pkg: bitmap-usage/benchmark/500k-large-groups/map
    cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    BenchmarkHttpClientServer_FindPrice            	    5232	    220943 ns/op	    8283 B/op	     112 allocs/op
    BenchmarkFindPrice_11position                  	    9979	    118803 ns/op	      64 B/op	       1 allocs/op
    BenchmarkFindPrice_3824position                	    9849	    119427 ns/op	      64 B/op	       1 allocs/op
    BenchmarkFindPrice_3824position_Optimized      	   25146	     46990 ns/op	      64 B/op	       1 allocs/op
    BenchmarkFindPrice_9701position                	    9825	    120534 ns/op	      64 B/op	       1 allocs/op
    BenchmarkFindPrice_9701position_Optimized      	    9945	    117033 ns/op	      64 B/op	       1 allocs/op
    BenchmarkFindPrice_MultiplePricesErr           	    9799	    119765 ns/op	       0 B/op	       0 allocs/op
    BenchmarkFindPrice_MultiplePricesErr_Optimized 	    9814	    119057 ns/op	       0 B/op	       0 allocs/op
    PASS
    ok  	bitmap-usage/benchmark/500k-large-groups/map	47.843s
    
高性能的分布式的专门空间优化的 Bitmap 服务, 高效检查数据是否存在,日活统计,签到,打点等等
高性能的分布式的专门空间优化的 Bitmap 服务, 高效检查数据是否存在,日活统计,签到,打点等等

基于Raft的数据一致性分布式的 bitmap 服务 bitmap(位图)技术是数据库、大数据和互联网业务等场景下经常使用的一种技术。 存在性判断 爬虫url去重 垃圾邮件过滤 用户已阅读 用户已赞 ... 去重 数据库 大数据计算 架构图 支持三种协议读写: HTTP、redcis和rpcx。 写

Dec 5, 2022
Package for indexing zip files and storing a compressed index

zipindex zipindex provides a size optimized representation of a zip file to allow decompressing the file without reading the zip file index. It will o

Nov 30, 2022
Maintidx measures the maintainability index of each function

maintidx maintidx measures the maintainability index of each function. Here for

Dec 17, 2022
Simple code just to try out and Binary Tree on Golang.

Character counter | ▮▮▮▮▮▮▮▮ Simple code just to try out and Binary Tree on Golang. Count characters to train openning a file and reading it, as well

May 17, 2022
A binary stream packer and unpacker

binpacker A binary packer and unpacker. Install go get github.com/zhuangsirui/binpacker Examples Packer buffer := new(bytes.Buffer) packer := binpacke

Dec 1, 2022
A Left-Leaning Red-Black (LLRB) implementation of balanced binary search trees for Google Go

GoLLRB GoLLRB is a Left-Leaning Red-Black (LLRB) implementation of 2-3 balanced binary search trees in Go Language. Overview As of this writing and to

Dec 23, 2022
Golang channel example with equivalent binary tree
Golang channel example with equivalent binary tree

golang_channel_example_with_equivalent_binary_tree Exercise: Equivalent Binary Trees There can be many different binary trees with the same sequence o

Oct 9, 2021
A project that deals with implementations of a binary tree

Binary Search Tree This is a project that deals with implementations of a binary tree and the following functions. Print Prints the entire tree. Argum

Nov 1, 2021
A slice backed binary heap with support for generic type parameters.

go-binaryheap A slice backed binary heap where the order can be customized by a comparison function. The main branch now requires go 1.18 because the

Jun 13, 2022
A simple set type for the Go language. Trusted by Docker, 1Password, Ethereum and Hashicorp.

golang-set The missing set collection for the Go language. Until Go has sets built-in...use this. Coming from Python one of the things I miss is the s

Jan 8, 2023
A simple Set data structure implementation in Go (Golang) using LinkedHashMap.

Set Set is a simple Set data structure implementation in Go (Golang) using LinkedHashMap. This library allow you to get a set of int64 or string witho

Sep 26, 2022
go.fifo provides a simple fifo thread-safe queue for the Go programming language

go.fifo Description go.fifo provides a simple FIFO thread-safe queue. *fifo.Queue supports pushing an item at the end with Add(), and popping an item

Aug 29, 2022
Simple priority queue in Go

Priority Queue in Go ==================== This package provides a priority queue implementation and scaffold interfaces. Installation ------------ U

Apr 5, 2022
BTree provides a simple, ordered, in-memory data structure for Go programs.

BTree implementation for Go This package provides an in-memory B-Tree implementation for Go, useful as an ordered, mutable data structure. The API is

Dec 30, 2022
A simple Bloom Filter implementation in Go

This is a simple Bloom filter implementation written in Go. For the theory behind Bloom filters, read http://en.wikipedia.org/wiki/Bloom_filter This

Apr 26, 2018
A simple and efficient thread-safe sharded hashmap for Go

shardmap A simple and efficient thread-safe sharded hashmap for Go. This is an alternative to the standard Go map and sync.Map, and is optimized for w

Dec 17, 2022
simple golang event bus structure

super simple and small event bus structure for golang that allows emissions as go routines.

Dec 11, 2021
A threadsafe single-value cache for Go with a simple but flexible API

SVCache SVCache is a threadsafe, single-value cache with a simple but flexible API. When there is no fresh value in the cache, an attempt to retrieve

Jan 23, 2022
Structscanner is a simple library to make going from database queries to structs easier

structscanner is a simple library to make going from database queries to structs easier, while retaining the flexibility of joins and mapping using struct tags.

Oct 17, 2022