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 }