package two import ( "fmt" "strings" log "github.com/sirupsen/logrus" ) type disk struct { blocks []block data []int } func newDisk(blocks []block) disk { offset := 0 data := []int{} for id, block := range blocks { blocks[id].offset = offset for range block.used { data = append(data, id) } for range block.available() { data = append(data, empty) } offset += block.used + block.available() } return disk{ blocks: blocks, data: data, } } func (d *disk) sort() { for i := len(d.blocks) - 1; i >= 0; i-- { log.Debugf("searching for space for block %d of size %d\n", i, d.blocks[i].used) for j := 0; j < len(d.data); j++ { if j >= d.blocks[i].offset+d.blocks[i].used { break } if d.data[j] != empty { continue } var sz int if d.data[j] == empty { sz = d.sizeOfEmptyBlock(j) } if d.blocks[i].used <= sz { d.writeBlockToDisk(j, d.blocks[i]) // don't attempt to write block again break } // skip to end of empty block j += sz } } } func (d *disk) sizeOfEmptyBlock(j int) int { var sz int for k := j; k < len(d.data) && d.data[k] == empty; k++ { sz++ } log.Debugf("found empty space of size %d\n", sz) return sz } func (d *disk) writeBlockToDisk(start int, b block) { for i := b.offset; i < b.offset+b.used; i, start = i+1, start+1 { d.data[start] = d.data[i] log.Debugf("writing %d to disk at pos %d\n", d.data[i], start) } for i := b.offset; i < len(d.data) && i < b.offset+b.used; i++ { d.data[i] = empty log.Debugf("truncating space on disk at pos %d", i) } log.Debug(d.debug()) } func (d *disk) debug() string { var sb strings.Builder for _, n := range d.data { if n == empty { sb.WriteRune('.') } else { sb.WriteString(fmt.Sprintf("%d", n)) } } return sb.String() }