recmgr

package module
v0.0.0-...-95550e4 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2016 License: ISC Imports: 2 Imported by: 0

README

recmgr

MIT licensed GoDoc

Package recmgr provides a thin, multi-keyed, goroutine-safe wrapper around Google's btree package. It facilitates the use of multiple indexes to manage an in-memory collection of records.

This package operates on pointers to values, typically structs that can be indexed in multiple ways.

The methods in this package correspond to the methods of the same name in the btree package. Because multiple indexes are processed as a group, some methods are not supported, for example DeleteMin() and DeleteMax(). Similarly, some method semantics are different, for example Delete() returns the number of removed keys rather than the deleted item. Additionally, variations of the traversal methods are available that return a slice of record pointers.

All methods in this package are safe for concurrent goroutine use.

Test coverage is 100%.

##Installation

To install and later update the package on your system, run

go get -u github.com/jung-kurt/recmgr

##Quick Start

The following Go code demonstrates the creation and operation of a record manager instance.

var grp recmgr.GrpType
type person struct {
	name string
	num  int
}
personList := []person{
	{"Athos", 1},
	{"Porthos", 2},
	{"Aramis", 3}}
idxName := grp.Index(4, func(a, b interface{}) bool {
	return a.(*person).name < b.(*person).name
})
idxNum := grp.Index(4, func(a, b interface{}) bool {
	return a.(*person).num < b.(*person).num
})
for j := range personList {
	grp.ReplaceOrInsert(&personList[j])
}
print := func(recPtr interface{}) bool {
	p := recPtr.(*person)
	fmt.Printf("    %-8s %2d\n", p.name, p.num)
	return true
}
fmt.Println("Name order")
idxName.Ascend(print)
fmt.Println("Number order")
idxNum.Ascend(print)
// Output:
// Name order
//     Aramis    3
//     Athos     1
//     Porthos   2
// Number order
//     Athos     1
//     Porthos   2
//     Aramis    3

##Limitations

The records managed by this package are referenced by pointers so they should remain accessible for the duration of the recmgr instance. Notice in the range loop shown above that the record address passed to ReplaceOrInsert() points into the array that underlies the personList slice, not the address of the range expression's ephemeral second value.

Within the managed collection of records, if any key field (that is, any struct field that is used in the less function passed to Index()) is modified, it is advised to delete the record before modification and add it again afterward to keep the underlying btrees consistent. Non-key fields can be changed with impunity.

##License

recmgr is copyrighted by Kurt Jung and is released under the MIT License.

Documentation

Overview

Package recmgr provides a thin, multi-keyed, goroutine-safe wrapper around Google's btree package. It facilitates the use of multiple indexes to manage an in-memory collection of records.

This package operates on pointers to values, typically structs that can be indexed in multiple ways.

The methods in this package correspond to the methods of the same name in the btree package. Because multiple indexes are processed as a group, some methods are not supported, for example DeleteMin() and DeleteMax(). Similarly, some method semantics are different, for example Delete() returns the number of removed keys rather than the deleted item. Additionally, variations of the traversal methods are available that return a slice of record pointers.

All methods in this package are safe for concurrent goroutine use.

Test coverage is 100%.

Installation

To install and later update the package on your system, run

go get -u github.com/jung-kurt/recmgr

Quick Start

The following Go code demonstrates the creation and operation of a record manager instance.

var grp recmgr.GrpType
type person struct {
	name string
	num  int
}
personList := []person{
	{"Athos", 1},
	{"Porthos", 2},
	{"Aramis", 3}}
idxName := grp.Index(4, func(a, b interface{}) bool {
	return a.(*person).name < b.(*person).name
})
idxNum := grp.Index(4, func(a, b interface{}) bool {
	return a.(*person).num < b.(*person).num
})
for j := range personList {
	grp.ReplaceOrInsert(&personList[j])
}
print := func(recPtr interface{}) bool {
	p := recPtr.(*person)
	fmt.Printf("    %-8s %2d\n", p.name, p.num)
	return true
}
fmt.Println("Name order")
idxName.Ascend(print)
fmt.Println("Number order")
idxNum.Ascend(print)
// Output:
// Name order
//     Aramis    3
//     Athos     1
//     Porthos   2
// Number order
//     Athos     1
//     Porthos   2
//     Aramis    3

Limitations

The records managed by this package are referenced by pointers so they should remain accessible for the duration of the recmgr instance. Notice in the range loop shown above that the record address passed to ReplaceOrInsert() points into the array that underlies the personList slice, not the address of the range expression's ephemeral second value.

Within the managed collection of records, if any key field (that is, any struct field that is used in the less function passed to Index()) is modified, it is advised to delete the record before modification and add it again afterward to keep the underlying btrees consistent. Non-key fields can be changed with impunity.

License

recmgr is copyrighted by Kurt Jung and is released under the MIT License.

Example
package main

import (
	"fmt"
	"github.com/jung-kurt/recmgr"
	"strings"
)

type RecType struct {
	name string
	num  int
}

func (rec RecType) String() string {
	numStr := fmt.Sprintf("%d", rec.num)
	return fmt.Sprintf("%s%s%s", rec.name, strings.Repeat(".", 18-len(numStr)-len(rec.name)), numStr)
}

func main() {
	var rm recmgr.GrpType
	recList := []RecType{
		{name: "Brahms", num: 1833},
		{name: "Bach", num: 1685},
		{name: "Palestrina", num: 1525},
		{name: "Mozart", num: 1756},
		{name: "Schubert", num: 1797},
	}
	indent := func(fmtStr string, args ...interface{}) {
		fmt.Printf("    %s\n", fmt.Sprintf(fmtStr, args...))
	}
	print := func(recPtr interface{}) bool {
		if recPtr != nil {
			indent("%s", *recPtr.(*RecType))
		}
		return true
	}
	idxName := rm.Index(4, func(a, b interface{}) bool {
		return a.(*RecType).name < b.(*RecType).name
	})
	idxNum := rm.Index(4, func(a, b interface{}) bool {
		return a.(*RecType).num < b.(*RecType).num
	})
	for j := range recList {
		rm.ReplaceOrInsert(&recList[j])
	}
	fmt.Println("Name order")
	idxName.Ascend(print)
	fmt.Println("Number order")
	idxNum.Ascend(print)
	fmt.Println("Delete \"Palestrina\"")
	indent("keys deleted: %d", rm.Delete(idxName.Get(&RecType{name: "Palestrina"})))
	fmt.Println("Name order")
	idxName.Ascend(print)
	fmt.Println("Number order")
	idxNum.Ascend(print)
	fmt.Println("Number < 1797")
	idxNum.AscendLessThan(&RecType{num: 1797}, print)
	fmt.Println("Name >= \"Mozart\"")
	idxName.AscendGreaterOrEqual(&RecType{name: "Mozart"}, print)
	fmt.Println("1685 <= Number < 1797")
	idxNum.AscendRange(&RecType{num: 1685}, &RecType{num: 1797}, print)
	fmt.Println("Get 1756")
	print(idxNum.Get(&RecType{num: 1756}))
	fmt.Println("Get 1800")
	print(idxNum.Get(&RecType{num: 1800}))
	fmt.Println("Get \"Schubert\"")
	print(idxName.Get(&RecType{name: "Schubert"}))
	fmt.Println("Get \"Beethoven\"")
	print(idxName.Get(&RecType{name: "Beethoven"}))
	fmt.Println("Has 1756")
	indent("%v", idxNum.Has(&RecType{num: 1756}))
	fmt.Println("Has 1770")
	indent("%v", idxNum.Has(&RecType{num: 1770}))
	fmt.Println("Index count of \"Mozart\"")
	indent("%d", rm.Has(idxName.Get(&RecType{name: "Mozart"})))
	fmt.Println("Terminated")
	idxName.Ascend(func(recPtr interface{}) bool { return false })
}
Output:
Name order
    Bach..........1685
    Brahms........1833
    Mozart........1756
    Palestrina....1525
    Schubert......1797
Number order
    Palestrina....1525
    Bach..........1685
    Mozart........1756
    Schubert......1797
    Brahms........1833
Delete "Palestrina"
    keys deleted: 2
Name order
    Bach..........1685
    Brahms........1833
    Mozart........1756
    Schubert......1797
Number order
    Bach..........1685
    Mozart........1756
    Schubert......1797
    Brahms........1833
Number < 1797
    Bach..........1685
    Mozart........1756
Name >= "Mozart"
    Mozart........1756
    Schubert......1797
1685 <= Number < 1797
    Bach..........1685
    Mozart........1756
Get 1756
    Mozart........1756
Get 1800
Get "Schubert"
    Schubert......1797
Get "Beethoven"
Has 1756
    true
Has 1770
    false
Index count of "Mozart"
    2
Terminated
Example (Basic)
package main

import (
	"fmt"
	"github.com/jung-kurt/recmgr"
)

func main() {
	var grp recmgr.GrpType
	type person struct {
		name string
		num  int
	}
	personList := []person{
		{"Athos", 1},
		{"Porthos", 2},
		{"Aramis", 3}}
	idxName := grp.Index(4, func(a, b interface{}) bool {
		return a.(*person).name < b.(*person).name
	})
	idxNum := grp.Index(4, func(a, b interface{}) bool {
		return a.(*person).num < b.(*person).num
	})
	for j := range personList {
		grp.ReplaceOrInsert(&personList[j])
	}
	print := func(recPtr interface{}) bool {
		p := recPtr.(*person)
		fmt.Printf("    %-8s %2d\n", p.name, p.num)
		return true
	}
	fmt.Printf("Name order (%d)\n", idxName.Len())
	idxName.Ascend(print)
	fmt.Printf("Number order (%d)\n", idxNum.Len())
	idxNum.Ascend(print)
}
Output:
Name order (3)
    Aramis    3
    Athos     1
    Porthos   2
Number order (3)
    Athos     1
    Porthos   2
    Aramis    3

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type GrpType

type GrpType struct {
	// contains filtered or unexported fields
}

GrpType aggregates a number of btree indexes. Adding and deleting records is done with instances of this type and operates on all indexes. Values of this type require no special initialization before use. Its methods are safe for concurrent goroutine use.

func (*GrpType) Delete

func (grp *GrpType) Delete(recPtr interface{}) (count int)

Delete removes all keys of the record pointed to by recPtr from the record manager. The referenced record is not modified. All fields involved in each of the indexes must be specified. A convenient way to do this is to pass Delete() the result of Get() since only one key has to be fully specified. This method returns zero if recPtr is nil.

func (*GrpType) Has

func (grp *GrpType) Has(recPtr interface{}) (count int)

Has returns the number of indexes that contain a key for the record specified by recPtr. Each key field used in every index must be assigned. Zero is returned if recPtr is nil.

func (*GrpType) Index

func (grp *GrpType) Index(degree int, less func(aPtr, bPtr interface{}) bool) (idx IndexType)

Index adds an index to the record manager instance.

degree specifies the underlying btree degree.

less is a function that should return true if the record pointed to by aPtr sorts less than the record pointed to by bPtr.

This function should be called, once for each index, before adding any records to the manager, that is, before calling ReplaceOrInsert().

func (*GrpType) ReplaceOrInsert

func (grp *GrpType) ReplaceOrInsert(recPtr interface{})

ReplaceOrInsert inserts, or replaces if already present, a record reference to each of the underlying btree indexes. No action is taken if recPtr is nil.

type IndexType

type IndexType struct {
	// contains filtered or unexported fields
}

IndexType associates a record collection with a record comparison function. A value of this type is used to access records in index order. Its methods are safe for concurrent goroutine use.

func (IndexType) Ascend

func (idx IndexType) Ascend(fnc VisitFncType)

Ascend calls fnc for every value in the collection, that is, [first, last], in the order associated with idx. The traversal is terminated if fnc returns false.

func (IndexType) AscendGreaterOrEqual

func (idx IndexType) AscendGreaterOrEqual(gePtr interface{}, fnc VisitFncType)

AscendGreaterOrEqual calls fnc for every value in the collection greater than or equal to the value pointed to by gePtr, that is, [gePtr, last], in the order associated with idx. The traversal is terminated if fnc returns false. All key fields needed by idx must be assigned in the value pointed to by gePtr.

func (IndexType) AscendGreaterOrEqualList

func (idx IndexType) AscendGreaterOrEqualList(gePtr interface{}) (list []interface{})

AscendGreaterOrEqualList returns a slice with every value in the collection greater than or equal to the value pointed to by gePtr, that is, [gePtr, last], in the order associated with idx. All key fields needed by idx must be assigned in the value pointed to by gePtr.

func (IndexType) AscendLessThan

func (idx IndexType) AscendLessThan(ltPtr interface{}, fnc VisitFncType)

AscendLessThan calls fnc for every value in the collection less than the value pointed to by ltPtr, that is, [first, ltPtr), in the order determined by idx. The traversal is terminated if fnc returns false. All key fields needed by idx must be assigned in the value pointed to by ltPtr.

func (IndexType) AscendLessThanList

func (idx IndexType) AscendLessThanList(ltPtr interface{}) (list []interface{})

AscendLessThanList returns a slice with every value in the collection less than the value pointed to by ltPtr, that is, [first, ltPtr), in the order associated with idx. All key fields needed by idx must be assigned in the value pointed to by ltPtr.

func (IndexType) AscendList

func (idx IndexType) AscendList() (list []interface{})

AscendList returns a slice of record pointers for every value in the collection in the order associated with idx.

func (IndexType) AscendRange

func (idx IndexType) AscendRange(gePtr, ltPtr interface{}, fnc VisitFncType)

AscendRange calls fnc for every value in the collection greater than or equal to the value pointed to by gePtr and less than the value pointed to by ltPtr, that is, [gePtr, lePtr), in the order specified by idx. The traversal is terminated if fnc returns false. All key fields needed by idx must be assigned in the values pointed to by gePtr and ltPtr.

func (IndexType) AscendRangeList

func (idx IndexType) AscendRangeList(gePtr, ltPtr interface{}) (list []interface{})

AscendRangeList returns a slice with every value in the collection greater than or equal to the value pointed to by gePtr and less than the value pointed to by ltPtr, that is, [gePtr, lePtr), in the order specified by idx. All key fields needed by idx must be assigned in the values pointed to by gePtr and ltPtr.

func (IndexType) Get

func (idx IndexType) Get(keyPtr interface{}) (recPtr interface{})

Get retrieves the value associated with the key specified by keyPtr. All key fields needed by idx must be assigned in the value pointed to by keyPtr. If the value cannot be located, nil is returned.

func (IndexType) Has

func (idx IndexType) Has(keyPtr interface{}) (ok bool)

Has returns true if the value associated with the key specified by keyPtr is present, false otherwise. All key fields needed by idx must be assigned in the value pointed to by keyPtr.

func (IndexType) Len

func (idx IndexType) Len() (count int)

Len returns the number of items in the btree associated with idx.

type VisitFncType

type VisitFncType func(recPtr interface{}) bool

VisitFncType defines the application function that will be called by the record manager library when traversing a record collection. The boolean false value is returned to terminate the traversal.

Jump to

Keyboard shortcuts

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