1
0
Fork 0
golang-forgejo-f3-gof3/tree/memory/memory.go

351 lines
7.9 KiB
Go
Raw Permalink Normal View History

// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package memory
import (
"context"
"fmt"
"code.forgejo.org/f3/gof3/v3/f3"
"code.forgejo.org/f3/gof3/v3/id"
"code.forgejo.org/f3/gof3/v3/kind"
"code.forgejo.org/f3/gof3/v3/logger"
"code.forgejo.org/f3/gof3/v3/options"
options_logger "code.forgejo.org/f3/gof3/v3/options/logger"
"code.forgejo.org/f3/gof3/v3/path"
"code.forgejo.org/f3/gof3/v3/tree/generic"
)
type IDAllocatorInterface interface {
allocateID(id string) string
isNull() bool
}
type idAllocatorGenerator struct {
prefix string
lastID rune
}
func NewIDAllocatorGenerator(prefix string) IDAllocatorInterface {
return &idAllocatorGenerator{
prefix: prefix,
lastID: 'A',
}
}
func (o *idAllocatorGenerator) allocateID(string) string {
r := fmt.Sprintf("%s-%c", o.prefix, o.lastID)
o.lastID++
return r
}
func (o *idAllocatorGenerator) isNull() bool { return false }
type idAllocatorNull struct{}
func (o *idAllocatorNull) allocateID(id string) string { return id }
func (o *idAllocatorNull) isNull() bool { return true }
func NewIDAllocatorNull() IDAllocatorInterface {
return &idAllocatorNull{}
}
type memoryOptions struct {
options.Options
options_logger.OptionsLogger
IDAllocator IDAllocatorInterface
}
func NewOptions(idAllocator IDAllocatorInterface) options.Interface {
opts := &memoryOptions{}
opts.IDAllocator = idAllocator
opts.SetName("memory")
l := logger.NewLogger()
l.SetLevel(logger.Trace)
opts.SetLogger(l)
return opts
}
type memoryStorage struct {
idAllocator IDAllocatorInterface
root *memoryStorageNode
}
func newmemoryStorage(opts options.Interface) *memoryStorage {
return &memoryStorage{
idAllocator: opts.(*memoryOptions).IDAllocator,
}
}
func (o *memoryStorage) newStorageNode(id string) *memoryStorageNode {
return &memoryStorageNode{
storage: o,
f: NewFormat(o.idAllocator.allocateID(id)),
children: make(map[string]*memoryStorageNode),
}
}
func (o *memoryStorage) Find(path path.PathString) *memoryStorageNode {
p := path.Elements()
fmt.Printf("memoryStorage Find %s\n", path.Join())
current := o.root
for {
fmt.Printf(" memoryStorage Find lookup '%s'\n", current.f.GetID())
if current.f.GetID() != p[0] {
panic("")
}
p = p[1:]
if len(p) == 0 {
return current
}
if next, ok := current.children[p[0]]; ok {
current = next
} else {
return nil
}
}
}
type memoryStorageNode struct {
storage *memoryStorage
f *FormatMemory
children map[string]*memoryStorageNode
}
type treeDriver struct {
generic.NullTreeDriver
storage *memoryStorage
allocateID bool
}
func newTreeDriver(opts options.Interface) *treeDriver {
tree := &treeDriver{
storage: newmemoryStorage(opts),
allocateID: !opts.(*memoryOptions).IDAllocator.isNull(),
}
tree.Init()
return tree
}
func (o *treeDriver) AllocateID() bool { return o.allocateID }
func (o *treeDriver) Factory(ctx context.Context, kind kind.Kind) generic.NodeDriverInterface {
return &Driver{}
}
type Driver struct {
generic.NullDriver
f *FormatMemory
}
type FormatMemory struct {
f3.Common
Ref *f3.Reference
Content string
}
func NewFormat(id string) *FormatMemory {
f := &FormatMemory{}
f.Ref = f3.NewReference("")
f.Content = "????"
f.SetID(id)
return f
}
func (o *FormatMemory) GetReferences() f3.References {
references := o.Common.GetReferences()
if o.Ref.Get() != "" {
references = append(references, o.Ref)
}
return references
}
func (o *Driver) NewFormat() f3.Interface {
return &FormatMemory{}
}
func (o *Driver) ToFormat() f3.Interface {
if o == nil || o.f == nil {
return o.NewFormat()
}
return &FormatMemory{
Common: o.f.Common,
Ref: o.f.Ref,
Content: o.f.Content,
}
}
func (o *Driver) FromFormat(f f3.Interface) {
m := f.(*FormatMemory)
o.f = &FormatMemory{
Common: m.Common,
Ref: m.Ref,
Content: m.Content,
}
}
func (o *Driver) Equals(ctx context.Context, other generic.NodeInterface) bool {
switch i := other.GetDriver().(type) {
case *Driver:
return o.f.Content == i.f.Content
default:
return false
}
}
func (o *Driver) String() string {
if o.f == nil {
return "<nil>"
}
return o.f.Content
}
func (o *Driver) Get(ctx context.Context) bool {
node := o.GetNode()
o.Trace("id '%s' '%s'", node.GetID(), node.GetCurrentPath().ReadableString())
storage := o.getStorage(node, node.GetCurrentPath())
if storage != nil {
o.f = storage.f
}
node.List(ctx)
return true
}
func (o *Driver) Put(ctx context.Context) id.NodeID {
return o.upsert(ctx)
}
func (o *Driver) Patch(ctx context.Context) {
o.upsert(ctx)
}
func (o *Driver) upsert(ctx context.Context) id.NodeID {
node := o.GetNode()
path := node.GetParent().GetCurrentPath()
storageParent := o.getStorage(node, path)
i := node.GetID()
o.Trace("node id '%s'", i)
if existing, ok := storageParent.children[i.String()]; ok {
o.Trace("update %s content=%s ref=%s", node.GetCurrentPath().ReadableString(), o.f.Content, o.f.Ref)
existing.f = o.f
} else {
storageChild := storageParent.storage.newStorageNode(i.String())
storageID := storageChild.f.GetID()
storageParent.children[storageID] = storageChild
i = id.NewNodeID(storageID)
if o.f == nil {
o.f = storageChild.f
} else {
o.f.SetID(storageChild.f.GetID())
}
o.Trace("create '%s' '%s'", node.GetCurrentPath().ReadableString(), i)
}
return i
}
func (o *Driver) Delete(ctx context.Context) {
node := o.GetNode()
storage := o.getStorage(node, node.GetParent().GetCurrentPath())
if storage != nil && storage.children != nil {
id := node.GetID().String()
delete(storage.children, id)
}
}
func (o *Driver) getStorage(node generic.NodeInterface, path path.Path) *memoryStorageNode {
storage := node.GetTree().GetDriver().(*treeDriver).storage
return storage.Find(path.PathString())
}
func (o *Driver) ListPage(ctx context.Context, page int) generic.ChildrenSlice {
node := o.GetNode()
o.Trace("'%s'", node.GetCurrentPath().ReadableString())
storage := o.getStorage(node, node.GetCurrentPath())
children := generic.NewChildrenSlice(0)
if storage != nil {
for i := range storage.children {
node := node.CreateChild(context.Background())
childID := id.NewNodeID(i)
node.SetID(childID)
children = append(children, node)
}
}
return children
}
func (o *Driver) GetIDFromName(ctx context.Context, content string) id.NodeID {
node := o.GetNode()
o.Trace("'%s'", node.GetCurrentPath().ReadableString())
storage := o.getStorage(node, node.GetCurrentPath())
if storage != nil {
for i, child := range storage.children {
if child.f.Content == content {
o.Trace("found '%s'", i)
return id.NewNodeID(i)
}
}
}
return id.NilID
}
type treeMemory struct {
generic.Tree
}
func newTreeMemory(ctx context.Context, opts options.Interface) generic.TreeInterface {
t := &treeMemory{}
t.Init(t, opts)
t.GetLogger().SetLevel(logger.Trace)
t.Register(kind.KindNil, func(ctx context.Context, kind kind.Kind) generic.NodeInterface {
return generic.NewNode()
})
treeDriver := newTreeDriver(opts)
t.SetDriver(treeDriver)
f := NewFormat("")
f.Content = "ROOT"
storage := treeDriver.storage
storage.root = &memoryStorageNode{
storage: storage,
f: f,
children: make(map[string]*memoryStorageNode),
}
root := t.Factory(ctx, kind.KindRoot)
root.FromFormat(f)
t.SetRoot(root)
return t
}
func SetContent(node generic.NodeInterface, content string) {
f := node.GetDriver().ToFormat().(*FormatMemory)
f.Content = content
node.FromFormat(f)
}
func GetContent(node generic.NodeInterface) string {
return node.GetDriver().ToFormat().(*FormatMemory).Content
}
func SetRef(node generic.NodeInterface, ref string) {
f := node.GetDriver().ToFormat().(*FormatMemory)
f.Ref = f3.NewReference(ref)
node.FromFormat(f)
}
func GetRef(node generic.NodeInterface) string {
return node.GetDriver().ToFormat().(*FormatMemory).Ref.Get()
}
func init() {
generic.RegisterFactory("memory", newTreeMemory)
}