gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/slice/chunks.go (about) 1 package slice 2 3 import _ "unsafe" 4 5 //go:linkname GoPanicIndex runtime.goPanicIndex 6 func GoPanicIndex(x int, y int) 7 8 //go:linkname GoPanicSliceAlen runtime.goPanicSliceAlen 9 func GoPanicSliceAlen(x int, y int) 10 11 //go:linkname GoPanicSliceB runtime.goPanicSliceB 12 func GoPanicSliceB(x int, y int) 13 14 type Chunks[E any] [][]E 15 16 func Join[E any](ss [][]E) []E { 17 switch len(ss) { 18 case 0: 19 return nil 20 case 1: 21 return ss[0] 22 case 2: 23 rs := ss[0] 24 return append(rs[:len(rs):len(rs)], ss[1]...) 25 default: 26 var n int 27 for _, s := range ss { 28 n += len(s) 29 } 30 rs := make([]E, n) 31 sp := copy(rs, ss[0]) 32 for _, es := range ss[1:] { 33 sp += copy(rs[sp:], es) 34 } 35 return rs 36 } 37 } 38 39 func Join1N[E any](s []E, ss [][]E) []E { 40 switch len(ss) { 41 case 0: 42 return s 43 case 1: 44 return append(s[:len(s):len(s)], ss[0]...) 45 default: 46 var n = len(s) 47 for _, s := range ss { 48 n += len(s) 49 } 50 rs := make([]E, n) 51 sp := copy(rs, s) 52 for _, es := range ss { 53 sp += copy(rs[sp:], es) 54 } 55 return rs 56 } 57 } 58 59 func JoinN1[E any](ss [][]E, s []E) []E { 60 switch len(ss) { 61 case 0: 62 return s 63 case 1: 64 rs := ss[0] 65 return append(rs[:len(rs):len(rs)], s...) 66 default: 67 var n = len(s) 68 for _, s := range ss { 69 n += len(s) 70 } 71 rs := make([]E, n) 72 sp := copy(rs, ss[0]) 73 for _, es := range ss[1:] { 74 sp += copy(rs[sp:], es) 75 } 76 copy(rs[sp:], s) 77 return rs 78 } 79 } 80 81 func Join11[E any](s1, s2 []E) []E { 82 return append(s1[:len(s1):len(s1)], s2...) 83 } 84 85 func Join1N1[E any](s1 []E, ss [][]E, s2 []E) []E { 86 switch len(ss) { 87 case 0: 88 return append(s1[:len(s1):len(s1)], s2...) 89 default: 90 var n = len(s1) + len(s2) 91 for _, s := range ss { 92 n += len(s) 93 } 94 rs := make([]E, n) 95 sp := copy(rs, s1) 96 for _, es := range ss { 97 sp += copy(rs[sp:], es) 98 } 99 copy(rs[sp:], s2) 100 return rs 101 } 102 } 103 104 func Join111[E any](s1, s2, s3 []E) []E { 105 rs := make([]E, len(s1)+len(s2)+len(s3)) 106 sp := copy(rs, s1) 107 sp += copy(rs[sp:], s2) 108 copy(rs[sp:], s3) 109 return rs 110 } 111 112 func Locate[E any](cs [][]E, index int) (int, int) { 113 i := index 114 for j, chunk := range cs { 115 if i < len(chunk) { 116 return j, i 117 } 118 i -= len(chunk) 119 } 120 GoPanicIndex(index, index-i) 121 return 0, 0 122 } 123 124 func LocateStart[E any](cs [][]E, start int) (int, int) { 125 if len(cs) == 0 { 126 return 0, 0 127 } 128 i := start 129 for j, chunk := range cs { 130 if i < len(chunk) { 131 return j, i 132 } 133 i -= len(chunk) 134 } 135 if i > 0 { 136 GoPanicSliceAlen(start, start-i) 137 } 138 return len(cs) - 1, len(cs[len(cs)-1]) 139 } 140 141 func LocateEnd[E any](cs [][]E, end int) (int, int) { 142 if len(cs) == 0 { 143 return 0, 0 144 } 145 i := end 146 for j, chunk := range cs { 147 if i <= len(chunk) { 148 return j, i 149 } 150 i -= len(chunk) 151 } 152 GoPanicSliceAlen(end, end-i) 153 return 0, 0 154 } 155 156 func TrimChunks[E any](chunks [][]E) [][]E { 157 return TrimChunksEnd(TrimChunksStart(chunks)) 158 } 159 160 func TrimChunksStart[E any](chunks [][]E) [][]E { 161 for len(chunks) > 0 { 162 if len(chunks[0]) == 0 { 163 chunks = chunks[1:] 164 } else { 165 break 166 } 167 } 168 return chunks 169 } 170 171 func TrimChunksEnd[E any](chunks [][]E) [][]E { 172 for i := len(chunks) - 1; i >= 0; i-- { 173 if len(chunks[i]) == 0 { 174 chunks = chunks[:i] 175 } else { 176 break 177 } 178 } 179 return chunks 180 } 181 182 func (cs Chunks[E]) Len() int { 183 var l int 184 for _, c := range cs { 185 l += len(c) 186 } 187 return l 188 } 189 190 func (cs Chunks[E]) Get(i int) E { 191 x, y := Locate(cs, i) 192 return cs[x][y] 193 } 194 195 func (cs Chunks[E]) Pointer(i int) *E { 196 x, y := Locate(cs, i) 197 return &cs[x][y] 198 } 199 200 func (cs Chunks[E]) First() (e E, exist bool) { 201 cs = cs.TrimStart() 202 if len(cs) == 0 { 203 return 204 } 205 return cs[0][0], true 206 } 207 208 func (cs Chunks[E]) FirstPointer() *E { 209 cs = cs.TrimStart() 210 if len(cs) == 0 { 211 return nil 212 } 213 return &cs[0][0] 214 } 215 216 func (cs Chunks[E]) Last() (e E, exist bool) { 217 cs = cs.TrimEnd() 218 if len(cs) == 0 { 219 return 220 } 221 c := cs[len(cs)-1] 222 return c[len(c)-1], true 223 } 224 225 func (cs Chunks[E]) LastPointer() *E { 226 cs = cs.TrimEnd() 227 if len(cs) == 0 { 228 return nil 229 } 230 c := cs[len(cs)-1] 231 return &c[len(c)-1] 232 } 233 234 func (cs Chunks[E]) TrimStart() Chunks[E] { 235 return TrimChunksStart(cs) 236 } 237 238 func (cs Chunks[E]) TrimEnd() Chunks[E] { 239 return TrimChunksEnd(cs) 240 } 241 242 func (cs Chunks[E]) Trim() Chunks[E] { 243 return TrimChunks(cs) 244 } 245 246 func (cs Chunks[E]) sliceFrom(sx, sy int) []E { 247 if len(cs) == 0 { 248 return nil 249 } 250 return Join1N(cs[sx][sy:], cs[sx+1:]) 251 } 252 253 func (cs Chunks[E]) sliceTo(ex, ey int) []E { 254 if len(cs) == 0 { 255 return nil 256 } 257 return JoinN1(cs[:ex], cs[ex][:ey]) 258 } 259 260 func (cs Chunks[E]) slice(sx, sy, ex, ey int) []E { 261 if len(cs) == 0 { 262 return nil 263 } 264 switch { 265 case sx > ex: 266 return nil 267 case sx == ex: 268 return cs[sx][sy:ey] 269 case sx == ex-1: 270 return Join11(cs[sx][sy:], cs[ex][:ey]) 271 default: 272 return Join1N1(cs[sx][sy:], cs[sx+1:ex], cs[ex][:ey]) 273 } 274 } 275 276 func (cs Chunks[E]) Slice(start, end int) []E { 277 if start >= 0 && end >= 0 { 278 if start > end { 279 GoPanicSliceB(start, end) 280 } 281 cs = cs.TrimStart().TrimEnd() 282 sx, sy := LocateStart(cs, start) 283 ex, ey := LocateEnd(cs, end) 284 return cs.slice(sx, sy, ex, ey) 285 } 286 cs = cs.TrimStart().TrimEnd() 287 switch { 288 case start < 0 && end < 0: 289 return Join(cs) 290 case start < 0: 291 return cs.sliceTo(LocateEnd(cs, end)) 292 default: 293 return cs.sliceFrom(LocateStart(cs, start)) 294 } 295 } 296 297 func (cs Chunks[E]) cutFrom(sx, sy int) Chunks[E] { 298 if len(cs) == 0 { 299 return nil 300 } 301 if sy == 0 { 302 return cs[sx:] 303 } 304 return Join11(Chunks[E]{cs[sx][sy:]}, cs[sx+1:]) 305 } 306 307 func (cs Chunks[E]) cutTo(ex, ey int) Chunks[E] { 308 if len(cs) == 0 { 309 return nil 310 } 311 if ey == len(cs[ex]) { 312 return cs[:ex+1] 313 } 314 return Join11(cs[:ex], Chunks[E]{cs[ex][:ey]}) 315 } 316 317 func (cs Chunks[E]) cut(sx, sy, ex, ey int) Chunks[E] { 318 if len(cs) == 0 { 319 return nil 320 } 321 switch { 322 case sx > ex: 323 return nil 324 case sx == ex: 325 return Chunks[E]{cs[sx][sy:ey]} 326 case sx == ex-1: 327 return Chunks[E]{cs[sx][sy:], cs[ex][:ey]} 328 default: 329 if sy == 0 && ey == len(cs[ex]) { 330 return cs[sx : ex+1] 331 } 332 return Join111(Chunks[E]{cs[sx][sy:]}, cs[sx+1:ex], Chunks[E]{cs[ex][:ey]}) 333 } 334 } 335 336 func (cs Chunks[E]) Cut(start, end int) Chunks[E] { 337 if start >= 0 && end >= 0 { 338 if start > end { 339 GoPanicSliceB(start, end) 340 } 341 cs = cs.TrimStart().TrimEnd() 342 sx, sy := LocateStart(cs, start) 343 ex, ey := LocateEnd(cs, end) 344 return cs.cut(sx, sy, ex, ey) 345 } 346 cs = cs.TrimStart().TrimEnd() 347 switch { 348 case start < 0 && end < 0: 349 return cs 350 case start < 0: 351 return cs.cutTo(LocateEnd(cs, end)) 352 default: 353 return cs.cutFrom(LocateStart(cs, start)) 354 } 355 } 356 357 func (cs Chunks[E]) Set(i int, e E) { 358 *cs.Pointer(i) = e 359 } 360 361 func (cs Chunks[E]) GetAndSet(i int, e E) (old E) { 362 ptr := cs.Pointer(i) 363 old = *ptr 364 *ptr = e 365 return 366 } 367 368 func (cs Chunks[E]) Swap(i, j int) { 369 x1, y1 := Locate(cs, i) 370 x2, y2 := Locate(cs, j) 371 cs[x1][y1], cs[x2][y2] = cs[x2][y2], cs[x1][y1] 372 }