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.
161 lines
3.9 KiB
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
|
|
}
|