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  }