<small>Discover Insane Possibility of Go Slice Usage from Runtime Source Code</small> === <!-- .slide: data-background-color="pink" --> <!-- .slide: data-transition="zoom" --> > [name=郭學聰 Hsueh-Tsung Kuo] > [time=Sat, 31 Jul 2021] [color=red] ###### CC BY-SA 4.0 --- <!-- .slide: data-transition="convex" --> ## Who am I? ![fieliapm](https://www.gravatar.com/avatar/2aef78f04240a6ac9ccd473ba1cbd1e3?size=2048 =384x384) <small>Someone (who?) said: a game programmer should be able to draw cute anime character(?)</small> ---- <!-- .slide: data-transition="convex" --> * A programmer from game company in Taiwan * Backend (and temporary frontend) engineer * Usually develop something related to my work in Python, Ruby, ECMAScript, Golang, C# * ECMAScript hater since **Netscape** is dead * Built CDN-aware game asset update system * Professional small vehicle driver * Draw cute anime character in spare time --- <!-- .slide: data-transition="convex" --> ## Outline ---- <!-- .slide: data-transition="convex" --> 4. What is Slice? * Array * Slice ---- <!-- .slide: data-transition="convex" --> 5. Source Code of Slice Implementation * Runtime * Slice Structure * Caution * Utility Functions * Where is append()? * Compile Time * Slice Operation * Accessing Slice Elements * Re-slicing * Machine Code Optimization ---- <!-- .slide: data-transition="convex" --> 6. Insane Slice Application * SliceTricks * Application in Algorithm * One More Thing 7. Conclusion 8. Resource 9. Q&A --- <!-- .slide: data-transition="convex" --> ## What is Slice? ---- <!-- .slide: data-transition="convex" --> ### Array ```go= var a [4]int a[0] = 1 i := a[0] // i == 1 // a[2] == 0, the zero value of the int type ``` ---- <!-- .slide: data-transition="convex" --> #### Array Structure ![array](https://blog.golang.org/slices-intro/slice-array.png) ---- <!-- .slide: data-transition="convex" --> #### Array Literal ```go= b := [2]string{"Penn", "Teller"} // make the compiler count the array elements b := [...]string{"Penn", "Teller"} ``` ---- <!-- .slide: data-transition="convex" --> ### Slice ```go= func make([]T, len, cap) []T var s []byte s = make([]byte, 5, 5) // s == []byte{0, 0, 0, 0, 0} ``` ---- <!-- .slide: data-transition="convex" --> ### Slice ```go= s := make([]byte, 5) len(s) == 5 cap(s) == 5 ``` ---- <!-- .slide: data-transition="convex" --> #### Slice Structure ![slice_struct](https://blog.golang.org/slices-intro/slice-struct.png) ![slice_struct](https://blog.golang.org/slices-intro/slice-1.png) ---- <!-- .slide: data-transition="convex" --> #### Slice Literal ```go= letters := []string{"a", "b", "c", "d"} ``` --- <!-- .slide: data-transition="convex" --> ## Source Code of Slice Implementation ---- <!-- .slide: data-transition="convex" --> ### Runtime <small>https://github.com/golang/go/blob/go1.16.5/src/runtime/slice.go</small> ---- <!-- .slide: data-transition="convex" --> #### Slice Structure ```go= type slice struct { array unsafe.Pointer len int cap int } ``` ---- <!-- .slide: data-transition="convex" --> ##### Caution * Underlying arrays of slices are mutable * Slices themselves are immutable * Call by value ---- <!-- .slide: data-transition="convex" --> #### Utility Functions ```go= func makeslice(et *_type, len, cap int) unsafe.Pointer func growslice(et *_type, old slice, cap int) slice func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) append() // where? ``` ---- <!-- .slide: data-transition="convex" --> #### Where is append()? <small>https://github.com/golang/go/blob/go1.16.5/src/cmd/compile/internal/gc/ssa.go#L2841</small> ---- <!-- .slide: data-transition="convex" --> ### Compile Time <small>https://github.com/golang/go/blob/go1.16.5/src/cmd/compile/internal/gc/ssa.go#L5458</small> ---- <!-- .slide: data-transition="convex" --> #### Slice Operation * Accessing slice elements * Re-slicing ---- <!-- .slide: data-transition="convex" --> ##### Accessing Slice Elements * slice * string * pointer ```go= val := s[2] s[3] = val ``` ---- <!-- .slide: data-transition="convex" --> ##### Re-slicing * slice * string * pointer ```go= // i : begin index (include) // j : end index (exclude) // k : index of capacity boundary (exclude) s := v[i:j:k] ``` ---- <!-- .slide: data-transition="convex" --> ###### Boundary Checking ```go= // k <= cap(v) // j <= k s := v[i:j:k] ``` * :heavy_check_mark: "len(s) > len(v)" <!-- .element: class="fragment" data-fragment-index="1" --> * if capacity of underlying array is enough <!-- .element: class="fragment" data-fragment-index="2" --> * :x: **string** doesn't have cap property <!-- .element: class="fragment" data-fragment-index="3" --> ---- <!-- .slide: data-transition="convex" --> ###### New Slice Caculation ```go= // Calculate the base pointer (rptr) for the new slice. // // Generate the following code assuming that indexes are in bounds. // The masking is to make sure that we don't generate a slice // that points to the next object in memory. We cannot just set // the pointer to nil because then we would create a nil slice or // string. // // rcap = k - i // rlen = j - i // rptr = ptr + (mask(rcap) & (i * stride)) // // Where mask(x) is 0 if x==0 and -1 if x>0 and stride is the width // of the element type. ``` ---- <!-- .slide: data-transition="convex" --> #### Machine Code Optimization * Re-slicing * Not atomic * Instruction might be interleaved in optimized assembly code * Discard boundary checking operation * If compiler detects that overflow will not happen <!-- .element: class="fragment" data-fragment-index="1" --> --- <!-- .slide: data-transition="convex" --> ## Insane Slice Application ---- <!-- .slide: data-transition="convex" --> ### SliceTricks * Official * <small>https://github.com/golang/go/wiki/SliceTricks</small> * Graphics by @ueokande * <small>https://ueokande.github.io/go-slice-tricks/</small> ---- <!-- .slide: data-transition="convex" --> #### AppendVector ![AppendVector1](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/AppendVector1.svg) ![AppendVector2](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/AppendVector2.svg) ```go= a = append(a, b...) ``` ---- <!-- .slide: data-transition="convex" --> #### Copy ![Copy](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Copy.svg) ```go= b = make([]T, len(a)) copy(b, a) ``` ```go= b = append([]T(nil), a...) ``` ```go= b = append(a[:0:0], a...) ``` ---- <!-- .slide: data-transition="convex" --> #### Cut ![Cut](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Cut.svg) ```go= a = append(a[:i], a[j:]...) ``` ---- <!-- .slide: data-transition="convex" --> #### Delete ![Delete1](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Delete1.svg) ```go= a = append(a[:i], a[i+1:]...) ``` ```go= a = a[:i+copy(a[i:], a[i+1:])] ``` ---- <!-- .slide: data-transition="convex" --> #### Delete without preserving order ![DeleteWithoutPreservingOrder](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/DeleteWithoutPreservingOrder.svg) ```go= a[i] = a[len(a)-1] a = a[:len(a)-1] ``` ---- <!-- .slide: data-transition="convex" --> #### Cut (GC) ![CutGC](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/CutGC.svg) ```go= copy(a[i:], a[j:]) for k, n := len(a)-j+i, len(a); k < n; k++ { a[k] = nil // or the zero value of T } a = a[:len(a)-j+i] ``` ---- <!-- .slide: data-transition="convex" --> #### Delete (GC) ![DeleteGC](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/DeleteGC.svg) ```go= copy(a[i:], a[i+1:]) a[len(a)-1] = nil // or the zero value of T a = a[:len(a)-1] ``` ---- <!-- .slide: data-transition="convex" --> #### Delete without preserving order (GC) ![DeleteWithoutPreservingOrderGC](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/DeleteWithoutPreservingOrderGC.svg) ```go= a[i] = a[len(a)-1] a[len(a)-1] = nil a = a[:len(a)-1] ``` ---- <!-- .slide: data-transition="convex" --> #### Expand ![Expand](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Expand.svg) ```go= a = append(a[:i], append(make([]T, j), a[i:]...)...) ``` ---- <!-- .slide: data-transition="convex" --> #### Extend ![Extend](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Extend.svg) ```go= a = append(a, make([]T, j)...) ``` ---- <!-- .slide: data-transition="convex" --> #### Filter (in place) ![Filter](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Filter.svg) ```go= n := 0 for _, x := range a { if keep(x) { a[n] = x n++ } } a = a[:n] ``` ---- <!-- .slide: data-transition="convex" --> #### Insert ![Insert](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Insert.svg) ```go= a = append(a[:i], append([]T{x}, a[i:]...)...) ``` ---- <!-- .slide: data-transition="convex" --> #### InsertVector ![InsertVector](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/InsertVector.svg) ```go= a = append(a[:i], append(b, a[i:]...)...) ``` ---- <!-- .slide: data-transition="convex" --> #### Push ![Push](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Push.svg) ```go= a = append(a, x) ``` ---- <!-- .slide: data-transition="convex" --> #### Pop ![Extend](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Pop.svg) ```go= x, a = a[len(a)-1], a[:len(a)-1] ``` ---- <!-- .slide: data-transition="convex" --> #### Push Front/Unshift ![Unshift](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Unshift.svg) ```go= a = append([]T{x}, a...) ``` ---- <!-- .slide: data-transition="convex" --> #### Pop Front/Shift ![Shift](https://raw.githubusercontent.com/ueokande/go-slice-tricks/master/src/components/CheatSheet/Shift.svg) ```go= x, a = a[0], a[1:] ``` ---- <!-- .slide: data-transition="convex" --> ### Application in Algorithm ---- <!-- .slide: data-transition="convex" --> #### QuickSort ```go= func QuickSort(a []int) { if len(a) <= 1 { return } pivot := rand.Int() % len(a) left, right := 0, len(a)-1 a[pivot], a[right] = a[right], a[pivot] for i, _ := range a[:right] { if a[i] < a[right] { a[left], a[i] = a[i], a[left] left++ } } a[left], a[right] = a[right], a[left] QuickSort(a[:left]) QuickSort(a[left+1:]) } ``` ---- <!-- .slide: data-transition="convex" --> ### One More Thing ---- <!-- .slide: data-transition="convex" --> #### Slice Capacity :heavy_plus_sign: append() ```go= s := []int{1, 2, 3, 4, 5, 6, 7, 8} fmt.Printf("s == %v\n\n", s) s2 := s[1:4:5] fmt.Printf("s2 == %v\n\n", s2) s2 = append(s2, 15) fmt.Printf("s == %v\n", s) fmt.Printf("s2 == %v\n\n", s2) s3 := s2[:4:4] fmt.Printf("s3 == %v\n\n", s3) s2 = append(s2, 16) fmt.Printf("s == %v\n", s) fmt.Printf("s2 == %v\n\n", s2) ``` ---- <!-- .slide: data-transition="convex" --> #### Result ```go s == [1 2 3 4 5 6 7 8] s2 == [2 3 4] s == [1 2 3 4 15 6 7 8] s2 == [2 3 4 15] s3 == [2 3 4 15] s == [1 2 3 4 15 6 7 8] s2 == [2 3 4 15 16] ``` --- <!-- .slide: data-transition="convex" --> ## Conclusion ---- <!-- .slide: data-transition="convex" --> ### Slice is Invincible * Accessing slice elements * Re-slicing * append() ---- <!-- .slide: data-transition="convex" --> ### Bless :hash: {成為 slice 大師|<big>Become slice master</big>} > [name=郭學聰 Hsueh-Tsung Kuo] [time=2021_07_31] [color=red] :notebook: --- <!-- .slide: data-transition="convex" --> ## Resource ---- <!-- .slide: data-transition="convex" --> ### Reference * Slice introduction * <small>https://blog.golang.org/slices-intro</small> * Slice source code * <small>https://github.com/golang/go/blob/go1.16.5/src/runtime/slice.go</small> * <small>https://github.com/golang/go/blob/go1.16.5/src/cmd/compile/internal/gc/ssa.go</small> * SliceTricks * Official * <small>https://github.com/golang/go/wiki/SliceTricks</small> * Graphics by @ueokande * <small>https://ueokande.github.io/go-slice-tricks/</small> ---- <!-- .slide: data-transition="convex" --> ### Utility * Slides * Editor: HackMD * Presentation: Mozilla FireFox * Recording * OBS Studio * Panasonic DC-GH5 * LEICA DG SUMMILUX 15mm/F1.7 * Video Editing & Compositing * AviSynth official builds --- <!-- .slide: data-transition="zoom" --> ## Q&A --- <style> .reveal { background: #FFDFEF; color: black; } .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 { color: black; } .reveal code { font-size: 18px !important; line-height: 1.2; } .progress div{ height:14px !important; background: hotpink !important; } // original template .rightpart{ float:right; width:50%; } .leftpart{ margin-right: 50% !important; height:50%; } .reveal section img { background:none; border:none; box-shadow:none; } p.blo { font-size: 50px !important; background:#B6BDBB; border:1px solid silver; display:inline-block; padding:0.5em 0.75em; border-radius: 10px; box-shadow: 5px 5px 5px #666; } p.blo1 { background: #c7c2bb; } p.blo2 { background: #b8c0c8; } p.blo3 { background: #c7cedd; } p.bloT { font-size: 60px !important; background:#B6BDD3; border:1px solid silver; display:inline-block; padding:0.5em 0.75em; border-radius: 8px; box-shadow: 1px 2px 5px #333; } p.bloA { background: #B6BDE3; } p.bloB { background: #E3BDB3; } /*.slide-number{ margin-bottom:10px !important; width:100%; text-align:center; font-size:25px !important; background-color:transparent !important; }*/ iframe.myclass{ width:100px; height:100px; bottom:0; left:0; position:fixed; border:none; z-index:99999; } h1.raw { color: #fff; background-image: linear-gradient(90deg,#f35626,#feab3a); -webkit-background-clip: text; -webkit-text-fill-color: transparent; animation: hue 5s infinite linear; } @keyframes hue { from { filter: hue-rotate(0deg); } to { filter: hue-rotate(360deg); } } .progress{ height:14px !important; } .progress span{ height:14px !important; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAMCAIAAAAs6UAAAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUNCQzIyREQ0QjdEMTFFMzlEMDM4Qzc3MEY0NzdGMDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUNCQzIyREU0QjdEMTFFMzlEMDM4Qzc3MEY0NzdGMDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQ0JDMjJEQjRCN0QxMUUzOUQwMzhDNzcwRjQ3N0YwOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQ0JDMjJEQzRCN0QxMUUzOUQwMzhDNzcwRjQ3N0YwOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PovDFgYAAAAmSURBVHjaYvjPwMAAxjMZmBhA9H8INv4P4TPM/A+m04zBNECAAQBCWQv9SUQpVgAAAABJRU5ErkJggg==") repeat-x !important; } .progress span:after, .progress span.nyancat{ content: ""; background: url('data:image/gif;base64,R0lGODlhIgAVAKIHAL3/9/+Zmf8zmf/MmZmZmf+Z/wAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpDMkJBNjY5RTU1NEJFMzExOUM4QUM2MDAwNDQzRERBQyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCREIzOEIzMzRCN0IxMUUzODhEQjgwOTYzMTgyNTE0QiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCREIzOEIzMjRCN0IxMUUzODhEQjgwOTYzMTgyNTE0QiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkM1QkE2NjlFNTU0QkUzMTE5QzhBQzYwMDA0NDNEREFDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMyQkE2NjlFNTU0QkUzMTE5QzhBQzYwMDA0NDNEREFDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8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') !important; width: 34px !important; height: 21px !important; border: none !important; float:right; margin-top:-7px; margin-right:-10px; } </style>
{"metaMigratedAt":"2023-06-16T03:50:13.586Z","metaMigratedFrom":"YAML","title":"Discover Insane Possibility of Go Slice Usage from Runtime Source Code","breaks":true,"description":"View the slide with \"Slide Mode\".","slideOptions":"{\"spotlight\":{\"enabled\":false},\"allottedMinutes\":25}","contributors":"[{\"id\":\"ea27dcd7-a3f2-47c2-b25e-6760e7936c38\",\"add\":57676,\"del\":36697}]"}
    524 views