gitlab-org--gitlab-foss/workhorse/internal/lsif_transformer/parser/references.go

111 lines
2.3 KiB
Go

package parser
import (
"strconv"
)
type ReferencesOffset struct {
Id Id
Len int32
}
type References struct {
Items *cache
Offsets *cache
CurrentOffsetId Id
}
type SerializedReference struct {
Path string `json:"path"`
}
func NewReferences() (*References, error) {
items, err := newCache("references", Item{})
if err != nil {
return nil, err
}
offsets, err := newCache("references-offsets", ReferencesOffset{})
if err != nil {
return nil, err
}
return &References{
Items: items,
Offsets: offsets,
CurrentOffsetId: 0,
}, nil
}
// Store is responsible for keeping track of references that will be used when
// serializing in `For`.
//
// The references are stored in a file to cache them. It is like
// `map[Id][]Item` (where `Id` is `refId`) but relies on caching the array and
// its offset in files for storage to reduce RAM usage. The items can be
// fetched by calling `getItems`.
func (r *References) Store(refId Id, references []Item) error {
size := len(references)
if size == 0 {
return nil
}
items := append(r.getItems(refId), references...)
err := r.Items.SetEntry(r.CurrentOffsetId, items)
if err != nil {
return err
}
size = len(items)
r.Offsets.SetEntry(refId, ReferencesOffset{Id: r.CurrentOffsetId, Len: int32(size)})
r.CurrentOffsetId += Id(size)
return nil
}
func (r *References) For(docs map[Id]string, refId Id) []SerializedReference {
references := r.getItems(refId)
if references == nil {
return nil
}
var serializedReferences []SerializedReference
for _, reference := range references {
serializedReference := SerializedReference{
Path: docs[reference.DocId] + "#L" + strconv.Itoa(int(reference.Line)),
}
serializedReferences = append(serializedReferences, serializedReference)
}
return serializedReferences
}
func (r *References) Close() error {
for _, err := range []error{
r.Items.Close(),
r.Offsets.Close(),
} {
if err != nil {
return err
}
}
return nil
}
func (r *References) getItems(refId Id) []Item {
var offset ReferencesOffset
if err := r.Offsets.Entry(refId, &offset); err != nil || offset.Len == 0 {
return nil
}
items := make([]Item, offset.Len)
if err := r.Items.Entry(offset.Id, &items); err != nil {
return nil
}
return items
}