file.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. // An ugly side of Go.
  9. // template <typename T> please!
  10. func min(a int, b int) int {
  11. if a < b {
  12. return a
  13. }
  14. return b
  15. }
  16. func min64(a int64, b int64) int64 {
  17. if a < b {
  18. return a
  19. }
  20. return b
  21. }
  22. func max(a int, b int) int {
  23. if a < b {
  24. return b
  25. }
  26. return a
  27. }
  28. func max64(a int64, b int64) int64 {
  29. if a < b {
  30. return b
  31. }
  32. return a
  33. }
  34. func abs64(v int64) int64 {
  35. if v <= 0 {
  36. return -v
  37. }
  38. return v
  39. }
  40. func NewFile(time int, length int, status map[int]int64) *File {
  41. file := new(File)
  42. file.status = status
  43. file.tree = new(RBTree)
  44. if length > 0 {
  45. status[time] += int64(length)
  46. file.tree.Insert(Item{key: 0, value: time})
  47. }
  48. file.tree.Insert(Item{key: length, value: TreeEnd})
  49. return file
  50. }
  51. func NewFileFromTree(keys []int, vals []int, status map[int]int64) *File {
  52. file := new(File)
  53. file.status = status
  54. file.tree = new(RBTree)
  55. if len(keys) != len(vals) {
  56. panic("keys and vals must be of equal length")
  57. }
  58. for i := 0; i < len(keys); i++ {
  59. file.tree.Insert(Item{key: keys[i], value: vals[i]})
  60. }
  61. file.Validate()
  62. return file
  63. }
  64. func (file *File) Len() int {
  65. return file.tree.Max().Item().key
  66. }
  67. func (file *File) Update(time int, pos int, ins_length int, del_length int) {
  68. if time < 0 {
  69. panic("time may not be negative")
  70. }
  71. if pos < 0 {
  72. panic("attempt to insert/delete at a negative position")
  73. }
  74. if ins_length < 0 || del_length < 0 {
  75. panic("ins_length and del_length must be nonnegative")
  76. }
  77. if ins_length|del_length == 0 {
  78. return
  79. }
  80. tree := file.tree
  81. if pos > tree.Max().Item().key {
  82. panic(fmt.Sprintf("attempt to insert after the end of the file: %d < %d",
  83. tree.Max().Item().key, pos))
  84. }
  85. if tree.Len() < 2 && tree.Min().Item().key != 0 {
  86. panic("invalid tree state")
  87. }
  88. status := file.status
  89. iter := tree.FindLE(pos)
  90. origin := *iter.Item()
  91. status[time] += int64(ins_length)
  92. if del_length == 0 {
  93. // simple case with insertions only
  94. if origin.key < pos || (origin.value == time && pos == 0) {
  95. iter = iter.Next()
  96. }
  97. for ; !iter.Limit(); iter = iter.Next() {
  98. iter.Item().key += ins_length
  99. }
  100. if origin.value != time {
  101. tree.Insert(Item{key: pos, value: time})
  102. if origin.key < pos {
  103. tree.Insert(Item{key: pos + ins_length, value: origin.value})
  104. }
  105. }
  106. return
  107. }
  108. // delete nodes
  109. for true {
  110. node := iter.Item()
  111. next_iter := iter.Next()
  112. if next_iter.Limit() {
  113. if pos+del_length > node.key {
  114. panic("attempt to delete after the end of the file")
  115. }
  116. break
  117. }
  118. delta := min(next_iter.Item().key, pos+del_length) - max(node.key, pos)
  119. if delta <= 0 {
  120. break
  121. }
  122. status[node.value] -= int64(delta)
  123. if node.key >= pos {
  124. origin = *node
  125. tree.DeleteWithIterator(iter)
  126. }
  127. iter = next_iter
  128. }
  129. // prepare for the keys update
  130. var previous *Item
  131. if ins_length > 0 && (origin.value != time || origin.key == pos) {
  132. // insert our new interval
  133. if iter.Item().value == time {
  134. prev := iter.Prev()
  135. if prev.Item().value != time {
  136. iter.Item().key = pos
  137. } else {
  138. tree.DeleteWithIterator(iter)
  139. iter = prev
  140. }
  141. origin.value = time // cancels the insertion after applying the delta
  142. } else {
  143. _, iter = tree.Insert(Item{key: pos, value: time})
  144. }
  145. } else {
  146. // rollback 1 position back, see "for true" deletion cycle ^
  147. iter = iter.Prev()
  148. previous = iter.Item()
  149. }
  150. // update the keys of all subsequent nodes
  151. delta := ins_length - del_length
  152. if delta != 0 {
  153. for iter = iter.Next(); !iter.Limit(); iter = iter.Next() {
  154. // we do not need to re-balance the tree
  155. iter.Item().key += delta
  156. }
  157. // have to adjust origin in case ins_length == 0
  158. if origin.key > pos {
  159. origin.key += delta
  160. }
  161. }
  162. if ins_length > 0 {
  163. if origin.value != time {
  164. tree.Insert(Item{pos + ins_length, origin.value})
  165. } else if pos == 0 {
  166. // recover the beginning
  167. tree.Insert(Item{pos, time})
  168. }
  169. } else if (pos > origin.key && previous.value != origin.value) || pos == origin.key || pos == 0 {
  170. // continue the original interval
  171. tree.Insert(Item{pos, origin.value})
  172. }
  173. }
  174. func (file *File) Dump() string {
  175. buffer := ""
  176. for iter := file.tree.Min(); !iter.Limit(); iter = iter.Next() {
  177. node := iter.Item()
  178. buffer += fmt.Sprintf("%d %d\n", node.key, node.value)
  179. }
  180. return buffer
  181. }
  182. func (file *File) Validate() {
  183. if file.tree.Min().Item().key != 0 {
  184. panic("the tree must start with key 0")
  185. }
  186. if file.tree.Max().Item().value != -1 {
  187. panic(fmt.Sprintf("the last value in the tree must be %d", TreeEnd))
  188. }
  189. prev_key := -1
  190. for iter := file.tree.Min(); !iter.Limit(); iter = iter.Next() {
  191. node := iter.Item()
  192. if node.key == prev_key {
  193. panic(fmt.Sprintf("duplicate tree key: %d", node.key))
  194. }
  195. prev_key = node.key
  196. }
  197. }