You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dorm/vendor/modernc.org/db/slist.go

161 lines
3.9 KiB

// Copyright 2017 The DB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package db // import "modernc.org/db"
const (
oSListNext = 8 * iota // int64 0 8
oSListData // [dataSize]byte 8 dataSize
)
// SList is a node of a single linked list.
type SList struct {
*DB
Off int64 // Location in the database. R/O
}
// NewSList returns a newly allocated SList or an error, if any. The datasize
// parameter is the fixed size of data associated with the list node. To
// get/set the node data, use the ReadAt/WriteAt methods of db, using
// SList.DataOff() as the offset. Reading or writing more than datasize data at
// DataOff() is undefined behavior and may irreparably corrupt the database.
//
// The result of NewSList is not a part of any list.
func (db *DB) NewSList(dataSize int64) (SList, error) {
off, err := db.Alloc(oSListData + dataSize)
if err != nil {
return SList{}, err
}
r, err := db.OpenSList(off)
if err != nil {
return SList{}, err
}
return r, r.setNext(0)
}
func (l SList) setNext(off int64) error { return l.w8(l.Off+oSListNext, off) }
// OpenSList returns an existing SList found at offset off or an error, of any.
// The off argument must have been acquired from NewSList.
func (db *DB) OpenSList(off int64) (SList, error) { return SList{db, off}, nil }
// DataOff returns the offset in db at which data of l are located.
func (l SList) DataOff() int64 { return l.Off + oSListData }
// Next returns the offset of the next node of l.
func (l SList) Next() (int64, error) { return l.r8(l.Off + oSListNext) }
// InsertAfter inserts l after the SList node at off. Node l must not be
// already a part of any list.
func (l SList) InsertAfter(off int64) error {
n, err := l.OpenSList(off)
if err != nil {
return err
}
afterNext, err := n.Next()
if err != nil {
return err
}
if err = n.setNext(l.Off); err != nil {
return err
}
return l.setNext(afterNext)
}
// InsertBefore inserts l before the SList node at off. If the SList node at
// off is linked to from an SList node at prev, the prev argument must reflect
// that, otherwise prev must be zero. Node l must not be already a part of any
// list.
func (l SList) InsertBefore(prev, off int64) error {
n, err := l.OpenSList(off)
if err != nil {
return err
}
if prev != 0 {
p, err := l.OpenSList(prev)
if err != nil {
return err
}
if err := p.setNext(l.Off); err != nil {
return err
}
}
return l.setNext(n.Off)
}
// Remove removes l from a list. If l is linked to from an SList node at prev,
// the prev argument must reflect that, otherwise prev must be zero.
//
// The free function may be nil, otherwise it's called with the result of
// l.DataOff() before removing l.
func (l SList) Remove(prev int64, free func(off int64) error) error {
if free != nil {
if err := free(l.DataOff()); err != nil {
return err
}
}
if prev != 0 {
next, err := l.Next()
if err != nil {
return err
}
p, err := l.OpenSList(prev)
if err != nil {
return err
}
if err := p.setNext(next); err != nil {
return err
}
}
return l.Free(l.Off)
}
// RemoveToLast removes all nodes from a list starting at l to the end of the
// list. If l is linked to from an SList node at prev, the prev argument must
// reflect that, otherwise prev must be zero.
//
// The free function may be nil, otherwise it's called with the result of
// l.DataOff() before removing l.
func (l SList) RemoveToLast(prev int64, free func(off int64) error) error {
if prev != 0 {
p, err := l.OpenSList(prev)
if err != nil {
return err
}
if err := p.setNext(0); err != nil {
return err
}
}
for l.Off != 0 {
if free != nil {
if err := free(l.DataOff()); err != nil {
return err
}
}
next, err := l.Next()
if err != nil {
return err
}
if err := l.Free(l.Off); err != nil {
return err
}
l.Off = next
}
return nil
}