github.com/haraldrudell/parl@v0.4.176/pslices/slice-away-append_test.go (about) 1 /* 2 © 2024–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package pslices 7 8 import ( 9 "slices" 10 "testing" 11 ) 12 13 // There are three outcomes for a slice-away append: 14 // - 1 realloc: the result is larger than the underlying array 15 // - 2 append: appending fits slicedAway capacity 16 // - 3 copy: appending to SlicedAway fits the underlying array but 17 // not slicedAway capacity 18 19 func TestSliceAwayAppend_Realloc(t *testing.T) { 20 //t.Error("logging on") 21 var ( 22 // unsliced slice0 23 slice00 = []int{1, 2, 3} 24 // values to append 4 5 6 25 values = []int{4, 5, 6} 26 // slice-away index for 1-element slicedAway slice 27 slicedAwayIndex = 1 28 // expected slice0 slicedAway result: 2, 4, 5, 6 29 expSlice0 = append([]int{slice00[slicedAwayIndex]}, values...) 30 ) 31 32 var ( 33 offset int 34 isValid bool 35 ) 36 37 var slice0 = slice00 38 var slicedAway = slice0[slicedAwayIndex : slicedAwayIndex+1] 39 // before: slice0: [1 2 3] slicedAway: [2] values: [4 5 6] 40 t.Logf("before: slice0: %v slicedAway: %v values: %v", slice0, slicedAway, values) 41 SliceAwayAppend(&slicedAway, &slice0, values) 42 // after: slice0: [2 4 5 6] slicedAway: [2 4 5 6] 43 t.Logf("after: slice0: %v slicedAway: %v", slice0, slicedAway) 44 45 // slicedAway value should match 46 if !slices.Equal(slicedAway, expSlice0) { 47 t.Errorf("FAIL slicedAway %v exp %v", slicedAway, expSlice0) 48 } 49 50 // slice0 value should match 51 if !slices.Equal(slice0, expSlice0) { 52 t.Errorf("FAIL slice0 %v exp %v", slice0, expSlice0) 53 } 54 55 // slice0 and slicedAway should share underlying array 56 offset, isValid = Offset(slice0, slicedAway) 57 _ = offset 58 if !isValid { 59 t.Error("FAIL slice0 slicedAway not same underlying array") 60 } 61 62 // slice0 should be reallocated away from slice00 63 offset, isValid = Offset(slice0, slice00) 64 _ = offset 65 if isValid { 66 t.Error("FAIL slice0 slice00 is same underlying array") 67 } 68 } 69 70 func TestSliceAwayAppend_Append(t *testing.T) { 71 //t.Error("logging on") 72 var ( 73 // a slice with all values known 1 2 3 4 74 slice00 = []int{1, 2, 3, 4} 75 // values to append 5 76 values = []int{5} 77 // slice-away index for 1-element slicedAway slice 78 sliceAwayIndex = 1 79 // 1 2 5 4 80 expSlice0 = append(append(slices.Clone(slice00[:sliceAwayIndex+1]), values...), slice00[sliceAwayIndex+1+len(values):]...) 81 // 2 5 82 expSlicedAway = append([]int{slice00[sliceAwayIndex]}, values...) 83 ) 84 85 var ( 86 offset int 87 isValid bool 88 ) 89 90 var slice0 = slice00 91 var slicedAway = slice0[sliceAwayIndex : sliceAwayIndex+1] 92 // before: slice0: [1 2 3 4] slicedAway: [2] values: [5] 93 t.Logf("before: slice0: %v slicedAway: %v values: %v", slice0, slicedAway, values) 94 SliceAwayAppend(&slicedAway, &slice0, values) 95 // after: slice0: [1 2 5 4] slicedAway: [2 5] 96 t.Logf("after: slice0: %v slicedAway: %v", slice0, slicedAway) 97 98 // slicedAway value should match 99 if !slices.Equal(slicedAway, expSlicedAway) { 100 t.Errorf("FAIL slicedAway %v exp %v", slicedAway, expSlicedAway) 101 } 102 103 // slice0 value should match 104 if !slices.Equal(slice0, expSlice0) { 105 t.Errorf("FAIL slice0 %v exp %v", slice0, expSlice0) 106 } 107 108 // slice0 and slicedAway should share underlying array 109 offset, isValid = Offset(slice0, slicedAway) 110 _ = offset 111 if !isValid { 112 t.Error("FAIL slice0 slicedAway not same underlying array") 113 } 114 115 // slice0 and slice00 should share underlying array 116 offset, isValid = Offset(slice0, slice00) 117 _ = offset 118 if !isValid { 119 t.Error("FAIL slice0 slice00 not same underlying array") 120 } 121 } 122 123 func TestSliceAwayAppend_Copy(t *testing.T) { 124 //t.Error("logging on") 125 // requirements: 126 // - slicedAway and values should fit slice00 127 // - slicedAway should be sliced away so far that its capacity cannot 128 // fit values 129 // - the last element of slice00 should be untouched 130 // - the second-to-last element of slice00 should be zeroed out 131 // - slicedAway can be length 1 132 // - therefore, values must be at least length 2 133 // - values and slicedAway must be less than the second to last element of slicedAway 134 // - calc: 2 + 1 < len(slice00) - 2: slice00 is length 5 135 var ( 136 // unsliced slice0 137 slice00 = []int{1, 2, 3, 4, 5} 138 // values to append 5 139 values = []int{6, 7} 140 slicedAwayIndex0 = len(slice00) - 2 141 slicedAwayIndex1 = len(slice00) - 1 142 // 4, 6, 7, 0, 5 143 expSlice0 = append( 144 append( 145 append( 146 // slicedAway 147 slices.Clone(slice00[slicedAwayIndex0:slicedAwayIndex1]), 148 // values 149 values..., 150 ), 151 // zero-out 152 0, 153 ), 154 // 5 155 slice00[slicedAwayIndex1:]..., 156 ) 157 // 3 5 158 expSliceAway = expSlice0[:slicedAwayIndex1-slicedAwayIndex0+len(values)] 159 ) 160 161 var ( 162 offset int 163 isValid bool 164 ) 165 166 // re-use slice should work 167 var slice0 = slice00 168 var slicedAway = slice0[slicedAwayIndex0:slicedAwayIndex1] 169 // before: slice0: [1 2 3 4 5] slicedAway: [4] values: [6 7] 170 t.Logf("before: slice0: %v slicedAway: %v values: %v", slice0, slicedAway, values) 171 SliceAwayAppend(&slicedAway, &slice0, values) 172 // after: slice0: [4 6 7 0 5] slicedAway: [4 6 7] 173 t.Logf("after: slice0: %v slicedAway: %v", slice0, slicedAway) 174 175 // slicedAway should match 176 if !slices.Equal(slicedAway, expSliceAway) { 177 t.Errorf("FAIL slicedAway %v exp %v", slicedAway, expSliceAway) 178 } 179 180 // slice0 should match 181 if !slices.Equal(slice0, expSlice0) { 182 t.Errorf("FAIL slice0 %v exp %v", slice0, expSlice0) 183 } 184 // slice0 and slicedAway should share underlying array 185 offset, isValid = Offset(slice0, slicedAway) 186 _ = offset 187 if !isValid { 188 t.Error("FAIL slice0 slicedAway not same underlying array") 189 } 190 191 // slice0 and slice00 should share underlying array 192 offset, isValid = Offset(slice0, slice00) 193 _ = offset 194 if !isValid { 195 t.Error("FAIL slice0 slice00 not same underlying array") 196 } 197 } 198 199 func TestSliceAwayAppend1_Realloc(t *testing.T) { 200 //t.Error("logging on") 201 var ( 202 // unsliced slice0 203 slice00 = []int{1} 204 // values to append 4 5 6 205 value = 4 206 // expected slice0 slicedAway result: 2, 4, 5, 6 207 expSlice0 = append(slices.Clone(slice00), value) 208 ) 209 210 var ( 211 offset int 212 isValid bool 213 ) 214 215 var slice0 = slice00 216 var slicedAway = slice0 217 // before: slice0: [1] slicedAway: [1] value: 4 218 t.Logf("before: slice0: %v slicedAway: %v value: %v", slice0, slicedAway, value) 219 SliceAwayAppend1(&slicedAway, &slice0, value) 220 // after: slice0: [1 4] slicedAway: [1 4] 221 t.Logf("after: slice0: %v slicedAway: %v", slice0, slicedAway) 222 223 // slicedAway value should match 224 if !slices.Equal(slicedAway, expSlice0) { 225 t.Errorf("FAIL slicedAway %v exp %v", slicedAway, expSlice0) 226 } 227 228 // slice0 value should match 229 if !slices.Equal(slice0, expSlice0) { 230 t.Errorf("FAIL slice0 %v exp %v", slice0, expSlice0) 231 } 232 233 // slice0 and slicedAway should share underlying array 234 offset, isValid = Offset(slice0, slicedAway) 235 _ = offset 236 if !isValid { 237 t.Error("FAIL slice0 slicedAway not same underlying array") 238 } 239 240 // slice0 should be reallocated away from slice00 241 offset, isValid = Offset(slice0, slice00) 242 _ = offset 243 if isValid { 244 t.Error("FAIL slice0 slice00 is same underlying array") 245 } 246 } 247 248 func TestSliceAwayAppend1_Append(t *testing.T) { 249 //t.Error("logging on") 250 var ( 251 // a slice with all values known 1 2 3 4 252 slice00 = []int{1, 2, 3, 4} 253 // values to append 5 254 value = 5 255 // slice-away index for 1-element slicedAway slice 256 sliceAwayIndex = 1 257 // 1 2 5 4 258 expSlice0 = append(append(slices.Clone(slice00[:sliceAwayIndex+1]), value), slice00[sliceAwayIndex+2:]...) 259 // 2 5 260 expSlicedAway = append([]int{slice00[sliceAwayIndex]}, value) 261 ) 262 263 var ( 264 offset int 265 isValid bool 266 ) 267 268 var slice0 = slice00 269 var slicedAway = slice0[sliceAwayIndex : sliceAwayIndex+1] 270 // before: slice0: [1 2 3 4] slicedAway: [2] value: 5 271 t.Logf("before: slice0: %v slicedAway: %v value: %v", slice0, slicedAway, value) 272 SliceAwayAppend1(&slicedAway, &slice0, value) 273 // after: slice0: [1 2 5 4] slicedAway: [2 5] 274 t.Logf("after: slice0: %v slicedAway: %v", slice0, slicedAway) 275 276 // slicedAway value should match 277 if !slices.Equal(slicedAway, expSlicedAway) { 278 t.Errorf("FAIL slicedAway %v exp %v", slicedAway, expSlicedAway) 279 } 280 281 // slice0 value should match 282 if !slices.Equal(slice0, expSlice0) { 283 t.Errorf("FAIL slice0 %v exp %v", slice0, expSlice0) 284 } 285 286 // slice0 and slicedAway should share underlying array 287 offset, isValid = Offset(slice0, slicedAway) 288 _ = offset 289 if !isValid { 290 t.Error("FAIL slice0 slicedAway not same underlying array") 291 } 292 293 // slice0 and slice00 should share underlying array 294 offset, isValid = Offset(slice0, slice00) 295 _ = offset 296 if !isValid { 297 t.Error("FAIL slice0 slice00 not same underlying array") 298 } 299 } 300 301 func TestSliceAwayAppend1_Copy(t *testing.T) { 302 //t.Error("logging on") 303 // requirements: 304 // - to force a copy while appending a single element, 305 // slicedAway must be at the end of slice0 306 // - slicedAway and values should fit slice00 307 // - the last element of slice00 should be zeroed out 308 // - slicedAway can be length 1 309 // - for zero-out to happen, slice0 must be longer than 310 // slicedAway and value 311 // - len(slice00) = len(slicedAway) = len(value) + 1: 3 312 var ( 313 // unsliced slice0 314 slice00 = []int{1, 2, 3} 315 // values to append 5 316 value = 4 317 slicedAwayIndex0 = len(slice00) - 1 318 slicedAwayIndex1 = len(slice00) 319 // 3, 4, 0 320 expSlice0 = append( 321 append( 322 // slicedAway 323 slices.Clone(slice00[slicedAwayIndex0:slicedAwayIndex1]), 324 // values 325 value, 326 ), 327 // zero-out 328 0, 329 ) 330 // 3 4 331 expSliceAway = expSlice0[:slicedAwayIndex1-slicedAwayIndex0+1] 332 ) 333 334 var ( 335 offset int 336 isValid bool 337 ) 338 339 // re-use slice should work 340 var slice0 = slice00 341 var slicedAway = slice0[slicedAwayIndex0:slicedAwayIndex1] 342 // before: slice0: [1 2 3] slicedAway: [3] values: 4 343 t.Logf("before: slice0: %v slicedAway: %v values: %v", slice0, slicedAway, value) 344 SliceAwayAppend1(&slicedAway, &slice0, value) 345 // after: slice0: [3 4 0] slicedAway: [3 4] 346 t.Logf("after: slice0: %v slicedAway: %v", slice0, slicedAway) 347 348 // slicedAway should match 349 if !slices.Equal(slicedAway, expSliceAway) { 350 t.Errorf("FAIL slicedAway %v exp %v", slicedAway, expSliceAway) 351 } 352 353 // slice0 should match 354 if !slices.Equal(slice0, expSlice0) { 355 t.Errorf("FAIL slice0 %v exp %v", slice0, expSlice0) 356 } 357 // slice0 and slicedAway should share underlying array 358 offset, isValid = Offset(slice0, slicedAway) 359 _ = offset 360 if !isValid { 361 t.Error("FAIL slice0 slicedAway not same underlying array") 362 } 363 364 // slice0 and slice00 should share underlying array 365 offset, isValid = Offset(slice0, slice00) 366 _ = offset 367 if !isValid { 368 t.Error("FAIL slice0 slice00 not same underlying array") 369 } 370 } 371 372 func TestOffset(t *testing.T) { 373 //t.Error("logging on") 374 var size = 3 375 var sliceIndex = 2 376 377 var offset int 378 var isValid bool 379 380 var slice0 = make([]int, size) 381 var slicedAway = slice0[sliceIndex:] 382 offset, isValid = Offset(slice0, slicedAway) 383 // offset: 2 isValid: true 384 t.Logf("offset: %d isValid: %t", offset, isValid) 385 if !isValid { 386 t.Error("FAIL isValid false") 387 } 388 if offset != sliceIndex { 389 t.Errorf("FAIL bad offset %d exp %d", offset, sliceIndex) 390 } 391 }