| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 | package herculesimport "fmt"type File struct {	tree   *RBTree	status map[int]int64}const TreeEnd int = -1func min(a int, b int) int {	if a < b {		return a	}	return b}func max(a int, b int) int {	if a < b {		return b	}	return a}func NewFile(time int, length int, status map[int]int64) *File {	file := new(File)	file.status = status	file.tree = new(RBTree)	if length > 0 {		status[time] += int64(length)		file.tree.Insert(Item{key: 0, value: time})	}	file.tree.Insert(Item{key: length, value: TreeEnd})	return file}func (file *File) Len() int {	return file.tree.Max().Item().key}func (file *File) Update(time int, pos int, ins_length int, del_length int) {	if time < 0 {		panic("time may not be negative")	}	if pos < 0 {		panic("attempt to insert/delete at a negative position")	}	if ins_length < 0 || del_length < 0 {		panic("ins_length and del_length must be nonnegative")	}	if ins_length|del_length == 0 {		return	}	tree := file.tree	if pos > tree.Max().Item().key {		panic(fmt.Sprintf("attempt to insert after the end of the file: %d < %d",			tree.Max().Item().key, pos))	}	if tree.Len() < 2 && tree.Min().Item().key != 0 {		panic("invalid tree state")	}	status := file.status	iter := tree.FindLE(pos)	origin := *iter.Item()	status[time] += int64(ins_length)	if del_length == 0 {		// simple case with insertions only		if origin.key < pos || (origin.value == time && pos == 0) {			iter = iter.Next()		}		for ; !iter.Limit(); iter = iter.Next() {			iter.Item().key += ins_length		}		if origin.value != time {			tree.Insert(Item{key: pos, value: time})			if origin.key < pos {				tree.Insert(Item{key: pos + ins_length, value: origin.value})			}		}		return	}	// delete nodes	for true {		node := iter.Item()		next_iter := iter.Next()		if next_iter.Limit() {			if pos+del_length > node.key {				panic("attempt to delete after the end of the file")			}			break		}		delta := min(next_iter.Item().key, pos+del_length) - max(node.key, pos)		if delta <= 0 {			break		}		status[node.value] -= int64(delta)		if node.key >= pos {			origin = *node			tree.DeleteWithIterator(iter)		}		iter = next_iter	}	// prepare for the keys update	var previous *Item	if ins_length > 0 && (origin.value != time || origin.key == pos) {		// insert our new interval		if iter.Item().value == time {			if iter.Prev().Item().value != time {				iter.Item().key = pos			} else {				next_iter := iter.Next()				tree.DeleteWithIterator(iter)				iter = next_iter			}			origin.value = time // cancels the insertion after applying the delta		} else {			_, iter = tree.Insert(Item{key: pos, value: time})		}	} else {		// rollback 1 position back, see "for true" deletion cycle ^		iter = iter.Prev()		previous = iter.Item()	}	// update the keys of all subsequent nodes	delta := ins_length - del_length	if delta != 0 {		for iter = iter.Next(); !iter.Limit(); iter = iter.Next() {			// we do not need to re-balance the tree			iter.Item().key += delta		}		// have to adjust origin in case ins_length == 0		if origin.key > pos {			origin.key += delta		}	}	if ins_length > 0 {		if origin.value != time {			tree.Insert(Item{pos + ins_length, origin.value})		}	} else if (pos > origin.key && previous.value != origin.value) || pos == origin.key {		// continue the original interval		tree.Insert(Item{pos, origin.value})	}}func (file *File) Dump() string {	buffer := ""	for iter := file.tree.Min(); !iter.Limit(); iter = iter.Next() {		node := iter.Item()		buffer += fmt.Sprintf("%d %d\n", node.key, node.value)	}	return buffer}
 |