file.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package hercules
  2. import "fmt"
  3. type File struct {
  4. tree *RBTree
  5. status map[int]int64
  6. }
  7. const TreeEnd int = -1
  8. func min(a int, b int) int {
  9. if a < b {
  10. return a
  11. }
  12. return b
  13. }
  14. func max(a int, b int) int {
  15. if a < b {
  16. return b
  17. }
  18. return a
  19. }
  20. func NewFile(time int, length int, status map[int]int64) *File {
  21. file := new(File)
  22. file.status = status
  23. file.tree = new(RBTree)
  24. if length > 0 {
  25. status[time] += int64(length)
  26. file.tree.Insert(Item{key: 0, value: time})
  27. }
  28. file.tree.Insert(Item{key: length, value: TreeEnd})
  29. return file
  30. }
  31. func (file *File) Len() int {
  32. return file.tree.Max().Item().key
  33. }
  34. func (file *File) Update(time int, pos int, ins_length int, del_length int) {
  35. if time < 0 {
  36. panic("time may not be negative")
  37. }
  38. if pos < 0 {
  39. panic("attempt to insert/delete at a negative position")
  40. }
  41. if ins_length < 0 || del_length < 0 {
  42. panic("ins_length and del_length must be nonnegative")
  43. }
  44. if ins_length|del_length == 0 {
  45. return
  46. }
  47. tree := file.tree
  48. if pos > tree.Max().Item().key {
  49. panic(fmt.Sprintf("attempt to insert after the end of the file: %d < %d",
  50. tree.Max().Item().key, pos))
  51. }
  52. if tree.Len() < 2 && tree.Min().Item().key != 0 {
  53. panic("invalid tree state")
  54. }
  55. status := file.status
  56. iter := tree.FindLE(pos)
  57. origin := *iter.Item()
  58. status[time] += int64(ins_length)
  59. if del_length == 0 {
  60. // simple case with insertions only
  61. if origin.key < pos || (origin.value == time && pos == 0) {
  62. iter = iter.Next()
  63. }
  64. for ; !iter.Limit(); iter = iter.Next() {
  65. iter.Item().key += ins_length
  66. }
  67. if origin.value != time {
  68. tree.Insert(Item{key: pos, value: time})
  69. if origin.key < pos {
  70. tree.Insert(Item{key: pos + ins_length, value: origin.value})
  71. }
  72. }
  73. return
  74. }
  75. // delete nodes
  76. for true {
  77. node := iter.Item()
  78. next_iter := iter.Next()
  79. if next_iter.Limit() {
  80. if pos+del_length > node.key {
  81. panic("attempt to delete after the end of the file")
  82. }
  83. break
  84. }
  85. delta := min(next_iter.Item().key, pos+del_length) - max(node.key, pos)
  86. if delta <= 0 {
  87. break
  88. }
  89. status[node.value] -= int64(delta)
  90. if node.key >= pos {
  91. origin = *node
  92. tree.DeleteWithIterator(iter)
  93. }
  94. iter = next_iter
  95. }
  96. // prepare for the keys update
  97. var previous *Item
  98. if ins_length > 0 && (origin.value != time || origin.key == pos) {
  99. // insert our new interval
  100. if iter.Item().value == time {
  101. if iter.Prev().Item().value != time {
  102. iter.Item().key = pos
  103. } else {
  104. next_iter := iter.Next()
  105. tree.DeleteWithIterator(iter)
  106. iter = next_iter
  107. }
  108. origin.value = time // cancels the insertion after applying the delta
  109. } else {
  110. _, iter = tree.Insert(Item{key: pos, value: time})
  111. }
  112. } else {
  113. // rollback 1 position back, see "for true" deletion cycle ^
  114. iter = iter.Prev()
  115. previous = iter.Item()
  116. }
  117. // update the keys of all subsequent nodes
  118. delta := ins_length - del_length
  119. if delta != 0 {
  120. for iter = iter.Next(); !iter.Limit(); iter = iter.Next() {
  121. // we do not need to re-balance the tree
  122. iter.Item().key += delta
  123. }
  124. // have to adjust origin in case ins_length == 0
  125. if origin.key > pos {
  126. origin.key += delta
  127. }
  128. }
  129. if ins_length > 0 {
  130. if origin.value != time {
  131. tree.Insert(Item{pos + ins_length, origin.value})
  132. }
  133. } else if (pos > origin.key && previous.value != origin.value) || pos == origin.key {
  134. // continue the original interval
  135. tree.Insert(Item{pos, origin.value})
  136. }
  137. }
  138. func (file *File) Dump() string {
  139. buffer := ""
  140. for iter := file.tree.Min(); !iter.Limit(); iter = iter.Next() {
  141. node := iter.Item()
  142. buffer += fmt.Sprintf("%d %d\n", node.key, node.value)
  143. }
  144. return buffer
  145. }