github.com/primecitizens/pcz/std@v0.2.1/builtin/slice/grow.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 // 4 // Copyright 2021 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 package stdslice 9 10 import ( 11 "unsafe" 12 13 "github.com/primecitizens/pcz/std/core/alloc" 14 "github.com/primecitizens/pcz/std/core/assert" 15 ) 16 17 func Append[E any, Alloc alloc.M](alloc Alloc, dst []E, elems ...E) []E { 18 assert.TODO() 19 return dst 20 } 21 22 // Grow increases the slice's capacity, if necessary, to guarantee space for 23 // another n elements. After Grow(n), at least n elements can be appended 24 // to the slice without another allocation. If n is negative or too large to 25 // allocate the memory, Grow panics. 26 func Grow[E any, Alloc alloc.M](alloc Alloc, s []E, n int) []E { 27 if n < 0 { 28 assert.Throw("cannot", "be", "negative") 29 } 30 if n -= cap(s) - len(s); n > 0 { 31 s = Append(alloc, s[:cap(s)], make([]E, n)...)[:len(s)] 32 } 33 return s 34 } 35 36 // Insert inserts the values v... into s at index i, 37 // returning the modified slice. 38 // The elements at s[i:] are shifted up to make room. 39 // In the returned slice r, r[i] == v[0], 40 // and r[i+len(v)] == value originally at r[i]. 41 // Insert panics if i is out of range. 42 // This function is O(len(s) + len(v)). 43 func Insert[E any, Alloc alloc.M](alloc Alloc, s []E, i int, v ...E) []E { 44 m := len(v) 45 if m == 0 { 46 return s 47 } 48 n := len(s) 49 if i == n { 50 return Append(alloc, s, v...) 51 } 52 if n+m > cap(s) { 53 // Use append rather than make so that we bump the size of 54 // the slice up to the next storage class. 55 // This is what Grow does but we don't call Grow because 56 // that might copy the values twice. 57 s2 := Append(alloc, s[:i], make([]E, n+m-i)...) 58 copy(s2[i:], v) 59 copy(s2[i+m:], s[i:]) 60 return s2 61 } 62 s = s[:n+m] 63 64 // before: 65 // s: aaaaaaaabbbbccccccccdddd 66 // ^ ^ ^ ^ 67 // i i+m n n+m 68 // after: 69 // s: aaaaaaaavvvvbbbbcccccccc 70 // ^ ^ ^ ^ 71 // i i+m n n+m 72 // 73 // a are the values that don't move in s. 74 // v are the values copied in from v. 75 // b and c are the values from s that are shifted up in index. 76 // d are the values that get overwritten, never to be seen again. 77 78 if !overlaps(v, s[i+m:]) { 79 // Easy case - v does not overlap either the c or d regions. 80 // (It might be in some of a or b, or elsewhere entirely.) 81 // The data we copy up doesn't write to v at all, so just do it. 82 83 copy(s[i+m:], s[i:]) 84 85 // Now we have 86 // s: aaaaaaaabbbbbbbbcccccccc 87 // ^ ^ ^ ^ 88 // i i+m n n+m 89 // Note the b values are duplicated. 90 91 copy(s[i:], v) 92 93 // Now we have 94 // s: aaaaaaaavvvvbbbbcccccccc 95 // ^ ^ ^ ^ 96 // i i+m n n+m 97 // That's the result we want. 98 return s 99 } 100 101 // The hard case - v overlaps c or d. We can't just shift up 102 // the data because we'd move or clobber the values we're trying 103 // to insert. 104 // So instead, write v on top of d, then rotate. 105 copy(s[n:], v) 106 107 // Now we have 108 // s: aaaaaaaabbbbccccccccvvvv 109 // ^ ^ ^ ^ 110 // i i+m n n+m 111 112 rotateRight(s[i:], m) 113 114 // Now we have 115 // s: aaaaaaaavvvvbbbbcccccccc 116 // ^ ^ ^ ^ 117 // i i+m n n+m 118 // That's the result we want. 119 return s 120 } 121 122 // Replace replaces the elements s[i:j] by the given v, and returns the 123 // modified slice. Replace panics if s[i:j] is not a valid slice of s. 124 func Replace[E any, Alloc alloc.M](alloc Alloc, s []E, i, j int, v ...E) []E { 125 _ = s[i:j] // verify that i:j is a valid subslice 126 127 if i == j { 128 return Insert(alloc, s, i, v...) 129 } 130 if j == len(s) { 131 return Append(alloc, s[:i], v...) 132 } 133 134 tot := len(s[:i]) + len(v) + len(s[j:]) 135 if tot > cap(s) { 136 // Too big to fit, allocate and copy over. 137 s2 := Append(alloc, s[:i], make([]E, tot-i)...) // See Insert 138 copy(s2[i:], v) 139 copy(s2[i+len(v):], s[j:]) 140 return s2 141 } 142 143 r := s[:tot] 144 145 if i+len(v) <= j { 146 // Easy, as v fits in the deleted portion. 147 copy(r[i:], v) 148 if i+len(v) != j { 149 copy(r[i+len(v):], s[j:]) 150 } 151 return r 152 } 153 154 // We are expanding (v is bigger than j-i). 155 // The situation is something like this: 156 // (example has i=4,j=8,len(s)=16,len(v)=6) 157 // s: aaaaxxxxbbbbbbbbyy 158 // ^ ^ ^ ^ 159 // i j len(s) tot 160 // a: prefix of s 161 // x: deleted range 162 // b: more of s 163 // y: area to expand into 164 165 if !overlaps(r[i+len(v):], v) { 166 // Easy, as v is not clobbered by the first copy. 167 copy(r[i+len(v):], s[j:]) 168 copy(r[i:], v) 169 return r 170 } 171 172 // This is a situation where we don't have a single place to which 173 // we can copy v. Parts of it need to go to two different places. 174 // We want to copy the prefix of v into y and the suffix into x, then 175 // rotate |y| spots to the right. 176 // 177 // v[2:] v[:2] 178 // | | 179 // s: aaaavvvvbbbbbbbbvv 180 // ^ ^ ^ ^ 181 // i j len(s) tot 182 // 183 // If either of those two destinations don't alias v, then we're good. 184 y := len(v) - (j - i) // length of y portion 185 186 if !overlaps(r[i:j], v) { 187 copy(r[i:j], v[y:]) 188 copy(r[len(s):], v[:y]) 189 rotateRight(r[i:], y) 190 return r 191 } 192 if !overlaps(r[len(s):], v) { 193 copy(r[len(s):], v[:y]) 194 copy(r[i:j], v[y:]) 195 rotateRight(r[i:], y) 196 return r 197 } 198 199 // Now we know that v overlaps both x and y. 200 // That means that the entirety of b is *inside* v. 201 // So we don't need to preserve b at all; instead we 202 // can copy v first, then copy the b part of v out of 203 // v to the right destination. 204 k := startIdx(v, s[j:]) 205 copy(r[i:], v) 206 copy(r[i+len(v):], r[i+k:]) 207 return r 208 } 209 210 // Rotation algorithm explanation: 211 // 212 // rotate left by 2 213 // start with 214 // 0123456789 215 // split up like this 216 // 01 234567 89 217 // swap first 2 and last 2 218 // 89 234567 01 219 // join first parts 220 // 89234567 01 221 // recursively rotate first left part by 2 222 // 23456789 01 223 // join at the end 224 // 2345678901 225 // 226 // rotate left by 8 227 // start with 228 // 0123456789 229 // split up like this 230 // 01 234567 89 231 // swap first 2 and last 2 232 // 89 234567 01 233 // join last parts 234 // 89 23456701 235 // recursively rotate second part left by 6 236 // 89 01234567 237 // join at the end 238 // 8901234567 239 240 // TODO: There are other rotate algorithms. 241 // This algorithm has the desirable property that it moves each element exactly twice. 242 // The triple-reverse algorithm is simpler and more cache friendly, but takes more writes. 243 // The follow-cycles algorithm can be 1-write but it is not very cache friendly. 244 245 // rotateLeft rotates b left by n spaces. 246 // s_final[i] = s_orig[i+r], wrapping around. 247 func rotateLeft[E any](s []E, r int) { 248 for r != 0 && r != len(s) { 249 if r*2 <= len(s) { 250 swap(s[:r], s[len(s)-r:]) 251 s = s[:len(s)-r] 252 } else { 253 swap(s[:len(s)-r], s[r:]) 254 s, r = s[len(s)-r:], r*2-len(s) 255 } 256 } 257 } 258 259 func rotateRight[E any](s []E, r int) { 260 rotateLeft(s, len(s)-r) 261 } 262 263 // swap swaps the contents of x and y. x and y must be equal length and disjoint. 264 func swap[E any](x, y []E) { 265 for i := 0; i < len(x); i++ { 266 x[i], y[i] = y[i], x[i] 267 } 268 } 269 270 // overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap. 271 func overlaps[E any](a, b []E) bool { 272 if len(a) == 0 || len(b) == 0 { 273 return false 274 } 275 elemSize := unsafe.Sizeof(a[0]) 276 if elemSize == 0 { 277 return false 278 } 279 // TODO: use a runtime/unsafe facility once one becomes available. See issue 12445. 280 // Also see crypto/internal/alias/alias.go:AnyOverlap 281 return uintptr(unsafe.Pointer(&a[0])) <= uintptr(unsafe.Pointer(&b[len(b)-1]))+(elemSize-1) && 282 uintptr(unsafe.Pointer(&b[0])) <= uintptr(unsafe.Pointer(&a[len(a)-1]))+(elemSize-1) 283 } 284 285 // startIdx returns the index in haystack where the needle starts. 286 // prerequisite: the needle must be aliased entirely inside the haystack. 287 func startIdx[E any](haystack, needle []E) int { 288 p := &needle[0] 289 for i := range haystack { 290 if p == &haystack[i] { 291 return i 292 } 293 } 294 // TODO: what if the overlap is by a non-integral number of Es? 295 assert.Throw("needle", "not", "found") 296 return -1 297 }