9fans.net/go@v0.0.7/cmd/acme/internal/disk/buff.go (about)

     1  package disk
     2  
     3  import "9fans.net/go/cmd/acme/internal/util"
     4  
     5  type Buffer struct {
     6  	nc     int
     7  	c      []rune // cnc was len(c), cmax was cap(c)
     8  	cq     int
     9  	cdirty bool
    10  	cbi    int
    11  	bl     []*block // nbl was len(bl) == cap(bl)
    12  }
    13  
    14  var blist *block
    15  
    16  func (b *Buffer) Len() int { return b.nc }
    17  
    18  func (b *Buffer) resizeCache(n int) {
    19  	for cap(b.c) < n {
    20  		b.c = append(b.c[:cap(b.c)], 0)
    21  	}
    22  	b.c = b.c[:n]
    23  }
    24  
    25  func (b *Buffer) insertBlock(i, n int) {
    26  	if i > len(b.bl) {
    27  		util.Fatal("internal error: addblock")
    28  	}
    29  	b.bl = append(b.bl, nil)
    30  	copy(b.bl[i+1:], b.bl[i:])
    31  	b.bl[i] = disk.allocBlock(n)
    32  }
    33  
    34  func (b *Buffer) deleteBlock(i int) {
    35  	if i >= len(b.bl) {
    36  		util.Fatal("internal error: delblock")
    37  	}
    38  
    39  	disk.freeBlock(b.bl[i])
    40  	copy(b.bl[i:], b.bl[i+1:])
    41  	b.bl = b.bl[:len(b.bl)-1]
    42  }
    43  
    44  /*
    45   * Move cache so b->cq <= q0 < b->cq+b->cnc.
    46   * If at very end, q0 will fall on end of cache block.
    47   */
    48  
    49  func (b *Buffer) flushCache() {
    50  	if b.cdirty || len(b.c) == 0 {
    51  		if len(b.c) == 0 {
    52  			b.deleteBlock(b.cbi)
    53  		} else {
    54  			disk.write(&b.bl[b.cbi], b.c)
    55  		}
    56  		b.cdirty = false
    57  	}
    58  }
    59  
    60  func (b *Buffer) setCache(q0 int) {
    61  	if q0 > b.Len() {
    62  		util.Fatal("internal error: setcache")
    63  	}
    64  	/*
    65  	 * flush and reload if q0 is not in cache.
    66  	 */
    67  	if b.Len() == 0 || (b.cq <= q0 && q0 < b.cq+len(b.c)) {
    68  		return
    69  	}
    70  	/*
    71  	 * if q0 is at end of file and end of cache, continue to grow this block
    72  	 */
    73  	if q0 == b.Len() && q0 == b.cq+len(b.c) && len(b.c) < maxblock { // TODO(rsc): sam says <= Maxblock; which is right?
    74  		return
    75  	}
    76  	b.flushCache()
    77  	var q, i int
    78  	/* find block */
    79  	if q0 < b.cq {
    80  		q = 0
    81  		i = 0
    82  	} else {
    83  		q = b.cq
    84  		i = b.cbi
    85  	}
    86  	blp := &b.bl[i]
    87  	for q+(*blp).u.n <= q0 && q+(*blp).u.n < b.Len() {
    88  		q += (*blp).u.n
    89  		i++
    90  		if i >= len(b.bl) {
    91  			util.Fatal("block not found")
    92  		}
    93  		blp = &b.bl[i]
    94  	}
    95  	bl := *blp
    96  	/* remember position */
    97  	b.cbi = i
    98  	b.cq = q
    99  	b.resizeCache(bl.u.n)
   100  	/*read block*/
   101  	disk.read(bl, b.c)
   102  }
   103  
   104  func (b *Buffer) Read(q0 int, s []rune) {
   105  	n := len(s)
   106  	if !(q0 <= b.Len()) || !(q0+n <= b.Len()) {
   107  		util.Fatal("bufread: internal error")
   108  	}
   109  
   110  	for n > 0 {
   111  		b.setCache(q0)
   112  		m := util.Min(n, len(b.c)-(q0-b.cq))
   113  		copy(s[:m], b.c[q0-b.cq:])
   114  		q0 += m
   115  		s = s[m:]
   116  		n -= m
   117  	}
   118  }
   119  
   120  func (b *Buffer) Insert(q0 int, s []rune) {
   121  	n := len(s)
   122  	if q0 > b.Len() {
   123  		util.Fatal("internal error: bufinsert")
   124  	}
   125  
   126  	for n > 0 {
   127  		b.setCache(q0)
   128  		off := q0 - b.cq
   129  		var m int
   130  		if len(b.c)+n <= maxblock {
   131  			/* Everything fits in one block. */
   132  			t := len(b.c) + n
   133  			m = n
   134  			if b.bl == nil { /* allocate */
   135  				if len(b.c) != 0 {
   136  					util.Fatal("internal error: bufinsert1 cnc!=0")
   137  				}
   138  				b.insertBlock(0, t)
   139  				b.cbi = 0
   140  			}
   141  			b.resizeCache(t)
   142  			copy(b.c[off+m:], b.c[off:])
   143  			copy(b.c[off:], s[:m])
   144  		} else if q0 == b.cq || q0 == b.cq+len(b.c) {
   145  			/*
   146  			 * We must make a new block.  If q0 is at
   147  			 * the very beginning or end of this block,
   148  			 * just make a new block and fill it.
   149  			 */
   150  			if b.cdirty {
   151  				b.flushCache()
   152  			}
   153  			m = util.Min(n, maxblock)
   154  			var i int
   155  			if b.bl == nil { /* allocate */
   156  				if len(b.c) != 0 {
   157  					util.Fatal("internal error: bufinsert2 cnc!=0")
   158  				}
   159  				i = 0
   160  			} else {
   161  				i = b.cbi
   162  				if q0 > b.cq {
   163  					i++
   164  				}
   165  			}
   166  			b.insertBlock(i, m)
   167  			b.resizeCache(m)
   168  			copy(b.c, s[:m])
   169  			b.cq = q0
   170  			b.cbi = i
   171  		} else {
   172  			/*
   173  			 * Split the block; cut off the right side and
   174  			 * let go of it.
   175  			 */
   176  			m = len(b.c) - off
   177  			if m > 0 {
   178  				i := b.cbi + 1
   179  				b.insertBlock(i, m)
   180  				disk.write(&b.bl[i], b.c[off:])
   181  				b.c = b.c[:off]
   182  			}
   183  			/*
   184  			 * Now at end of block.  Take as much input
   185  			 * as possible and tack it on end of block.
   186  			 */
   187  			m = util.Min(n, maxblock-len(b.c))
   188  			n := len(b.c)
   189  			b.resizeCache(n + m)
   190  			copy(b.c[n:], s)
   191  		}
   192  
   193  		b.nc += m
   194  		q0 += m
   195  		s = s[m:]
   196  		n -= m
   197  		b.cdirty = true
   198  	}
   199  }
   200  
   201  func (b *Buffer) Delete(q0, q1 int) {
   202  	if !(q0 <= q1 && q0 <= b.Len()) || !(q1 <= b.Len()) {
   203  		util.Fatal("internal error: bufdelete")
   204  	}
   205  	for q1 > q0 {
   206  		b.setCache(q0)
   207  		off := q0 - b.cq
   208  		var n int
   209  		if q1 > b.cq+len(b.c) {
   210  			n = len(b.c) - off
   211  		} else {
   212  			n = q1 - q0
   213  		}
   214  		m := len(b.c) - (off + n)
   215  		if m > 0 {
   216  			copy(b.c[off:], b.c[off+n:])
   217  		}
   218  		b.c = b.c[:len(b.c)-n]
   219  		b.cdirty = true
   220  		q1 -= n
   221  		b.nc -= n
   222  	}
   223  }
   224  
   225  func (b *Buffer) Reset() {
   226  	b.nc = 0
   227  	b.c = b.c[:0]
   228  	b.cq = 0
   229  	b.cdirty = false
   230  	b.cbi = 0
   231  	/* delete backwards to avoid n² behavior */
   232  	// TODO(rsc): Is there a reason we leave one b.bl entry behind?
   233  	for i := len(b.bl) - 1; ; {
   234  		i--
   235  		if i < 0 {
   236  			break
   237  		}
   238  		b.deleteBlock(i)
   239  	}
   240  }
   241  
   242  func (b *Buffer) Close() {
   243  	b.Reset()
   244  	// free(b.c)
   245  	b.c = nil
   246  	// free(b.bl)
   247  	b.bl = nil
   248  }