aboutsummaryrefslogtreecommitdiff
path: root/commitquery
diff options
context:
space:
mode:
Diffstat (limited to 'commitquery')
-rw-r--r--commitquery/commit_data.go (renamed from commitquery/commit.go)0
-rw-r--r--commitquery/errors.go1
-rw-r--r--commitquery/mark_bits.go17
-rw-r--r--commitquery/marks.go102
-rw-r--r--commitquery/node_commit_time.go1
-rw-r--r--commitquery/node_compare.go2
-rw-r--r--commitquery/node_generation.go4
-rw-r--r--commitquery/node_id.go1
-rw-r--r--commitquery/node_parent.go27
-rw-r--r--commitquery/node_parents.go6
-rw-r--r--commitquery/parent_ref.go13
-rw-r--r--commitquery/queries_acquire.go1
-rw-r--r--commitquery/queries_is_ancestor.go (renamed from commitquery/queries_ancestor.go)0
-rw-r--r--commitquery/queries_is_ancestor_integration_test.go (renamed from commitquery/ancestor_integration_test.go)0
-rw-r--r--commitquery/queries_is_ancestor_unit_test.go (renamed from commitquery/ancestor_unit_test.go)0
-rw-r--r--commitquery/queries_merge_base.go11
-rw-r--r--commitquery/queries_merge_bases.go (renamed from commitquery/queries_mergebase.go)8
-rw-r--r--commitquery/queries_merge_bases_integration_test.go (renamed from commitquery/mergebase_integration_test.go)0
-rw-r--r--commitquery/queries_merge_bases_unit_test.go (renamed from commitquery/mergebase_unit_test.go)0
-rw-r--r--commitquery/queries_release.go1
-rw-r--r--commitquery/query.go23
-rw-r--r--commitquery/query_collect_marked_results.go20
-rw-r--r--commitquery/query_ensure_loaded.go14
-rw-r--r--commitquery/query_has_marks.go11
-rw-r--r--commitquery/query_is_ancestor.go (renamed from commitquery/ancestor.go)1
-rw-r--r--commitquery/query_load_by_graph_pos.go8
-rw-r--r--commitquery/query_load_by_oid.go (renamed from commitquery/load.go)13
-rw-r--r--commitquery/query_load_commit_at_graph_pos.go (renamed from commitquery/graph_pos.go)45
-rw-r--r--commitquery/query_mark_phase.go36
-rw-r--r--commitquery/query_marks_get.go6
-rw-r--r--commitquery/query_merge_base.go17
-rw-r--r--commitquery/query_merge_bases.go (renamed from commitquery/merge_bases.go)44
-rw-r--r--commitquery/query_merge_bases_internal.go34
-rw-r--r--commitquery/query_new.go (renamed from commitquery/reset.go)24
-rw-r--r--commitquery/query_paint_down_to_common.go (renamed from commitquery/node_paint_down_to_common.go)1
-rw-r--r--commitquery/query_reduce.go (renamed from commitquery/reduce.go)6
-rw-r--r--commitquery/query_reset.go10
-rw-r--r--commitquery/query_resolve_commitish.go16
-rw-r--r--commitquery/query_resolve_graph_pos.go40
-rw-r--r--commitquery/query_resolve_oid.go (renamed from commitquery/resolve.go)15
-rw-r--r--commitquery/query_resolve_parent.go10
-rw-r--r--commitquery/query_set_clear_marks.go22
42 files changed, 334 insertions, 277 deletions
diff --git a/commitquery/commit.go b/commitquery/commit_data.go
index dff6a91c..dff6a91c 100644
--- a/commitquery/commit.go
+++ b/commitquery/commit_data.go
diff --git a/commitquery/errors.go b/commitquery/errors.go
index e99011d0..0006c86b 100644
--- a/commitquery/errors.go
+++ b/commitquery/errors.go
@@ -2,4 +2,5 @@ package commitquery
import "errors"
+// errBadGenerationOrder reports an invalid priority-queue ordering.
var errBadGenerationOrder = errors.New("commitquery: priority queue violated generation ordering")
diff --git a/commitquery/mark_bits.go b/commitquery/mark_bits.go
new file mode 100644
index 00000000..b10c833b
--- /dev/null
+++ b/commitquery/mark_bits.go
@@ -0,0 +1,17 @@
+package commitquery
+
+// markBits stores one set of traversal marks on one node.
+type markBits uint8
+
+// markLeft, markRight, markStale, and markResult track traversal state.
+const (
+ markLeft markBits = 1 << iota
+ markRight
+ markStale
+ markResult
+)
+
+// allMarks is the union of all defined mark bits.
+const (
+ allMarks = markLeft | markRight | markStale | markResult
+)
diff --git a/commitquery/marks.go b/commitquery/marks.go
deleted file mode 100644
index 2d0b013f..00000000
--- a/commitquery/marks.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package commitquery
-
-// Marks returns the mark bits of one internal node.
-func (query *query) marks(idx nodeIndex) markBits {
- return query.nodes[idx].marks
-}
-
-// HasAnyMarks reports whether one internal node has any requested bit.
-func (query *query) hasAnyMarks(idx nodeIndex, bits markBits) bool {
- return query.nodes[idx].marks&bits != 0
-}
-
-// HasAllMarks reports whether one internal node already has all requested bits.
-func (query *query) hasAllMarks(idx nodeIndex, bits markBits) bool {
- return query.nodes[idx].marks&bits == bits
-}
-
-// SetMarks ORs one set of mark bits into one internal node.
-func (query *query) setMarks(idx nodeIndex, bits markBits) {
- newBits := bits &^ query.nodes[idx].marks
- if newBits == 0 {
- return
- }
-
- query.trackTouched(idx)
- query.nodes[idx].marks |= bits
-}
-
-// ClearMarks removes one set of mark bits from one internal node.
-func (query *query) clearMarks(idx nodeIndex, bits markBits) {
- if query.nodes[idx].marks&bits == 0 {
- return
- }
-
- query.trackTouched(idx)
- query.nodes[idx].marks &^= bits
-}
-
-// BeginMarkPhase starts one tracked mark-mutation phase.
-func (query *query) beginMarkPhase() {
- for _, idx := range query.touched {
- query.nodes[idx].marks = 0
- }
-
- query.markPhase++
- if query.markPhase == 0 {
- query.markPhase++
- for i := range query.nodes {
- query.nodes[i].touchedPhase = 0
- }
- }
-
- query.touched = query.touched[:0]
-}
-
-// ClearTouchedMarks clears the provided bits from all nodes touched in the
-// current mark phase.
-func (query *query) clearTouchedMarks(bits markBits) {
- for _, idx := range query.touched {
- query.nodes[idx].marks &^= bits
- }
-}
-
-func (query *query) trackTouched(idx nodeIndex) {
- if query.nodes[idx].touchedPhase == query.markPhase {
- return
- }
-
- query.nodes[idx].touchedPhase = query.markPhase
- query.touched = append(query.touched, idx)
-}
-
-func (query *query) collectMarkedResults() []nodeIndex {
- out := make([]nodeIndex, 0, 4)
-
- for _, idx := range query.touched {
- if !query.hasAnyMarks(idx, markResult) {
- continue
- }
-
- if query.hasAnyMarks(idx, markStale) {
- continue
- }
-
- out = append(out, idx)
- }
-
- return out
-}
-
-type markBits uint8
-
-const (
- markLeft markBits = 1 << iota
- markRight
- markStale
- markResult
-)
-
-const (
- allMarks = markLeft | markRight | markStale | markResult
-)
diff --git a/commitquery/node_commit_time.go b/commitquery/node_commit_time.go
index 3c42673d..07c1f4e8 100644
--- a/commitquery/node_commit_time.go
+++ b/commitquery/node_commit_time.go
@@ -1,5 +1,6 @@
package commitquery
+// commitTime returns one node's commit time.
func (query *query) commitTime(idx nodeIndex) int64 {
return query.nodes[idx].commitTime
}
diff --git a/commitquery/node_compare.go b/commitquery/node_compare.go
index 7ae984dc..cf072af2 100644
--- a/commitquery/node_compare.go
+++ b/commitquery/node_compare.go
@@ -2,7 +2,7 @@ package commitquery
import objectid "codeberg.org/lindenii/furgit/object/id"
-// Compare compares two internal nodes using merge-base queue ordering.
+// compare orders two internal nodes using merge-base queue ordering.
func (query *query) compare(left, right nodeIndex) int {
leftGeneration := query.effectiveGeneration(left)
rightGeneration := query.effectiveGeneration(right)
diff --git a/commitquery/node_generation.go b/commitquery/node_generation.go
index b04f3762..03283cf6 100644
--- a/commitquery/node_generation.go
+++ b/commitquery/node_generation.go
@@ -6,7 +6,7 @@ import (
objectid "codeberg.org/lindenii/furgit/object/id"
)
-// EffectiveGeneration returns one node's generation value.
+// effectiveGeneration returns one node's generation value.
func (query *query) effectiveGeneration(idx nodeIndex) uint64 {
if !query.nodes[idx].hasGeneration {
return generationInfinity
@@ -15,10 +15,12 @@ func (query *query) effectiveGeneration(idx nodeIndex) uint64 {
return query.nodes[idx].generation
}
+// generationInfinity sorts nodes without a known generation last.
const (
generationInfinity = uint64(math.MaxUint64)
)
+// compareByGeneration builds one comparator ordered by generation first.
func (query *query) compareByGeneration() func(nodeIndex, nodeIndex) int {
return func(left, right nodeIndex) int {
leftGeneration := query.effectiveGeneration(left)
diff --git a/commitquery/node_id.go b/commitquery/node_id.go
index c1d82f38..8ec0b126 100644
--- a/commitquery/node_id.go
+++ b/commitquery/node_id.go
@@ -2,6 +2,7 @@ package commitquery
import objectid "codeberg.org/lindenii/furgit/object/id"
+// id returns one node's object ID.
func (query *query) id(idx nodeIndex) objectid.ObjectID {
return query.nodes[idx].id
}
diff --git a/commitquery/node_parent.go b/commitquery/node_parent.go
deleted file mode 100644
index 17224701..00000000
--- a/commitquery/node_parent.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package commitquery
-
-import (
- commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read"
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
-
-// Parents returns resolved parent node indices for one internal node.
-func (query *query) parents(idx nodeIndex) []nodeIndex {
- return query.nodes[idx].parents
-}
-
-// parentRef references one commit parent.
-type parentRef struct {
- ID objectid.ObjectID
- GraphPos commitgraphread.Position
- HasGraphPos bool
-}
-
-// resolveParent resolves one parent descriptor to one internal node.
-func (query *query) resolveParent(parent parentRef) (nodeIndex, error) {
- if parent.HasGraphPos {
- return query.resolveGraphPos(parent.GraphPos)
- }
-
- return query.resolveOID(parent.ID)
-}
diff --git a/commitquery/node_parents.go b/commitquery/node_parents.go
new file mode 100644
index 00000000..a98a774f
--- /dev/null
+++ b/commitquery/node_parents.go
@@ -0,0 +1,6 @@
+package commitquery
+
+// parents returns resolved parent node indices for one internal node.
+func (query *query) parents(idx nodeIndex) []nodeIndex {
+ return query.nodes[idx].parents
+}
diff --git a/commitquery/parent_ref.go b/commitquery/parent_ref.go
new file mode 100644
index 00000000..08d224df
--- /dev/null
+++ b/commitquery/parent_ref.go
@@ -0,0 +1,13 @@
+package commitquery
+
+import (
+ commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read"
+ objectid "codeberg.org/lindenii/furgit/object/id"
+)
+
+// parentRef references one commit parent.
+type parentRef struct {
+ ID objectid.ObjectID
+ GraphPos commitgraphread.Position
+ HasGraphPos bool
+}
diff --git a/commitquery/queries_acquire.go b/commitquery/queries_acquire.go
index ac7b765c..2925010c 100644
--- a/commitquery/queries_acquire.go
+++ b/commitquery/queries_acquire.go
@@ -1,5 +1,6 @@
package commitquery
+// acquire removes one worker from the idle pool or allocates one new worker.
func (queries *Queries) acquire() *query {
queries.mu.Lock()
defer queries.mu.Unlock()
diff --git a/commitquery/queries_ancestor.go b/commitquery/queries_is_ancestor.go
index e2c955c6..e2c955c6 100644
--- a/commitquery/queries_ancestor.go
+++ b/commitquery/queries_is_ancestor.go
diff --git a/commitquery/ancestor_integration_test.go b/commitquery/queries_is_ancestor_integration_test.go
index 8db680e6..8db680e6 100644
--- a/commitquery/ancestor_integration_test.go
+++ b/commitquery/queries_is_ancestor_integration_test.go
diff --git a/commitquery/ancestor_unit_test.go b/commitquery/queries_is_ancestor_unit_test.go
index 8cb147a6..8cb147a6 100644
--- a/commitquery/ancestor_unit_test.go
+++ b/commitquery/queries_is_ancestor_unit_test.go
diff --git a/commitquery/queries_merge_base.go b/commitquery/queries_merge_base.go
new file mode 100644
index 00000000..28de7fe2
--- /dev/null
+++ b/commitquery/queries_merge_base.go
@@ -0,0 +1,11 @@
+package commitquery
+
+import objectid "codeberg.org/lindenii/furgit/object/id"
+
+// MergeBase reports one merge base between left and right, if any.
+func (queries *Queries) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) {
+ query := queries.acquire()
+ defer queries.release(query)
+
+ return query.MergeBase(left, right)
+}
diff --git a/commitquery/queries_mergebase.go b/commitquery/queries_merge_bases.go
index ff0aafb9..74c5054a 100644
--- a/commitquery/queries_mergebase.go
+++ b/commitquery/queries_merge_bases.go
@@ -11,11 +11,3 @@ func (queries *Queries) MergeBases(left, right objectid.ObjectID) ([]objectid.Ob
return query.MergeBases(left, right)
}
-
-// MergeBase reports one merge base between left and right, if any.
-func (queries *Queries) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) {
- query := queries.acquire()
- defer queries.release(query)
-
- return query.MergeBase(left, right)
-}
diff --git a/commitquery/mergebase_integration_test.go b/commitquery/queries_merge_bases_integration_test.go
index f19468eb..f19468eb 100644
--- a/commitquery/mergebase_integration_test.go
+++ b/commitquery/queries_merge_bases_integration_test.go
diff --git a/commitquery/mergebase_unit_test.go b/commitquery/queries_merge_bases_unit_test.go
index 4db4f548..4db4f548 100644
--- a/commitquery/mergebase_unit_test.go
+++ b/commitquery/queries_merge_bases_unit_test.go
diff --git a/commitquery/queries_release.go b/commitquery/queries_release.go
index 791b2f03..5d0b2fde 100644
--- a/commitquery/queries_release.go
+++ b/commitquery/queries_release.go
@@ -1,5 +1,6 @@
package commitquery
+// release resets one worker and returns it to the idle pool if there is room.
func (queries *Queries) release(q *query) {
q.resetForReuse()
diff --git a/commitquery/query.go b/commitquery/query.go
new file mode 100644
index 00000000..5f184a5f
--- /dev/null
+++ b/commitquery/query.go
@@ -0,0 +1,23 @@
+package commitquery
+
+import (
+ commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read"
+ objectid "codeberg.org/lindenii/furgit/object/id"
+ objectstore "codeberg.org/lindenii/furgit/object/store"
+)
+
+// query stores one mutable reusable worker and its cached node arena.
+//
+// Labels: MT-Unsafe.
+type query struct {
+ store objectstore.ReadingStore
+ graph *commitgraphread.Reader
+
+ nodes []node
+
+ byOID map[objectid.ObjectID]nodeIndex
+ byGraphPos map[commitgraphread.Position]nodeIndex
+
+ markPhase uint32
+ touched []nodeIndex
+}
diff --git a/commitquery/query_collect_marked_results.go b/commitquery/query_collect_marked_results.go
new file mode 100644
index 00000000..7139fb9b
--- /dev/null
+++ b/commitquery/query_collect_marked_results.go
@@ -0,0 +1,20 @@
+package commitquery
+
+// collectMarkedResults returns touched nodes marked as non-stale results.
+func (query *query) collectMarkedResults() []nodeIndex {
+ out := make([]nodeIndex, 0, 4)
+
+ for _, idx := range query.touched {
+ if !query.hasAnyMarks(idx, markResult) {
+ continue
+ }
+
+ if query.hasAnyMarks(idx, markStale) {
+ continue
+ }
+
+ out = append(out, idx)
+ }
+
+ return out
+}
diff --git a/commitquery/query_ensure_loaded.go b/commitquery/query_ensure_loaded.go
new file mode 100644
index 00000000..830e9b19
--- /dev/null
+++ b/commitquery/query_ensure_loaded.go
@@ -0,0 +1,14 @@
+package commitquery
+
+// ensureLoaded completes one node's metadata load if it is not loaded yet.
+func (query *query) ensureLoaded(idx nodeIndex) error {
+ if query.nodes[idx].loaded {
+ return nil
+ }
+
+ if query.nodes[idx].hasGraphPos {
+ return query.loadByGraphPos(idx)
+ }
+
+ return query.loadByOID(idx)
+}
diff --git a/commitquery/query_has_marks.go b/commitquery/query_has_marks.go
new file mode 100644
index 00000000..22f44bd4
--- /dev/null
+++ b/commitquery/query_has_marks.go
@@ -0,0 +1,11 @@
+package commitquery
+
+// hasAnyMarks reports whether one internal node has any requested bit.
+func (query *query) hasAnyMarks(idx nodeIndex, bits markBits) bool {
+ return query.nodes[idx].marks&bits != 0
+}
+
+// hasAllMarks reports whether one internal node already has all requested bits.
+func (query *query) hasAllMarks(idx nodeIndex, bits markBits) bool {
+ return query.nodes[idx].marks&bits == bits
+}
diff --git a/commitquery/ancestor.go b/commitquery/query_is_ancestor.go
index 6a43babb..c21892c8 100644
--- a/commitquery/ancestor.go
+++ b/commitquery/query_is_ancestor.go
@@ -20,6 +20,7 @@ func (query *query) IsAncestor(ancestor, descendant objectid.ObjectID) (bool, er
return query.isAncestor(ancestorIdx, descendantIdx)
}
+// isAncestor answers one ancestry query between two resolved internal nodes.
func (query *query) isAncestor(ancestor, descendant nodeIndex) (bool, error) {
if ancestor == descendant {
return true, nil
diff --git a/commitquery/query_load_by_graph_pos.go b/commitquery/query_load_by_graph_pos.go
new file mode 100644
index 00000000..718d99b5
--- /dev/null
+++ b/commitquery/query_load_by_graph_pos.go
@@ -0,0 +1,8 @@
+package commitquery
+
+// loadByGraphPos populates one node from a commit-graph position.
+func (query *query) loadByGraphPos(idx nodeIndex) error {
+ pos := query.nodes[idx].graphPos
+
+ return query.loadCommitAtGraphPos(idx, pos)
+}
diff --git a/commitquery/load.go b/commitquery/query_load_by_oid.go
index 076f3000..eb997b2d 100644
--- a/commitquery/load.go
+++ b/commitquery/query_load_by_oid.go
@@ -10,19 +10,6 @@ import (
objecttype "codeberg.org/lindenii/furgit/object/type"
)
-// ensureLoaded completes one node's metadata load if it has not been loaded yet.
-func (query *query) ensureLoaded(idx nodeIndex) error {
- if query.nodes[idx].loaded {
- return nil
- }
-
- if query.nodes[idx].hasGraphPos {
- return query.loadByGraphPos(idx)
- }
-
- return query.loadByOID(idx)
-}
-
// loadByOID populates one node from an object ID.
func (query *query) loadByOID(idx nodeIndex) error {
id := query.nodes[idx].id
diff --git a/commitquery/graph_pos.go b/commitquery/query_load_commit_at_graph_pos.go
index 6b5118b0..f63b6385 100644
--- a/commitquery/graph_pos.go
+++ b/commitquery/query_load_commit_at_graph_pos.go
@@ -2,50 +2,7 @@ package commitquery
import commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read"
-// resolveGraphPos resolves one commit-graph position to one internal query node.
-func (query *query) resolveGraphPos(pos commitgraphread.Position) (nodeIndex, error) {
- idx, ok := query.byGraphPos[pos]
- if ok {
- err := query.ensureLoaded(idx)
- if err != nil {
- return 0, err
- }
-
- return idx, nil
- }
-
- commit, err := query.graph.CommitAt(pos)
- if err != nil {
- return 0, err
- }
-
- idx, ok = query.byOID[commit.OID]
- if !ok {
- idx = query.newNode(commit.OID)
- query.byOID[commit.OID] = idx
- }
-
- query.byGraphPos[pos] = idx
- query.nodes[idx].graphPos = pos
- query.nodes[idx].hasGraphPos = true
-
- err = query.loadCommitAtGraphPos(idx, pos)
- if err != nil {
- delete(query.byGraphPos, pos)
-
- return 0, err
- }
-
- return idx, nil
-}
-
-// loadByGraphPos populates one node from a commit-graph position.
-func (query *query) loadByGraphPos(idx nodeIndex) error {
- pos := query.nodes[idx].graphPos
-
- return query.loadCommitAtGraphPos(idx, pos)
-}
-
+// loadCommitAtGraphPos populates one node from one commit-graph record.
func (query *query) loadCommitAtGraphPos(idx nodeIndex, pos commitgraphread.Position) error {
commit, err := query.graph.CommitAt(pos)
if err != nil {
diff --git a/commitquery/query_mark_phase.go b/commitquery/query_mark_phase.go
new file mode 100644
index 00000000..0814df38
--- /dev/null
+++ b/commitquery/query_mark_phase.go
@@ -0,0 +1,36 @@
+package commitquery
+
+// beginMarkPhase starts one tracked mark-mutation phase.
+func (query *query) beginMarkPhase() {
+ for _, idx := range query.touched {
+ query.nodes[idx].marks = 0
+ }
+
+ query.markPhase++
+ if query.markPhase == 0 {
+ query.markPhase++
+ for i := range query.nodes {
+ query.nodes[i].touchedPhase = 0
+ }
+ }
+
+ query.touched = query.touched[:0]
+}
+
+// clearTouchedMarks clears the provided bits from all nodes touched in the
+// current mark phase.
+func (query *query) clearTouchedMarks(bits markBits) {
+ for _, idx := range query.touched {
+ query.nodes[idx].marks &^= bits
+ }
+}
+
+// trackTouched records one node in the current mark phase.
+func (query *query) trackTouched(idx nodeIndex) {
+ if query.nodes[idx].touchedPhase == query.markPhase {
+ return
+ }
+
+ query.nodes[idx].touchedPhase = query.markPhase
+ query.touched = append(query.touched, idx)
+}
diff --git a/commitquery/query_marks_get.go b/commitquery/query_marks_get.go
new file mode 100644
index 00000000..28136d84
--- /dev/null
+++ b/commitquery/query_marks_get.go
@@ -0,0 +1,6 @@
+package commitquery
+
+// marks returns the mark bits of one internal node.
+func (query *query) marks(idx nodeIndex) markBits {
+ return query.nodes[idx].marks
+}
diff --git a/commitquery/query_merge_base.go b/commitquery/query_merge_base.go
new file mode 100644
index 00000000..e1ba3126
--- /dev/null
+++ b/commitquery/query_merge_base.go
@@ -0,0 +1,17 @@
+package commitquery
+
+import objectid "codeberg.org/lindenii/furgit/object/id"
+
+// MergeBase reports one merge base between left and right, if any.
+func (query *query) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) {
+ bases, err := query.MergeBases(left, right)
+ if err != nil {
+ return objectid.ObjectID{}, false, err
+ }
+
+ if len(bases) == 0 {
+ return objectid.ObjectID{}, false, nil
+ }
+
+ return bases[0], true, nil
+}
diff --git a/commitquery/merge_bases.go b/commitquery/query_merge_bases.go
index 281906f3..384ee019 100644
--- a/commitquery/merge_bases.go
+++ b/commitquery/query_merge_bases.go
@@ -43,47 +43,3 @@ func (query *query) MergeBases(left, right objectid.ObjectID) ([]objectid.Object
return out, nil
}
-
-// MergeBase reports one merge base between left and right, if any.
-func (query *query) MergeBase(left, right objectid.ObjectID) (objectid.ObjectID, bool, error) {
- bases, err := query.MergeBases(left, right)
- if err != nil {
- return objectid.ObjectID{}, false, err
- }
-
- if len(bases) == 0 {
- return objectid.ObjectID{}, false, nil
- }
-
- return bases[0], true, nil
-}
-
-func (query *query) mergeBases(left, right nodeIndex) ([]nodeIndex, error) {
- if left == right {
- return []nodeIndex{left}, nil
- }
-
- err := query.paintDownToCommon(left, []nodeIndex{right}, 0)
- if err != nil {
- return nil, err
- }
-
- candidates := query.collectMarkedResults()
-
- if len(candidates) <= 1 {
- slices.SortFunc(candidates, query.compare)
-
- return candidates, nil
- }
-
- query.clearTouchedMarks(allMarks)
-
- reduced, err := removeRedundant(query, candidates)
- if err != nil {
- return nil, err
- }
-
- slices.SortFunc(reduced, query.compare)
-
- return reduced, nil
-}
diff --git a/commitquery/query_merge_bases_internal.go b/commitquery/query_merge_bases_internal.go
new file mode 100644
index 00000000..2d133435
--- /dev/null
+++ b/commitquery/query_merge_bases_internal.go
@@ -0,0 +1,34 @@
+package commitquery
+
+import "slices"
+
+// mergeBases returns internal merge-base candidates for two resolved nodes.
+func (query *query) mergeBases(left, right nodeIndex) ([]nodeIndex, error) {
+ if left == right {
+ return []nodeIndex{left}, nil
+ }
+
+ err := query.paintDownToCommon(left, []nodeIndex{right}, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ candidates := query.collectMarkedResults()
+
+ if len(candidates) <= 1 {
+ slices.SortFunc(candidates, query.compare)
+
+ return candidates, nil
+ }
+
+ query.clearTouchedMarks(allMarks)
+
+ reduced, err := removeRedundant(query, candidates)
+ if err != nil {
+ return nil, err
+ }
+
+ slices.SortFunc(reduced, query.compare)
+
+ return reduced, nil
+}
diff --git a/commitquery/reset.go b/commitquery/query_new.go
index 465f05c1..722f049e 100644
--- a/commitquery/reset.go
+++ b/commitquery/query_new.go
@@ -6,19 +6,9 @@ import (
objectstore "codeberg.org/lindenii/furgit/object/store"
)
-type query struct {
- store objectstore.ReadingStore
- graph *commitgraphread.Reader
-
- nodes []node
-
- byOID map[objectid.ObjectID]nodeIndex
- byGraphPos map[commitgraphread.Position]nodeIndex
-
- markPhase uint32
- touched []nodeIndex
-}
-
+// newQuery builds one empty mutable worker over one object store and graph.
+//
+// Labels: Deps-Borrowed, Life-Parent.
func newQuery(store objectstore.ReadingStore, graph *commitgraphread.Reader) *query {
return &query{
store: store,
@@ -27,11 +17,3 @@ func newQuery(store objectstore.ReadingStore, graph *commitgraphread.Reader) *qu
byGraphPos: make(map[commitgraphread.Position]nodeIndex),
}
}
-
-func (query *query) resetForReuse() {
- for _, idx := range query.touched {
- query.nodes[idx].marks = 0
- }
-
- query.touched = query.touched[:0]
-}
diff --git a/commitquery/node_paint_down_to_common.go b/commitquery/query_paint_down_to_common.go
index 2fa24816..e152e159 100644
--- a/commitquery/node_paint_down_to_common.go
+++ b/commitquery/query_paint_down_to_common.go
@@ -2,6 +2,7 @@ package commitquery
import "codeberg.org/lindenii/furgit/internal/priorityqueue"
+// paintDownToCommon propagates left and right marks downward until common nodes.
func (query *query) paintDownToCommon(left nodeIndex, rights []nodeIndex, minGeneration uint64) error {
query.beginMarkPhase()
diff --git a/commitquery/reduce.go b/commitquery/query_reduce.go
index 46c3bf39..b7ea5df1 100644
--- a/commitquery/reduce.go
+++ b/commitquery/query_reduce.go
@@ -1,8 +1,6 @@
package commitquery
-import (
- "slices"
-)
+import "slices"
// removeRedundant removes redundant merge-base candidates.
func removeRedundant(query *query, candidates []nodeIndex) ([]nodeIndex, error) {
@@ -15,6 +13,7 @@ func removeRedundant(query *query, candidates []nodeIndex) ([]nodeIndex, error)
return removeRedundantNoGen(query, candidates)
}
+// removeRedundantNoGen removes redundant candidates without generation data.
func removeRedundantNoGen(query *query, candidates []nodeIndex) ([]nodeIndex, error) {
redundant := make([]bool, len(candidates))
work := make([]nodeIndex, 0, len(candidates)-1)
@@ -72,6 +71,7 @@ func removeRedundantNoGen(query *query, candidates []nodeIndex) ([]nodeIndex, er
return out, nil
}
+// removeRedundantWithGen removes redundant candidates using generation data.
func removeRedundantWithGen(query *query, candidates []nodeIndex) []nodeIndex {
sorted := append([]nodeIndex(nil), candidates...)
slices.SortFunc(sorted, query.compareByGeneration())
diff --git a/commitquery/query_reset.go b/commitquery/query_reset.go
new file mode 100644
index 00000000..11f7cb3e
--- /dev/null
+++ b/commitquery/query_reset.go
@@ -0,0 +1,10 @@
+package commitquery
+
+// resetForReuse clears transient state before one worker returns to the pool.
+func (query *query) resetForReuse() {
+ for _, idx := range query.touched {
+ query.nodes[idx].marks = 0
+ }
+
+ query.touched = query.touched[:0]
+}
diff --git a/commitquery/query_resolve_commitish.go b/commitquery/query_resolve_commitish.go
new file mode 100644
index 00000000..1b91c8bd
--- /dev/null
+++ b/commitquery/query_resolve_commitish.go
@@ -0,0 +1,16 @@
+package commitquery
+
+import (
+ "codeberg.org/lindenii/furgit/internal/peel"
+ objectid "codeberg.org/lindenii/furgit/object/id"
+)
+
+// resolveCommitish peels one commit-ish object ID and resolves the commit.
+func (query *query) resolveCommitish(id objectid.ObjectID) (nodeIndex, error) {
+ commitID, err := peel.ToCommit(query.store, id)
+ if err != nil {
+ return 0, err
+ }
+
+ return query.resolveOID(commitID)
+}
diff --git a/commitquery/query_resolve_graph_pos.go b/commitquery/query_resolve_graph_pos.go
new file mode 100644
index 00000000..dce8fc22
--- /dev/null
+++ b/commitquery/query_resolve_graph_pos.go
@@ -0,0 +1,40 @@
+package commitquery
+
+import commitgraphread "codeberg.org/lindenii/furgit/format/commitgraph/read"
+
+// resolveGraphPos resolves one commit-graph position to one internal query node.
+func (query *query) resolveGraphPos(pos commitgraphread.Position) (nodeIndex, error) {
+ idx, ok := query.byGraphPos[pos]
+ if ok {
+ err := query.ensureLoaded(idx)
+ if err != nil {
+ return 0, err
+ }
+
+ return idx, nil
+ }
+
+ commit, err := query.graph.CommitAt(pos)
+ if err != nil {
+ return 0, err
+ }
+
+ idx, ok = query.byOID[commit.OID]
+ if !ok {
+ idx = query.newNode(commit.OID)
+ query.byOID[commit.OID] = idx
+ }
+
+ query.byGraphPos[pos] = idx
+ query.nodes[idx].graphPos = pos
+ query.nodes[idx].hasGraphPos = true
+
+ err = query.loadCommitAtGraphPos(idx, pos)
+ if err != nil {
+ delete(query.byGraphPos, pos)
+
+ return 0, err
+ }
+
+ return idx, nil
+}
diff --git a/commitquery/resolve.go b/commitquery/query_resolve_oid.go
index cd6c3650..ad47829c 100644
--- a/commitquery/resolve.go
+++ b/commitquery/query_resolve_oid.go
@@ -1,10 +1,8 @@
package commitquery
-import (
- "codeberg.org/lindenii/furgit/internal/peel"
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
+import objectid "codeberg.org/lindenii/furgit/object/id"
+// resolveOID resolves one commit object ID to one internal query node.
func (query *query) resolveOID(id objectid.ObjectID) (nodeIndex, error) {
idx, ok := query.byOID[id]
if ok {
@@ -28,12 +26,3 @@ func (query *query) resolveOID(id objectid.ObjectID) (nodeIndex, error) {
return idx, nil
}
-
-func (query *query) resolveCommitish(id objectid.ObjectID) (nodeIndex, error) {
- commitID, err := peel.ToCommit(query.store, id)
- if err != nil {
- return 0, err
- }
-
- return query.resolveOID(commitID)
-}
diff --git a/commitquery/query_resolve_parent.go b/commitquery/query_resolve_parent.go
new file mode 100644
index 00000000..6cd75898
--- /dev/null
+++ b/commitquery/query_resolve_parent.go
@@ -0,0 +1,10 @@
+package commitquery
+
+// resolveParent resolves one parent descriptor to one internal node.
+func (query *query) resolveParent(parent parentRef) (nodeIndex, error) {
+ if parent.HasGraphPos {
+ return query.resolveGraphPos(parent.GraphPos)
+ }
+
+ return query.resolveOID(parent.ID)
+}
diff --git a/commitquery/query_set_clear_marks.go b/commitquery/query_set_clear_marks.go
new file mode 100644
index 00000000..b9619338
--- /dev/null
+++ b/commitquery/query_set_clear_marks.go
@@ -0,0 +1,22 @@
+package commitquery
+
+// setMarks ORs one set of mark bits into one internal node.
+func (query *query) setMarks(idx nodeIndex, bits markBits) {
+ newBits := bits &^ query.nodes[idx].marks
+ if newBits == 0 {
+ return
+ }
+
+ query.trackTouched(idx)
+ query.nodes[idx].marks |= bits
+}
+
+// clearMarks removes one set of mark bits from one internal node.
+func (query *query) clearMarks(idx nodeIndex, bits markBits) {
+ if query.nodes[idx].marks&bits == 0 {
+ return
+ }
+
+ query.trackTouched(idx)
+ query.nodes[idx].marks &^= bits
+}