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 ¶
- type GrpType
- type IndexType
- func (idx IndexType) Ascend(fnc VisitFncType)
- func (idx IndexType) AscendGreaterOrEqual(gePtr interface{}, fnc VisitFncType)
- func (idx IndexType) AscendGreaterOrEqualList(gePtr interface{}) (list []interface{})
- func (idx IndexType) AscendLessThan(ltPtr interface{}, fnc VisitFncType)
- func (idx IndexType) AscendLessThanList(ltPtr interface{}) (list []interface{})
- func (idx IndexType) AscendList() (list []interface{})
- func (idx IndexType) AscendRange(gePtr, ltPtr interface{}, fnc VisitFncType)
- func (idx IndexType) AscendRangeList(gePtr, ltPtr interface{}) (list []interface{})
- func (idx IndexType) Get(keyPtr interface{}) (recPtr interface{})
- func (idx IndexType) Has(keyPtr interface{}) (ok bool)
- func (idx IndexType) Len() (count int)
- type VisitFncType
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 ¶
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 ¶
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 ¶
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.
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.
