haxmap

package module
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2022 License: MIT Imports: 7 Imported by: 49

README

HaxMap

Main Actions Status Go Report Card License

A lightning fast concurrent hashmap

The hashing algorithm used was xxHash and the hashmap's buckets were implemented using Harris lock-free list

Installation

You need Golang 1.18.x or above

$ go get github.com/alphadose/haxmap

Usage

package main

import (
	"fmt"

	"github.com/alphadose/haxmap"
)

func main() {
	// initialize map with key type `int` and value type `string`
	mep := haxmap.New[int, string]()

	// set a value (overwrites existing value if present)
	mep.Set(1, "one")

	// get the value and print it
	val, ok := mep.Get(1)
	if ok {
		println(val)
	}

	mep.Set(2, "two")
	mep.Set(3, "three")
	mep.Set(4, "four")

	// ForEach loop to iterate over all key-value pairs and execute the given lambda
	mep.ForEach(func(key int, value string) bool {
		fmt.Printf("Key -> %d | Value -> %s\n", key, value)
		return true // return `true` to continue iteration and `false` to break iteration
	})

	mep.Del(1) // delete a value
	mep.Del(0) // delete is safe even if a key doesn't exists

	// bulk deletion is supported too in the same API call
	// has better performance than deleting keys one by one
	mep.Del(2, 3, 4)

	if mep.Len() == 0 {
		println("cleanup complete")
	}
}

Benchmarks

Benchmarks were performed against golang sync.Map and the latest cornelk-hashmap

All results were computed from benchstat of 20 runs (code available here)

  1. Concurrent Reads Only
name                         time/op
HaxMapReadsOnly-8            6.94µs ± 4%
GoSyncMapReadsOnly-8         21.5µs ± 3%
CornelkMapReadsOnly-8        8.39µs ± 8%
  1. Concurrent Reads with Writes
name                         time/op
HaxMapReadsWithWrites-8      8.23µs ± 3%
GoSyncMapReadsWithWrites-8   25.0µs ± 2%
CornelkMapReadsWithWrites-8  8.83µs ±20%

name                         alloc/op
HaxMapReadsWithWrites-8      1.25kB ± 5%
GoSyncMapReadsWithWrites-8   6.20kB ± 7%
CornelkMapReadsWithWrites-8  1.53kB ± 9%

name                         allocs/op
HaxMapReadsWithWrites-8         156 ± 5%
GoSyncMapReadsWithWrites-8      574 ± 7%
CornelkMapReadsWithWrites-8     191 ± 9%

From the above results it is evident that haxmap takes the least time, memory and allocations in all cases making it the best golang concurrent hashmap in this period of time

Tips

  1. HaxMap by default uses xxHash algorithm, but you can override this and plug-in your own custom hash function. Beneath lies an example for the same.
package main

import (
	"github.com/alphadose/haxmap"
)

// your custom hash function
// the hash function signature must adhere to `func(keyType) uintptr`
func customStringHasher(s string) uintptr {
	return uintptr(len(s))
}

func main() {
	m := haxmap.New[string, string]() // initialize a string-string map
	m.SetHasher(customStringHasher) // this overrides the default xxHash algorithm

	m.Set("one", "1")
	val, ok := m.Get("one")
	if ok {
		println(val)
	}
}
  1. You can pre-allocate the size of the map which will improve performance in some cases.
package main

import (
	"github.com/alphadose/haxmap"
)

func main() {
	const initialSize = 1 << 10

	// pre-allocating the size of the map will prevent all grow operations
	// until that limit is hit thereby improving performance
	m := haxmap.New[int, string](initialSize)

	m.Set(1, "1")
	val, ok := m.Get(1)
	if ok {
		println(val)
	}
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Map added in v1.0.0

type Map[K hashable, V any] struct {
	// contains filtered or unexported fields
}

Map implements the concurrent hashmap

func New

func New[K hashable, V any](size ...uintptr) *Map[K, V]

New returns a new HashMap instance with an optional specific initialization size

func (*Map[K, V]) Del added in v1.0.0

func (m *Map[K, V]) Del(keys ...K)

Del deletes key/keys from the map Bulk deletion is more efficient than deleting keys one by one

func (*Map[K, V]) Fillrate added in v1.0.0

func (m *Map[K, V]) Fillrate() uintptr

Fillrate returns the fill rate of the map as an percentage integer

func (*Map[K, V]) ForEach added in v1.0.0

func (m *Map[K, V]) ForEach(lambda func(K, V) bool)

ForEach iterates over key-value pairs and executes the lambda provided for each such pair lambda must return `true` to continue iteration and `false` to break iteration

func (*Map[K, V]) Get added in v1.0.0

func (m *Map[K, V]) Get(key K) (value V, ok bool)

Get retrieves an element from the map returns `false“ if element is absent

func (*Map[K, V]) Grow added in v1.0.0

func (m *Map[K, V]) Grow(newSize uintptr)

Grow resizes the hashmap to a new size, gets rounded up to next power of 2 To double the size of the hashmap use newSize 0 No resizing is done in case of another resize operation already being in progress Growth and map bucket policy is inspired from https://github.com/cornelk/hashmap

func (*Map[K, V]) Len added in v1.0.0

func (m *Map[K, V]) Len() uintptr

Len returns the number of key-value pairs within the map

func (*Map[K, V]) Set added in v1.0.0

func (m *Map[K, V]) Set(key K, value V)

Set tries to update an element if key is present else it inserts a new element If a resizing operation is happening concurrently while calling Set() then the item might show up in the map only after the resize operation is finished

func (*Map[K, V]) SetHasher added in v1.0.0

func (m *Map[K, V]) SetHasher(hs func(K) uintptr)

SetHasher sets the hash function to the one provided by the user

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL