aboutsummaryrefslogtreecommitdiff
path: root/commitgraph_read_access.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-01-30 15:46:49 +0100
committerGravatar Runxi Yu2026-01-30 15:46:49 +0100
commit1ea061c92ca6ad435c00bea458b8f24a5e1a822a (patch)
tree1ca3e0455546c57cedbb017c24a2ef0da0397318 /commitgraph_read_access.go
parentREADME: Add writing thin packs to the list of things to do (diff)
signatureNo signature
commitgraph: Add basic commit-graph implementation
Diffstat (limited to 'commitgraph_read_access.go')
-rw-r--r--commitgraph_read_access.go124
1 files changed, 124 insertions, 0 deletions
diff --git a/commitgraph_read_access.go b/commitgraph_read_access.go
new file mode 100644
index 00000000..6757cb1d
--- /dev/null
+++ b/commitgraph_read_access.go
@@ -0,0 +1,124 @@
+package furgit
+
+import (
+ "encoding/binary"
+
+ "codeberg.org/lindenii/furgit/internal/bloom"
+)
+
+const (
+ commitGraphParentNone = 0x70000000
+ commitGraphParentExtraMask = 0x80000000
+ commitGraphParentLastMask = 0x7fffffff
+
+ correctedGenerationOverflow = 0x80000000
+)
+
+type commitGraphCommit struct {
+ Position uint32
+ Tree Hash
+ Parents []uint32
+ CommitTime uint64
+ Generation uint64
+ Graph *commitGraph
+ graphLexPos uint32
+}
+
+func commitGraphAppendParent(parents []uint32, g *commitGraph, edge uint32) ([]uint32, error) {
+ if edge == commitGraphParentNone {
+ return parents, nil
+ }
+ if (edge & commitGraphParentExtraMask) == 0 {
+ return append(parents, edge), nil
+ }
+ if g.chunkExtraEdges == nil {
+ return nil, ErrInvalidObject
+ }
+ idx := edge & commitGraphParentLastMask
+ for {
+ off := int(idx) * 4
+ if off+4 > len(g.chunkExtraEdges) {
+ return nil, ErrInvalidObject
+ }
+ val := binary.BigEndian.Uint32(g.chunkExtraEdges[off : off+4])
+ parents = append(parents, val&commitGraphParentLastMask)
+ idx++
+ if (val & commitGraphParentExtraMask) != 0 {
+ break
+ }
+ }
+ return parents, nil
+}
+
+func (cg *commitGraph) CommitPosition(id Hash) (uint32, bool) {
+ return cg.lookupOID(id)
+}
+
+func (cg *commitGraph) CommitAt(pos uint32) (*commitGraphCommit, error) {
+ return cg.commitDataAt(pos)
+}
+
+func (cg *commitGraph) OIDAt(pos uint32) (Hash, error) {
+ return cg.loadOID(pos)
+}
+
+func (c *commitGraphCommit) HasBloom() bool {
+ return c != nil && c.Graph != nil && c.Graph.chunkBloomIndex != nil && c.Graph.chunkBloomData != nil
+}
+
+func (cg *commitGraph) BloomSettings() *bloom.Settings {
+ if cg == nil {
+ return nil
+ }
+ return cg.bloomSettings
+}
+
+func (cg *commitGraph) BloomFilter(pos uint32) (*bloom.Filter, bool) {
+ g := cg
+ for g != nil && pos < g.numCommitsInBase {
+ g = g.base
+ }
+ if g == nil || g.chunkBloomIndex == nil || g.chunkBloomData == nil || g.bloomSettings == nil {
+ return nil, false
+ }
+ if pos >= g.numCommits+g.numCommitsInBase {
+ return nil, false
+ }
+ lex := pos - g.numCommitsInBase
+ if int(lex)*4+4 > len(g.chunkBloomIndex) {
+ return nil, false
+ }
+ end := binary.BigEndian.Uint32(g.chunkBloomIndex[int(lex)*4:])
+ var start uint32
+ if lex > 0 {
+ start = binary.BigEndian.Uint32(g.chunkBloomIndex[int(lex-1)*4:])
+ }
+ if end < start {
+ return nil, false
+ }
+ if int(end) > len(g.chunkBloomData)-bloom.DataHeaderSize ||
+ int(start) > len(g.chunkBloomData)-bloom.DataHeaderSize {
+ return nil, false
+ }
+ data := g.chunkBloomData[bloom.DataHeaderSize+start : bloom.DataHeaderSize+end]
+ return &bloom.Filter{Data: data, Version: g.bloomSettings.HashVersion}, true
+}
+
+func (c *commitGraphCommit) BloomFilter() (*bloom.Filter, *bloom.Settings, bool) {
+ if c == nil || c.Graph == nil {
+ return nil, nil, false
+ }
+ filter, ok := c.Graph.BloomFilter(c.Position)
+ if !ok {
+ return nil, nil, false
+ }
+ return filter, c.Graph.bloomSettings, true
+}
+
+func (c *commitGraphCommit) ChangedPathMightContain(path []byte) bool {
+ filter, settings, ok := c.BloomFilter()
+ if !ok {
+ return false
+ }
+ return filter.MightContain(path, settings)
+}