github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/go/datas/commit.go (about)

     1  // Copyright 2016 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package datas
     6  
     7  import (
     8  	"sort"
     9  
    10  	"github.com/attic-labs/noms/go/d"
    11  	"github.com/attic-labs/noms/go/hash"
    12  	"github.com/attic-labs/noms/go/nomdl"
    13  	"github.com/attic-labs/noms/go/types"
    14  )
    15  
    16  const (
    17  	ParentsField = "parents"
    18  	ValueField   = "value"
    19  	MetaField    = "meta"
    20  	commitName   = "Commit"
    21  )
    22  
    23  var commitTemplate = types.MakeStructTemplate(commitName, []string{MetaField, ParentsField, ValueField})
    24  
    25  var valueCommitType = nomdl.MustParseType(`Struct Commit {
    26          meta: Struct {},
    27          parents: Set<Ref<Cycle<Commit>>>,
    28          value: Value,
    29  }`)
    30  
    31  // NewCommit creates a new commit object.
    32  //
    33  // A commit has the following type:
    34  //
    35  // ```
    36  // struct Commit {
    37  //   meta: M,
    38  //   parents: Set<Ref<Cycle<Commit>>>,
    39  //   value: T,
    40  // }
    41  // ```
    42  // where M is a struct type and T is any type.
    43  func NewCommit(value types.Value, parents types.Set, meta types.Struct) types.Struct {
    44  	return commitTemplate.NewStruct([]types.Value{meta, parents, value})
    45  }
    46  
    47  // FindCommonAncestor returns the most recent common ancestor of c1 and c2, if
    48  // one exists, setting ok to true. If there is no common ancestor, ok is set
    49  // to false.
    50  func FindCommonAncestor(c1, c2 types.Ref, vr types.ValueReader) (a types.Ref, ok bool) {
    51  	if !IsRefOfCommitType(types.TypeOf(c1)) {
    52  		d.Panic("FindCommonAncestor() called on %s", types.TypeOf(c1).Describe())
    53  	}
    54  	if !IsRefOfCommitType(types.TypeOf(c2)) {
    55  		d.Panic("FindCommonAncestor() called on %s", types.TypeOf(c2).Describe())
    56  	}
    57  
    58  	c1Q, c2Q := &types.RefByHeight{c1}, &types.RefByHeight{c2}
    59  	for !c1Q.Empty() && !c2Q.Empty() {
    60  		c1Ht, c2Ht := c1Q.MaxHeight(), c2Q.MaxHeight()
    61  		if c1Ht == c2Ht {
    62  			c1Parents, c2Parents := c1Q.PopRefsOfHeight(c1Ht), c2Q.PopRefsOfHeight(c2Ht)
    63  			if common, ok := findCommonRef(c1Parents, c2Parents); ok {
    64  				return common, true
    65  			}
    66  			parentsToQueue(c1Parents, c1Q, vr)
    67  			parentsToQueue(c2Parents, c2Q, vr)
    68  		} else if c1Ht > c2Ht {
    69  			parentsToQueue(c1Q.PopRefsOfHeight(c1Ht), c1Q, vr)
    70  		} else {
    71  			parentsToQueue(c2Q.PopRefsOfHeight(c2Ht), c2Q, vr)
    72  		}
    73  	}
    74  	return
    75  }
    76  
    77  func parentsToQueue(refs types.RefSlice, q *types.RefByHeight, vr types.ValueReader) {
    78  	for _, r := range refs {
    79  		c := r.TargetValue(vr).(types.Struct)
    80  		p := c.Get(ParentsField).(types.Set)
    81  		p.IterAll(func(v types.Value) {
    82  			q.PushBack(v.(types.Ref))
    83  		})
    84  	}
    85  	sort.Sort(q)
    86  }
    87  
    88  func findCommonRef(a, b types.RefSlice) (types.Ref, bool) {
    89  	toRefSet := func(s types.RefSlice) map[hash.Hash]types.Ref {
    90  		out := map[hash.Hash]types.Ref{}
    91  		for _, r := range s {
    92  			out[r.TargetHash()] = r
    93  		}
    94  		return out
    95  	}
    96  
    97  	aSet, bSet := toRefSet(a), toRefSet(b)
    98  	for s, r := range aSet {
    99  		if _, present := bSet[s]; present {
   100  			return r, true
   101  		}
   102  	}
   103  	return types.Ref{}, false
   104  }
   105  
   106  func makeCommitStructType(metaType, parentsType, valueType *types.Type) *types.Type {
   107  	return types.MakeStructType("Commit",
   108  		types.StructField{
   109  			Name: MetaField,
   110  			Type: metaType,
   111  		},
   112  		types.StructField{
   113  			Name: ParentsField,
   114  			Type: parentsType,
   115  		},
   116  		types.StructField{
   117  			Name: ValueField,
   118  			Type: valueType,
   119  		},
   120  	)
   121  }
   122  
   123  func getRefElementType(t *types.Type) *types.Type {
   124  	d.PanicIfFalse(t.TargetKind() == types.RefKind)
   125  	return t.Desc.(types.CompoundDesc).ElemTypes[0]
   126  }
   127  
   128  func IsCommitType(t *types.Type) bool {
   129  	return types.IsSubtype(valueCommitType, t)
   130  }
   131  
   132  func IsCommit(v types.Value) bool {
   133  	return types.IsValueSubtypeOf(v, valueCommitType)
   134  }
   135  
   136  func IsRefOfCommitType(t *types.Type) bool {
   137  	return t.TargetKind() == types.RefKind && IsCommitType(getRefElementType(t))
   138  }