本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
4.8KB

  1. package merkletrie
  2. import (
  3. "fmt"
  4. "io"
  5. "gopkg.in/src-d/go-git.v4/utils/merkletrie/noder"
  6. )
  7. // A doubleIter is a convenience type to keep track of the current
  8. // noders in two merkletries that are going to be iterated in parallel.
  9. // It has methods for:
  10. //
  11. // - iterating over the merkletries, both at the same time or
  12. // individually: nextFrom, nextTo, nextBoth, stepBoth
  13. //
  14. // - checking if there are noders left in one or both of them with the
  15. // remaining method and its associated returned type.
  16. //
  17. // - comparing the current noders of both merkletries in several ways,
  18. // with the compare method and its associated returned type.
  19. type doubleIter struct {
  20. from struct {
  21. iter *Iter
  22. current noder.Path // nil if no more nodes
  23. }
  24. to struct {
  25. iter *Iter
  26. current noder.Path // nil if no more nodes
  27. }
  28. hashEqual noder.Equal
  29. }
  30. // NewdoubleIter returns a new doubleIter for the merkletries "from" and
  31. // "to". The hashEqual callback function will be used by the doubleIter
  32. // to compare the hash of the noders in the merkletries. The doubleIter
  33. // will be initialized to the first elements in each merkletrie if any.
  34. func newDoubleIter(from, to noder.Noder, hashEqual noder.Equal) (
  35. *doubleIter, error) {
  36. var ii doubleIter
  37. var err error
  38. if ii.from.iter, err = NewIter(from); err != nil {
  39. return nil, fmt.Errorf("from: %s", err)
  40. }
  41. if ii.from.current, err = ii.from.iter.Next(); turnEOFIntoNil(err) != nil {
  42. return nil, fmt.Errorf("from: %s", err)
  43. }
  44. if ii.to.iter, err = NewIter(to); err != nil {
  45. return nil, fmt.Errorf("to: %s", err)
  46. }
  47. if ii.to.current, err = ii.to.iter.Next(); turnEOFIntoNil(err) != nil {
  48. return nil, fmt.Errorf("to: %s", err)
  49. }
  50. ii.hashEqual = hashEqual
  51. return &ii, nil
  52. }
  53. func turnEOFIntoNil(e error) error {
  54. if e != nil && e != io.EOF {
  55. return e
  56. }
  57. return nil
  58. }
  59. // NextBoth makes d advance to the next noder in both merkletries. If
  60. // any of them is a directory, it skips its contents.
  61. func (d *doubleIter) nextBoth() error {
  62. if err := d.nextFrom(); err != nil {
  63. return err
  64. }
  65. if err := d.nextTo(); err != nil {
  66. return err
  67. }
  68. return nil
  69. }
  70. // NextFrom makes d advance to the next noder in the "from" merkletrie,
  71. // skipping its contents if it is a directory.
  72. func (d *doubleIter) nextFrom() (err error) {
  73. d.from.current, err = d.from.iter.Next()
  74. return turnEOFIntoNil(err)
  75. }
  76. // NextTo makes d advance to the next noder in the "to" merkletrie,
  77. // skipping its contents if it is a directory.
  78. func (d *doubleIter) nextTo() (err error) {
  79. d.to.current, err = d.to.iter.Next()
  80. return turnEOFIntoNil(err)
  81. }
  82. // StepBoth makes d advance to the next noder in both merkletries,
  83. // getting deeper into directories if that is the case.
  84. func (d *doubleIter) stepBoth() (err error) {
  85. if d.from.current, err = d.from.iter.Step(); turnEOFIntoNil(err) != nil {
  86. return err
  87. }
  88. if d.to.current, err = d.to.iter.Step(); turnEOFIntoNil(err) != nil {
  89. return err
  90. }
  91. return nil
  92. }
  93. // Remaining returns if there are no more noders in the tree, if both
  94. // have noders or if one of them doesn't.
  95. func (d *doubleIter) remaining() remaining {
  96. if d.from.current == nil && d.to.current == nil {
  97. return noMoreNoders
  98. }
  99. if d.from.current == nil && d.to.current != nil {
  100. return onlyToRemains
  101. }
  102. if d.from.current != nil && d.to.current == nil {
  103. return onlyFromRemains
  104. }
  105. return bothHaveNodes
  106. }
  107. // Remaining values tells you whether both trees still have noders, or
  108. // only one of them or none of them.
  109. type remaining int
  110. const (
  111. noMoreNoders remaining = iota
  112. onlyToRemains
  113. onlyFromRemains
  114. bothHaveNodes
  115. )
  116. // Compare returns the comparison between the current elements in the
  117. // merkletries.
  118. func (d *doubleIter) compare() (s comparison, err error) {
  119. s.sameHash = d.hashEqual(d.from.current, d.to.current)
  120. fromIsDir := d.from.current.IsDir()
  121. toIsDir := d.to.current.IsDir()
  122. s.bothAreDirs = fromIsDir && toIsDir
  123. s.bothAreFiles = !fromIsDir && !toIsDir
  124. s.fileAndDir = !s.bothAreDirs && !s.bothAreFiles
  125. fromNumChildren, err := d.from.current.NumChildren()
  126. if err != nil {
  127. return comparison{}, fmt.Errorf("from: %s", err)
  128. }
  129. toNumChildren, err := d.to.current.NumChildren()
  130. if err != nil {
  131. return comparison{}, fmt.Errorf("to: %s", err)
  132. }
  133. s.fromIsEmptyDir = fromIsDir && fromNumChildren == 0
  134. s.toIsEmptyDir = toIsDir && toNumChildren == 0
  135. return
  136. }
  137. // Answers to a lot of questions you can ask about how to noders are
  138. // equal or different.
  139. type comparison struct {
  140. // the following are only valid if both nodes have the same name
  141. // (i.e. nameComparison == 0)
  142. // Do both nodes have the same hash?
  143. sameHash bool
  144. // Are both nodes files?
  145. bothAreFiles bool
  146. // the following are only valid if any of the noders are dirs,
  147. // this is, if !bothAreFiles
  148. // Is one a file and the other a dir?
  149. fileAndDir bool
  150. // Are both nodes dirs?
  151. bothAreDirs bool
  152. // Is the from node an empty dir?
  153. fromIsEmptyDir bool
  154. // Is the to Node an empty dir?
  155. toIsEmptyDir bool
  156. }
上海开阖软件有限公司 沪ICP备12045867号-1