omap

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Dec 31, 2025 License: BSD-3-Clause Imports: 6 Imported by: 1

README

Ordered map

Omap is Golang package for working with thread safe ordered maps. The ordered map contains the golang map, list and mutex to execute Ordered Map functions.

The Ordered Map is a map that remembers the order of items. The map can be iterated over to retrieve the items in the order they were added.

GoDoc Go Report Card

Omap

Introduction to the omap Go Package

The omap Go package is a lightweight and efficient library for working with ordered maps in Go. An ordered map is a data structure that combines the benefits of a map and a list, allowing you to store key-value pairs in a specific order.

What is omap?

Omap is a Go package that provides an implementation of an ordered map. It is designed to be fast, efficient, and easy to use. Omap is particularly useful when you need to store data in a specific order, such as when working with configuration files, caching, or data processing pipelines.

Key Features of omap

  • Ordered: omap preserves the order in which key-value pairs are inserted, allowing you to iterate over the map in a specific order.

  • Fast lookups: omap uses a hash table to store key-value pairs, making lookups fast and efficient.

  • Efficient insertion and deletion: omap uses a linked list to store the order of key-value pairs, making insertion and deletion operations efficient.

Using omap

To use omap, you can install it using the following command:

go get github.com/kirill-scherba/omap

Here is an example of how to use omap:

package main

import (
    "fmt"
    "log"

    "github.com/kirill-scherba/omap"
)

func main() {
    // Create a new ordered map
    m, err := omap.New[string, string]()
    if err != nil {
        log.Fatal(err)
    }

    // Insert some key-value pairs
    m.Set("key1", "value1")
    m.Set("key2", "value2")
    m.Set("key3", "value3")

    // Iterate over the omap in order
    for _, pair := range m.Pairs() {
        fmt.Printf("%s: %s\n", pair.Key, pair.Value)
    }
}

This code creates a new omap, inserts some key-value pairs, and then iterates over the omap in order, printing out each key-value pair.

Execute this example on Go playground: https://go.dev/play/p/LzauNwMuezB

Or run it on your local machine: go run ./examples/pairs/

Conclusion

The omap Go package is a useful library for working with ordered maps in Go. Its fast lookups, efficient insertion and deletion, and ordered iteration make it a great choice for a variety of use cases. Whether you're working with configuration files, caching, or data processing pipelines, omap is definitely worth considering.

Example Use Cases

  • Configuration files: Use omap to store configuration data in a specific order, making it easy to iterate over the configuration and apply settings in the correct order.

  • Caching: Use omap to store cached data in a specific order, making it easy to iterate over the cache and evict items in the correct order.

  • Data processing pipelines: Use omap to store data in a specific order, making it easy to iterate over the data and process it in the correct order.

Examples

Basic usage example
package main

import (
    "fmt"
    "log"

    "github.com/kirill-scherba/omap"
)

func main() {
    fmt.Println("Ordered map basic example")

    // Struct to store in ordered map
    type Person struct {
        Name string
        Age  int
    }

    // Create new ordered map
    o, err := omap.New[string, *Person]()
    if err != nil {
        log.Fatal(err)
    }

    // Add records to ordered map
    o.Set("John", &Person{Name: "John", Age: 30})
    o.Set("Jane", &Person{Name: "Jane", Age: 25})
    o.Set("Bob", &Person{Name: "Bob", Age: 40})
    o.Set("Alice", &Person{Name: "Alice", Age: 35})

    // Print all records
    fmt.Print("\nList records ordered by default (insertion):\n\n")
    o.ForEach(func(key string, data *Person) {
        fmt.Println(key, data)
    })
}

Execute this example on Go playground: https://go.dev/play/p/T1VMf1J5n4_H

Or run it on your local machine: go run ./examples/basic/

Multiple indexes example

By default, the ordered map is created with one default (insertion) index.

You can create additional indexes by adding there sort functions and names to the ordered map creation function. All indexes are recalculated on each operation with map.

package main

import (
    "fmt"
    "log"
    "strings"

    "github.com/kirill-scherba/omap"
)

// Struct to store in ordered map
type Person struct {
    Name string
    Age  int
}

func main() {
    fmt.Println("Ordered map multiple indexes example")

    // Create new ordered map with indexes by Name and Age
    o, err := omap.New(
        omap.Index[string, *Person]{Key: "Name", Func: CompareByName},
        omap.Index[string, *Person]{Key: "Key", Func: omap.CompareByKey[string, *Person]},
        omap.Index[string, *Person]{Key: "AgeAsc", Func: CompareByAgeAsc},
        omap.Index[string, *Person]{Key: "AgeDesc", Func: CompareByAgeDesc},
    )
    if err != nil {
        log.Fatal(err)
    }

    // Add records to ordered map
    o.Set("John", &Person{Name: "John", Age: 30})
    o.Set("Jane", &Person{Name: "Jane", Age: 25})
    o.Set("Bob", &Person{Name: "Bob", Age: 40})
    o.Set("Alice", &Person{Name: "Alice", Age: 35})

    // Print all records
    fmt.Print("\nList records ordered by default (insertion):\n\n")
    o.ForEach(func(key string, data *Person) {
        fmt.Println(key, data)
    })

    // Print all records by Name index
    fmt.Print("\nList records ordered by Name index:\n\n")
    o.ForEach(func(key string, data *Person) {
        fmt.Println(key, data)
    }, "Name")

    // Print all records by Age ascending index
    fmt.Print("\nList records ordered by Age index:\n\n")
    o.ForEach(func(key string, data *Person) {
        fmt.Println(key, data)
    }, "AgeAsc")

    // Print all records by Age descending index
    fmt.Print("\nList records ordered by Age index:\n\n")
    o.ForEach(func(key string, data *Person) {
        fmt.Println(key, data)
    }, "AgeDesc")
}

func CompareByName(r1, r2 *omap.Record[string, *Person]) int {
    return strings.Compare(
        strings.ToLower(r1.Data().Name), strings.ToLower(r2.Data().Name),
    )
}

func CompareByAgeAsc(r1, r2 *omap.Record[string, *Person]) int {
    return r1.Data().Age - r2.Data().Age
}

func CompareByAgeDesc(r1, r2 *omap.Record[string, *Person]) int {
    return r2.Data().Age - r1.Data().Age
}

Execute this example on Go playground: https://go.dev/play/p/ppUx3Afn7ky

Or run it on your local machine: go run ./examples/multiple_index/

Licence

BSD

Documentation

Overview

Omap is Golang package for working with thread safe ordered maps. The ordered map contains the golang map, list and mutex to execute Ordered Map functions.

The Ordered Map is a map that remembers the order of items. The map can be iterated over to retrieve the items in the order they were added.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMapIsEmpty              = errors.New("map is empty")
	ErrRecordNotFound          = errors.New("record not found")
	ErrKeyAllreadySet          = errors.New("key already exists")
	ErrIncorrectIndexKey       = errors.New("incorrect index key name")
	ErrIncorrectIndexDirection = errors.New("incorrect index direction")
)

Functions

func CompareByKey

func CompareByKey[K constraints.Ordered, D any](r1, r2 *Record[K, D]) int

CompareByKey compares two records by their keys.

This function returns a negative value if rec1 key is less than rec2 key, zero if the keys are equal, and a positive value if rec1 key is greater than rec2 key.

Types

type Index

type Index[K comparable, D any] struct {
	Key  any
	Func SortIndexFunc[K, D]
}

Index is a sort index definition struct.

type Indexes added in v0.0.9

type Indexes[K comparable, D any] Omap[K, D]

Indexes provides methods to handle index lists.

func (*Indexes[K, D]) First added in v0.0.9

func (in *Indexes[K, D]) First(idxKeys ...any) *Record[K, D]

First gets first record from ordered map or nil if map is empty or incorrect index is passed.

func (*Indexes[K, D]) InsertAfter added in v0.0.9

func (in *Indexes[K, D]) InsertAfter(key K, data D, mark *Record[K, D]) (
	err error)

InsertAfter inserts record after element. Returns ErrKeyAllreadySet if key already exists.

func (*Indexes[K, D]) InsertBefore added in v0.0.9

func (in *Indexes[K, D]) InsertBefore(key K, data D, mark *Record[K, D]) (
	err error)

InsertBefore inserts record before element. Returns ErrKeyAllreadySet if key already exists.

func (*Indexes[K, D]) Last added in v0.0.9

func (in *Indexes[K, D]) Last(idxKeys ...any) *Record[K, D]

Last gets last record from ordered map or nil if the list is empty.

func (*Indexes[K, D]) MoveAfter added in v0.0.9

func (in *Indexes[K, D]) MoveAfter(rec, mark *Record[K, D]) (err error)

MoveAfter moves record rec to the new position after mark record. It returns ErrRecordNotFound if input record or mark record is nil.

func (*Indexes[K, D]) MoveBefore added in v0.0.9

func (in *Indexes[K, D]) MoveBefore(rec, mark *Record[K, D]) (err error)

MoveBefore moves record rec to the new position before mark record. It returns ErrRecordNotFound if input record or mark record is nil.

func (*Indexes[K, D]) MoveToBack added in v0.0.9

func (in *Indexes[K, D]) MoveToBack(rec *Record[K, D]) (err error)

MoveToBack moves record to the back of ordered map. It returns ErrRecordNotFound if input record is nil.

func (*Indexes[K, D]) MoveToFront added in v0.0.9

func (in *Indexes[K, D]) MoveToFront(rec *Record[K, D]) (err error)

MoveToFront moves record to the front of ordered map. It returns ErrRecordNotFound if input record is nil.

func (*Indexes[K, D]) MoveUp added in v0.0.12

func (in *Indexes[K, D]) MoveUp(rec *Record[K, D]) (err error)

MoveUp moves record rec to the new position before previous record. It returns ErrRecordNotFound if input record is nil.

func (*Indexes[K, D]) Next added in v0.0.9

func (in *Indexes[K, D]) Next(rec *Record[K, D]) *Record[K, D]

Next gets next record from ordered map or nil if there is last record or input record is nil.

func (*Indexes[K, D]) Prev added in v0.0.9

func (in *Indexes[K, D]) Prev(rec *Record[K, D]) *Record[K, D]

Prev gets previous record from ordered map or nil if this record is first.

type Omap

type Omap[K comparable, D any] struct {

	// Indexes module
	Idx *Indexes[K, D]

	// Mutex to protect ordered map operations
	*sync.RWMutex
	// contains filtered or unexported fields
}

Omap is a concurrent safe multi index ordered map.

func New

func New[K comparable, D any](sorts ...Index[K, D]) (m *Omap[K, D], err error)

New creates a new ordered map object with key of type T and data of type D.

func (*Omap[K, D]) Clear

func (m *Omap[K, D]) Clear()

Clear removes all records from ordered map.

func (*Omap[K, D]) Del

func (m *Omap[K, D]) Del(key K, unsafe ...bool) (data D, ok bool)

Del removes record from ordered map by key. Returns ok true and deleted data if key exists, and record was successfully removed.

func (*Omap[K, D]) DelLast added in v0.0.12

func (m *Omap[K, D]) DelLast(unsafe ...bool) (rec *Record[K, D], data D, ok bool)

DelLast removes last record from ordered map by default index. Returns ok true and deleted record if it was successfully removed.

func (*Omap[K, D]) Exists added in v0.0.10

func (m *Omap[K, D]) Exists(key K, unsafe ...bool) (exists bool)

Exists returns true if key exists in the map.

func (*Omap[K, D]) ForEach

func (m *Omap[K, D]) ForEach(f func(key K, data D), idxKey ...any)

ForEach calls function f for each key present in the map.

By default, it iterates over default (insertion) index. Use idxKey to iterate over other indexes.

Function f is called for each key present in the map. The order of iteration is determined by the index. If the index is not specified, the default (insertion) index is used. The RLock is held during the iteration, so the map cannot be modified during the iteration and any omap methods which uses Lock cannot be used avoid deadlocks.

func (*Omap[K, D]) ForEachPair added in v0.0.8

func (m *Omap[K, D]) ForEachPair(f func(pair Pair[K, D]), idxKey ...any)

ForEachPair calls function f for each key-value pair present in the map.

By default, it iterates over default (insertion) index. Use idxKey to iterate over other indexes.

It allows to handle key-value pairs directly, which could be useful for example to call methods on the pair, or to get the index of the pair in the list.

Function f is called for each key present in the map. The RLock is held during the iteration, so the map cannot be modified during the iteration and any omap methods which uses Lock cannot be used avoid deadlocks.

func (*Omap[K, D]) ForEachRecord added in v0.0.8

func (m *Omap[K, D]) ForEachRecord(f func(rec *Record[K, D]), idxKey ...any)

ForEachRecord calls function f for each record present in the map.

By default, it iterates over default (insertion) index. Use idxKey to iterate over other indexes.

It allows to handle records directly, which could be useful for example to call methods on the record, or to get the index of the record in the list.

Function f is called for each key present in the map. The RLock is held during the iteration, so the map cannot be modified during the iteration and any omap methods which uses Lock cannot be used avoid deadlocks.

func (*Omap[K, D]) Get

func (m *Omap[K, D]) Get(key K, unsafe ...bool) (data D, ok bool)

Get gets records data from ordered map by key. Returns ok true if found.

func (*Omap[K, D]) GetRecord

func (m *Omap[K, D]) GetRecord(key K, unsafe ...bool) (rec *Record[K, D], ok bool)

GetRecord gets record from ordered map by key. Returns ok true if found.

func (*Omap[K, D]) Len

func (m *Omap[K, D]) Len() int

Len returns the number of elements in the map.

func (*Omap[K, D]) Pairs added in v0.0.8

func (m *Omap[K, D]) Pairs(idxKey ...any) (pairs []Pair[K, D])

Pairs returns a slice of key-value pairs in the omap. By default, it iterates over default (insertion) index. Use idxKey to iterate over other indexes.

func (*Omap[K, D]) Records added in v0.0.9

func (m *Omap[K, D]) Records(idxKey ...any) iter.Seq2[K, D]

Records returns an iterator over the omap records. By default, it iterates over default (insertion) index. Use idxKey to iterate over other indexes.

The iteration stops when the function passed to the iterator returns false.

This function is safe for concurrent read access. RWmutex is locked by RLock. Don't use other Omap methods which uses mutex inside iterator avoid deadlocks.

func (*Omap[K, D]) RecordsWrite added in v0.1.0

func (m *Omap[K, D]) RecordsWrite(idxKey ...any) iter.Seq2[K, D]

RecordsWrite returns an iterator over the omap records. By default, it iterates over default (insertion) index. Use idxKey to iterate over other indexes.

The iteration stops when the function passed to the iterator returns false.

This function is safe for concurrent write access. RWmutex is locked by Lock. Don't use other Omap methods which uses mutex inside iterator avoid deadlocks.

func (*Omap[K, D]) Refresh added in v0.0.8

func (m *Omap[K, D]) Refresh()

Refresh refreshes the index lists.

The indexes automatically sorts when a new record was added or updated with the Set or SetFirst methods.

If you directly update the map data (D type) use this method to refresh the index lists.

You should use Lock or RLock to avoid concurrent access when changing the map data directly.

func (*Omap[K, D]) Set

func (m *Omap[K, D]) Set(key K, data D, unsafe ...bool) error

Set adds or updates record in ordered map by key. It adds new record to the back of ordered map. If key already exists, its data will be updated. Set unsafe to true to skip locking ordered map.

func (*Omap[K, D]) SetFirst

func (m *Omap[K, D]) SetFirst(key K, data D, unsafe ...bool) (err error)

SetFirst adds or updates record in ordered map by key. It adds new record to the front of ordered map. If key already exists, its data will be updated. Set unsafe to true to skip locking ordered map.

type Pair added in v0.0.8

type Pair[K comparable, D any] struct {
	Key   K
	Value D
}

Pair represents a key-value pair in the ordered map.

type Record

type Record[K comparable, D any] list.Element

Record is a struct that contains list element and methods.

We import container/list package to use *list.Element in Record type. We use *list.Element to make Record type compatible with *list.Element, so we can use Record as *list.Element.

func (*Record[K, D]) Data

func (r *Record[K, D]) Data() (data D)

Data returns record data (value).

func (*Record[K, D]) Key

func (r *Record[K, D]) Key() (key K)

Key returns record key.

func (*Record[K, D]) Update added in v0.0.10

func (r *Record[K, D]) Update(data D)

Update updates record data (value).

type SortIndexFunc

type SortIndexFunc[K comparable, D any] func(rec, next *Record[K, D]) int

Directories

Path Synopsis
Package cache provides an inmemory cache implementation based on ordered map.
Package cache provides an inmemory cache implementation based on ordered map.
examples
basic command
multiple_index command
pairs command
records command

Jump to

Keyboard shortcuts

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