9fans.net/go@v0.0.7/cmd/sam/buff.go (about)

     1  // #include "sam.h"
     2  
     3  package main
     4  
     5  import (
     6  	"io"
     7  	"unicode/utf8"
     8  )
     9  
    10  func sizecache(b *Buffer, n int) {
    11  	for cap(b.c) < n {
    12  		b.c = append(b.c[:cap(b.c)], 0)
    13  	}
    14  	b.c = b.c[:n]
    15  }
    16  
    17  func addblock(b *Buffer, i int, n int) {
    18  	if i > len(b.bl) {
    19  		panic_("internal error: addblock")
    20  	}
    21  	b.bl = append(b.bl, nil)
    22  	copy(b.bl[i+1:], b.bl[i:])
    23  	b.bl[i] = disknewblock(disk, n)
    24  }
    25  
    26  func delblock(b *Buffer, i int) {
    27  	if i >= len(b.bl) {
    28  		panic_("internal error: delblock")
    29  	}
    30  
    31  	diskrelease(disk, b.bl[i])
    32  	copy(b.bl[i:], b.bl[i+1:])
    33  	b.bl = b.bl[:len(b.bl)-1]
    34  }
    35  
    36  /*
    37   * Move cache so b->cq <= q0 < b->cq+b->cnc.
    38   * If at very end, q0 will fall on end of cache block.
    39   */
    40  
    41  func flush(b *Buffer) {
    42  	if b.cdirty || len(b.c) == 0 {
    43  		if len(b.c) == 0 {
    44  			delblock(b, b.cbi)
    45  		} else {
    46  			diskwrite(disk, &b.bl[b.cbi], b.c)
    47  		}
    48  		b.cdirty = false
    49  	}
    50  }
    51  
    52  func setcache(b *Buffer, q0 int) {
    53  	if q0 > b.nc {
    54  		panic_("internal error: setcache")
    55  	}
    56  	/*
    57  	 * flush and reload if q0 is not in cache.
    58  	 */
    59  	if b.nc == 0 || (b.cq <= q0 && q0 < b.cq+len(b.c)) {
    60  		return
    61  	}
    62  	/*
    63  	 * if q0 is at end of file and end of cache, continue to grow this block
    64  	 */
    65  	if q0 == b.nc && q0 == b.cq+len(b.c) && len(b.c) <= Maxblock {
    66  		return
    67  	}
    68  	flush(b)
    69  	var q, i int
    70  	/* find block */
    71  	if q0 < b.cq {
    72  		q = 0
    73  		i = 0
    74  	} else {
    75  		q = b.cq
    76  		i = b.cbi
    77  	}
    78  	blp := &b.bl[i]
    79  	for q+(*blp).u.n <= q0 && q+(*blp).u.n < b.nc {
    80  		q += (*blp).u.n
    81  		i++
    82  		if i >= len(b.bl) {
    83  			panic_("block not found")
    84  		}
    85  		blp = &b.bl[i]
    86  	}
    87  	bl := *blp
    88  	/* remember position */
    89  	b.cbi = i
    90  	b.cq = q
    91  	sizecache(b, bl.u.n)
    92  	/*read block*/
    93  	diskread(disk, bl, b.c)
    94  }
    95  
    96  func bufinsert(b *Buffer, q0 int, s []rune) {
    97  	n := len(s)
    98  	if q0 > b.nc {
    99  		panic_("internal error: bufinsert")
   100  	}
   101  
   102  	for n > 0 {
   103  		setcache(b, q0)
   104  		off := q0 - b.cq
   105  		var m int
   106  		if len(b.c)+n <= Maxblock {
   107  			/* Everything fits in one block. */
   108  			t := len(b.c) + n
   109  			m = n
   110  			if b.bl == nil { /* allocate */
   111  				if len(b.c) != 0 {
   112  					panic_("internal error: bufinsert1 cnc!=0")
   113  				}
   114  				addblock(b, 0, t)
   115  				b.cbi = 0
   116  			}
   117  			sizecache(b, t)
   118  			copy(b.c[off+m:], b.c[off:])
   119  			copy(b.c[off:], s[:m])
   120  		} else if q0 == b.cq || q0 == b.cq+len(b.c) {
   121  			/*
   122  			 * We must make a new block.  If q0 is at
   123  			 * the very beginning or end of this block,
   124  			 * just make a new block and fill it.
   125  			 */
   126  			if b.cdirty {
   127  				flush(b)
   128  			}
   129  			m = min(n, Maxblock)
   130  			var i int
   131  			if b.bl == nil { /* allocate */
   132  				if len(b.c) != 0 {
   133  					panic_("internal error: bufinsert2 cnc!=0")
   134  				}
   135  				i = 0
   136  			} else {
   137  				i = b.cbi
   138  				if q0 > b.cq {
   139  					i++
   140  				}
   141  			}
   142  			addblock(b, i, m)
   143  			sizecache(b, m)
   144  			copy(b.c, s[:m])
   145  			b.cq = q0
   146  			b.cbi = i
   147  		} else {
   148  			/*
   149  			 * Split the block; cut off the right side and
   150  			 * let go of it.
   151  			 */
   152  			m = len(b.c) - off
   153  			if m > 0 {
   154  				i := b.cbi + 1
   155  				addblock(b, i, m)
   156  				diskwrite(disk, &b.bl[i], b.c[off:])
   157  				b.c = b.c[:off]
   158  			}
   159  			/*
   160  			 * Now at end of block.  Take as much input
   161  			 * as possible and tack it on end of block.
   162  			 */
   163  			m = min(n, Maxblock-len(b.c))
   164  			n := len(b.c)
   165  			sizecache(b, n+m)
   166  			copy(b.c[n:], s)
   167  		}
   168  
   169  		b.nc += m
   170  		q0 += m
   171  		s = s[m:]
   172  		n -= m
   173  		b.cdirty = true
   174  	}
   175  }
   176  
   177  func bufdelete(b *Buffer, q0 int, q1 int) {
   178  	if !(q0 <= q1 && q0 <= b.nc) || !(q1 <= b.nc) {
   179  		panic_("internal error: bufdelete")
   180  	}
   181  	for q1 > q0 {
   182  		setcache(b, q0)
   183  		off := q0 - b.cq
   184  		var n int
   185  		if q1 > b.cq+len(b.c) {
   186  			n = len(b.c) - off
   187  		} else {
   188  			n = q1 - q0
   189  		}
   190  		m := len(b.c) - (off + n)
   191  		if m > 0 {
   192  			copy(b.c[off:], b.c[off+n:])
   193  		}
   194  		b.c = b.c[:len(b.c)-n]
   195  		b.cdirty = true
   196  		q1 -= n
   197  		b.nc -= n
   198  	}
   199  }
   200  
   201  func bufload(b *Buffer, q0 int, fd io.Reader, nulls *bool) int {
   202  	if q0 > b.nc {
   203  		panic_("internal error: bufload")
   204  	}
   205  	p := make([]byte, Maxblock+utf8.UTFMax+1)
   206  	r := make([]rune, Maxblock)
   207  	m := 0
   208  	n := 1
   209  	q1 := q0
   210  	/*
   211  	 * At top of loop, may have m bytes left over from
   212  	 * last pass, possibly representing a partial rune.
   213  	 */
   214  	for n > 0 {
   215  		var err error
   216  		n, err = fd.Read(p[m : m+Maxblock])
   217  		if err != nil && err != io.EOF {
   218  			error_(Ebufload)
   219  			break
   220  		}
   221  		m += n
   222  		nb, nr, nulls1 := cvttorunes(p[:m], r, err == io.EOF)
   223  		if nulls1 {
   224  			*nulls = true
   225  		}
   226  		copy(p, p[nb:m])
   227  		m -= nb
   228  		bufinsert(b, q1, r[:nr])
   229  		q1 += nr
   230  	}
   231  	// free(p)
   232  	// free(r)
   233  	return q1 - q0
   234  }
   235  
   236  func bufread(b *Buffer, q0 int, s []rune) {
   237  	n := len(s)
   238  	if !(q0 <= b.nc) || !(q0+n <= b.nc) {
   239  		panic_("bufread: internal error")
   240  	}
   241  
   242  	for n > 0 {
   243  		setcache(b, q0)
   244  		m := min(n, len(b.c)-(q0-b.cq))
   245  		copy(s[:m], b.c[q0-b.cq:])
   246  		q0 += m
   247  		s = s[m:]
   248  		n -= m
   249  	}
   250  }
   251  
   252  func bufreset(b *Buffer) {
   253  	b.nc = 0
   254  	b.c = b.c[:0]
   255  	b.cq = 0
   256  	b.cdirty = false
   257  	b.cbi = 0
   258  	/* delete backwards to avoid n² behavior */
   259  	// TODO(rsc): Is there a reason we leave one b.bl entry behind?
   260  	for i := len(b.bl) - 1; ; {
   261  		i--
   262  		if i < 0 {
   263  			break
   264  		}
   265  		delblock(b, i)
   266  	}
   267  }
   268  
   269  func bufclose(b *Buffer) {
   270  	bufreset(b)
   271  	// free(b.c)
   272  	b.c = nil
   273  	// free(b.bl)
   274  	b.bl = nil
   275  }