feat: support go1.22
* feat: support go1.22 * Temporary fix for consistency tests due to language change in for loops * review: clean old files --------- Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
This commit is contained in:
2
.github/workflows/go-cross.yml
vendored
2
.github/workflows/go-cross.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.20', '1.21' ]
|
||||
go-version: [ '1.21', '1.22' ]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
include:
|
||||
|
||||
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.21'
|
||||
GO_VERSION: '1.22'
|
||||
GOLANGCI_LINT_VERSION: v1.55.2
|
||||
|
||||
jobs:
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
needs: linting
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.20', '1.21' ]
|
||||
go-version: [ '1.21', '1.22' ]
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v2
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
working-directory: ${{ github.workspace }}/go/src/github.com/traefik/yaegi
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.20', '1.21' ]
|
||||
go-version: [ '1.21', '1.22' ]
|
||||
|
||||
steps:
|
||||
- name: Set up Go ${{ matrix.go-version }}
|
||||
|
||||
13
Makefile
13
Makefile
@@ -27,4 +27,15 @@ tests:
|
||||
install.sh: .goreleaser.yml
|
||||
godownloader --repo=traefik/yaegi -o install.sh .goreleaser.yml
|
||||
|
||||
.PHONY: check gen_all_syscall gen_tests generate_downloader internal/cmd/extract/extract install
|
||||
generic_list = cmp/cmp.go slices/slices.go slices/sort.go slices/zsortanyfunc.go maps/maps.go \
|
||||
sync/oncefunc.go sync/atomic/type.go
|
||||
|
||||
# get_generic_src imports stdlib files containing generic symbols definitions
|
||||
get_generic_src:
|
||||
eval "`go env`"; echo $$GOROOT; gov=$${GOVERSION#*.}; gov=$${gov%.*}; \
|
||||
for f in ${generic_list}; do \
|
||||
nf=stdlib/generic/go1_$${gov}_`echo $$f | tr / _`.txt; echo "nf: $$nf"; \
|
||||
cat "$$GOROOT/src/$$f" > "$$nf"; \
|
||||
done
|
||||
|
||||
.PHONY: check gen_all_syscall internal/cmd/extract/extract get_generic_src install
|
||||
|
||||
@@ -17,7 +17,7 @@ It powers executable Go scripts and plugins, in embedded interpreters or interac
|
||||
* Works everywhere Go works
|
||||
* All Go & runtime resources accessible from script (with control)
|
||||
* Security: `unsafe` and `syscall` packages neither used nor exported by default
|
||||
* Support the latest 2 major releases of Go (Go 1.20 and Go 1.21)
|
||||
* Support the latest 2 major releases of Go (Go 1.21 and Go 1.22)
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -15,11 +15,10 @@ func main() {
|
||||
r := extendedRequest{}
|
||||
req := &r.Request
|
||||
|
||||
|
||||
fmt.Println(r)
|
||||
fmt.Println(req)
|
||||
fmt.Printf("%T\n", r.Request)
|
||||
fmt.Printf("%T\n", req)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {{ <nil> 0 0 map[] <nil> <nil> 0 [] false map[] map[] <nil> map[] <nil> <nil> <nil> <nil>} }
|
||||
// &{ <nil> 0 0 map[] <nil> <nil> 0 [] false map[] map[] <nil> map[] <nil> <nil> <nil> <nil>}
|
||||
// http.Request
|
||||
// *http.Request
|
||||
|
||||
@@ -478,7 +478,7 @@ func GetMinor(part string) string {
|
||||
return minor
|
||||
}
|
||||
|
||||
const defaultMinorVersion = 21
|
||||
const defaultMinorVersion = 22
|
||||
|
||||
func genBuildTags() (string, error) {
|
||||
version := runtime.Version()
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -15,6 +16,13 @@ import (
|
||||
"github.com/traefik/yaegi/stdlib/unsafe"
|
||||
)
|
||||
|
||||
// The following tests depend on an incompatible language change in go1.22, where `for` variables are now
|
||||
// defined in body (thus reallocated at each loop). We skip them until both supported versions behave the same.
|
||||
// We will remove this in Go1.23.
|
||||
var testsToSkipGo122 = map[string]bool{"closure9.go": true, "closure10.go": true, "closure11.go": true, "closure12.go": true}
|
||||
|
||||
var go122 = strings.HasPrefix(runtime.Version(), "go1.22")
|
||||
|
||||
func TestInterpConsistencyBuild(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("short mode")
|
||||
@@ -125,6 +133,9 @@ func TestInterpConsistencyBuild(t *testing.T) {
|
||||
if go121 && testsToSkipGo121[file.Name()] {
|
||||
continue
|
||||
}
|
||||
if go122 && testsToSkipGo122[file.Name()] {
|
||||
continue
|
||||
}
|
||||
|
||||
file := file
|
||||
t.Run(file.Name(), func(t *testing.T) {
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
//go:build go1.20 && !go1.21
|
||||
// +build go1.20,!go1.21
|
||||
|
||||
package generic
|
||||
|
||||
var Sources = []string{}
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package generic
|
||||
|
||||
|
||||
71
stdlib/generic/go1_22_cmp_cmp.go.txt
Normal file
71
stdlib/generic/go1_22_cmp_cmp.go.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cmp provides types and functions related to comparing
|
||||
// ordered values.
|
||||
package cmp
|
||||
|
||||
// Ordered is a constraint that permits any ordered type: any type
|
||||
// that supports the operators < <= >= >.
|
||||
// If future releases of Go add new ordered types,
|
||||
// this constraint will be modified to include them.
|
||||
//
|
||||
// Note that floating-point types may contain NaN ("not-a-number") values.
|
||||
// An operator such as == or < will always report false when
|
||||
// comparing a NaN value with any other value, NaN or not.
|
||||
// See the [Compare] function for a consistent way to compare NaN values.
|
||||
type Ordered interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 |
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
|
||||
~float32 | ~float64 |
|
||||
~string
|
||||
}
|
||||
|
||||
// Less reports whether x is less than y.
|
||||
// For floating-point types, a NaN is considered less than any non-NaN,
|
||||
// and -0.0 is not less than (is equal to) 0.0.
|
||||
func Less[T Ordered](x, y T) bool {
|
||||
return (isNaN(x) && !isNaN(y)) || x < y
|
||||
}
|
||||
|
||||
// Compare returns
|
||||
//
|
||||
// -1 if x is less than y,
|
||||
// 0 if x equals y,
|
||||
// +1 if x is greater than y.
|
||||
//
|
||||
// For floating-point types, a NaN is considered less than any non-NaN,
|
||||
// a NaN is considered equal to a NaN, and -0.0 is equal to 0.0.
|
||||
func Compare[T Ordered](x, y T) int {
|
||||
xNaN := isNaN(x)
|
||||
yNaN := isNaN(y)
|
||||
if xNaN && yNaN {
|
||||
return 0
|
||||
}
|
||||
if xNaN || x < y {
|
||||
return -1
|
||||
}
|
||||
if yNaN || x > y {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// isNaN reports whether x is a NaN without requiring the math package.
|
||||
// This will always return false if T is not floating-point.
|
||||
func isNaN[T Ordered](x T) bool {
|
||||
return x != x
|
||||
}
|
||||
|
||||
// Or returns the first of its arguments that is not equal to the zero value.
|
||||
// If no argument is non-zero, it returns the zero value.
|
||||
func Or[T comparable](vals ...T) T {
|
||||
var zero T
|
||||
for _, val := range vals {
|
||||
if val != zero {
|
||||
return val
|
||||
}
|
||||
}
|
||||
return zero
|
||||
}
|
||||
41
stdlib/generic/go1_22_generic.go
Normal file
41
stdlib/generic/go1_22_generic.go
Normal file
@@ -0,0 +1,41 @@
|
||||
//go:build go1.22
|
||||
// +build go1.22
|
||||
|
||||
package generic
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed go1_22_cmp_cmp.go.txt
|
||||
var cmpSource string
|
||||
|
||||
//go:embed go1_22_maps_maps.go.txt
|
||||
var mapsSource string
|
||||
|
||||
//go:embed go1_22_slices_slices.go.txt
|
||||
var slicesSource string
|
||||
|
||||
/*
|
||||
//go:embed go1_22_slices_sort.go.txt
|
||||
var slicesSource1 string
|
||||
|
||||
//go:embed go1_22_slices_zsortanyfunc.go.txt
|
||||
var slicesSource2 string
|
||||
|
||||
//go:embed go1_22_sync_oncefunc.go.txt
|
||||
var syncSource string
|
||||
|
||||
//go:embed go1_22_sync_atomic_type.go.txt
|
||||
var syncAtomicSource string
|
||||
*/
|
||||
|
||||
// Sources contains the list of generic packages source strings.
|
||||
var Sources = [...]string{
|
||||
cmpSource,
|
||||
mapsSource,
|
||||
slicesSource,
|
||||
// FIXME(marc): support the following.
|
||||
// slicesSource1,
|
||||
// slicesSource2,
|
||||
// syncAtomicSource,
|
||||
// syncSource,
|
||||
}
|
||||
68
stdlib/generic/go1_22_maps_maps.go.txt
Normal file
68
stdlib/generic/go1_22_maps_maps.go.txt
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package maps defines various functions useful with maps of any type.
|
||||
package maps
|
||||
|
||||
// Equal reports whether two maps contain the same key/value pairs.
|
||||
// Values are compared using ==.
|
||||
func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool {
|
||||
if len(m1) != len(m2) {
|
||||
return false
|
||||
}
|
||||
for k, v1 := range m1 {
|
||||
if v2, ok := m2[k]; !ok || v1 != v2 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// EqualFunc is like Equal, but compares values using eq.
|
||||
// Keys are still compared with ==.
|
||||
func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool {
|
||||
if len(m1) != len(m2) {
|
||||
return false
|
||||
}
|
||||
for k, v1 := range m1 {
|
||||
if v2, ok := m2[k]; !ok || !eq(v1, v2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// clone is implemented in the runtime package.
|
||||
func clone(m any) any {
|
||||
return m
|
||||
}
|
||||
|
||||
// Clone returns a copy of m. This is a shallow clone:
|
||||
// the new keys and values are set using ordinary assignment.
|
||||
func Clone[M ~map[K]V, K comparable, V any](m M) M {
|
||||
// Preserve nil in case it matters.
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return clone(m).(M)
|
||||
}
|
||||
|
||||
// Copy copies all key/value pairs in src adding them to dst.
|
||||
// When a key in src is already present in dst,
|
||||
// the value in dst will be overwritten by the value associated
|
||||
// with the key in src.
|
||||
func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) {
|
||||
for k, v := range src {
|
||||
dst[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteFunc deletes any key/value pairs from m for which del returns true.
|
||||
func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) {
|
||||
for k, v := range m {
|
||||
if del(k, v) {
|
||||
delete(m, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
518
stdlib/generic/go1_22_slices_slices.go.txt
Normal file
518
stdlib/generic/go1_22_slices_slices.go.txt
Normal file
@@ -0,0 +1,518 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package slices defines various functions useful with slices of any type.
|
||||
package slices
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
// TODO(marc) fix this. "unsafe"
|
||||
)
|
||||
|
||||
// Equal reports whether two slices are equal: the same length and all
|
||||
// elements equal. If the lengths are different, Equal returns false.
|
||||
// Otherwise, the elements are compared in increasing index order, and the
|
||||
// comparison stops at the first unequal pair.
|
||||
// Floating point NaNs are not considered equal.
|
||||
func Equal[S ~[]E, E comparable](s1, s2 S) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
for i := range s1 {
|
||||
if s1[i] != s2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// EqualFunc reports whether two slices are equal using an equality
|
||||
// function on each pair of elements. If the lengths are different,
|
||||
// EqualFunc returns false. Otherwise, the elements are compared in
|
||||
// increasing index order, and the comparison stops at the first index
|
||||
// for which eq returns false.
|
||||
func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
for i, v1 := range s1 {
|
||||
v2 := s2[i]
|
||||
if !eq(v1, v2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair
|
||||
// of elements. The elements are compared sequentially, starting at index 0,
|
||||
// until one element is not equal to the other.
|
||||
// The result of comparing the first non-matching elements is returned.
|
||||
// If both slices are equal until one of them ends, the shorter slice is
|
||||
// considered less than the longer one.
|
||||
// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
|
||||
func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) int {
|
||||
for i, v1 := range s1 {
|
||||
if i >= len(s2) {
|
||||
return +1
|
||||
}
|
||||
v2 := s2[i]
|
||||
if c := cmp.Compare(v1, v2); c != 0 {
|
||||
return c
|
||||
}
|
||||
}
|
||||
if len(s1) < len(s2) {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// CompareFunc is like [Compare] but uses a custom comparison function on each
|
||||
// pair of elements.
|
||||
// The result is the first non-zero result of cmp; if cmp always
|
||||
// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
|
||||
// and +1 if len(s1) > len(s2).
|
||||
func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int {
|
||||
for i, v1 := range s1 {
|
||||
if i >= len(s2) {
|
||||
return +1
|
||||
}
|
||||
v2 := s2[i]
|
||||
if c := cmp(v1, v2); c != 0 {
|
||||
return c
|
||||
}
|
||||
}
|
||||
if len(s1) < len(s2) {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Index returns the index of the first occurrence of v in s,
|
||||
// or -1 if not present.
|
||||
func Index[S ~[]E, E comparable](s S, v E) int {
|
||||
for i := range s {
|
||||
if v == s[i] {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// IndexFunc returns the first index i satisfying f(s[i]),
|
||||
// or -1 if none do.
|
||||
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
|
||||
for i := range s {
|
||||
if f(s[i]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Contains reports whether v is present in s.
|
||||
func Contains[S ~[]E, E comparable](s S, v E) bool {
|
||||
return Index(s, v) >= 0
|
||||
}
|
||||
|
||||
// ContainsFunc reports whether at least one
|
||||
// element e of s satisfies f(e).
|
||||
func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
|
||||
return IndexFunc(s, f) >= 0
|
||||
}
|
||||
|
||||
// Insert inserts the values v... into s at index i,
|
||||
// returning the modified slice.
|
||||
// The elements at s[i:] are shifted up to make room.
|
||||
// In the returned slice r, r[i] == v[0],
|
||||
// and r[i+len(v)] == value originally at r[i].
|
||||
// Insert panics if i is out of range.
|
||||
// This function is O(len(s) + len(v)).
|
||||
func Insert[S ~[]E, E any](s S, i int, v ...E) S {
|
||||
_ = s[i:] // bounds check
|
||||
|
||||
m := len(v)
|
||||
if m == 0 {
|
||||
return s
|
||||
}
|
||||
n := len(s)
|
||||
if i == n {
|
||||
return append(s, v...)
|
||||
}
|
||||
if n+m > cap(s) {
|
||||
// Use append rather than make so that we bump the size of
|
||||
// the slice up to the next storage class.
|
||||
// This is what Grow does but we don't call Grow because
|
||||
// that might copy the values twice.
|
||||
s2 := append(s[:i], make(S, n+m-i)...)
|
||||
copy(s2[i:], v)
|
||||
copy(s2[i+m:], s[i:])
|
||||
return s2
|
||||
}
|
||||
s = s[:n+m]
|
||||
|
||||
// before:
|
||||
// s: aaaaaaaabbbbccccccccdddd
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
// after:
|
||||
// s: aaaaaaaavvvvbbbbcccccccc
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
//
|
||||
// a are the values that don't move in s.
|
||||
// v are the values copied in from v.
|
||||
// b and c are the values from s that are shifted up in index.
|
||||
// d are the values that get overwritten, never to be seen again.
|
||||
|
||||
if !overlaps(v, s[i+m:]) {
|
||||
// Easy case - v does not overlap either the c or d regions.
|
||||
// (It might be in some of a or b, or elsewhere entirely.)
|
||||
// The data we copy up doesn't write to v at all, so just do it.
|
||||
|
||||
copy(s[i+m:], s[i:])
|
||||
|
||||
// Now we have
|
||||
// s: aaaaaaaabbbbbbbbcccccccc
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
// Note the b values are duplicated.
|
||||
|
||||
copy(s[i:], v)
|
||||
|
||||
// Now we have
|
||||
// s: aaaaaaaavvvvbbbbcccccccc
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
// That's the result we want.
|
||||
return s
|
||||
}
|
||||
|
||||
// The hard case - v overlaps c or d. We can't just shift up
|
||||
// the data because we'd move or clobber the values we're trying
|
||||
// to insert.
|
||||
// So instead, write v on top of d, then rotate.
|
||||
copy(s[n:], v)
|
||||
|
||||
// Now we have
|
||||
// s: aaaaaaaabbbbccccccccvvvv
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
|
||||
rotateRight(s[i:], m)
|
||||
|
||||
// Now we have
|
||||
// s: aaaaaaaavvvvbbbbcccccccc
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
// That's the result we want.
|
||||
return s
|
||||
}
|
||||
|
||||
// Delete removes the elements s[i:j] from s, returning the modified slice.
|
||||
// Delete panics if j > len(s) or s[i:j] is not a valid slice of s.
|
||||
// Delete is O(len(s)-i), so if many items must be deleted, it is better to
|
||||
// make a single call deleting them all together than to delete one at a time.
|
||||
// Delete zeroes the elements s[len(s)-(j-i):len(s)].
|
||||
func Delete[S ~[]E, E any](s S, i, j int) S {
|
||||
_ = s[i:j:len(s)] // bounds check
|
||||
|
||||
if i == j {
|
||||
return s
|
||||
}
|
||||
|
||||
oldlen := len(s)
|
||||
s = append(s[:i], s[j:]...)
|
||||
clear(s[len(s):oldlen]) // zero/nil out the obsolete elements, for GC
|
||||
return s
|
||||
}
|
||||
|
||||
// DeleteFunc removes any elements from s for which del returns true,
|
||||
// returning the modified slice.
|
||||
// DeleteFunc zeroes the elements between the new length and the original length.
|
||||
func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
|
||||
i := IndexFunc(s, del)
|
||||
if i == -1 {
|
||||
return s
|
||||
}
|
||||
// Don't start copying elements until we find one to delete.
|
||||
for j := i + 1; j < len(s); j++ {
|
||||
if v := s[j]; !del(v) {
|
||||
s[i] = v
|
||||
i++
|
||||
}
|
||||
}
|
||||
clear(s[i:]) // zero/nil out the obsolete elements, for GC
|
||||
return s[:i]
|
||||
}
|
||||
|
||||
// Replace replaces the elements s[i:j] by the given v, and returns the
|
||||
// modified slice.
|
||||
// Replace panics if j > len(s) or s[i:j] is not a valid slice of s.
|
||||
// When len(v) < (j-i), Replace zeroes the elements between the new length and the original length.
|
||||
func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
|
||||
_ = s[i:j] // bounds check
|
||||
|
||||
if i == j {
|
||||
return Insert(s, i, v...)
|
||||
}
|
||||
if j == len(s) {
|
||||
return append(s[:i], v...)
|
||||
}
|
||||
|
||||
tot := len(s[:i]) + len(v) + len(s[j:])
|
||||
if tot > cap(s) {
|
||||
// Too big to fit, allocate and copy over.
|
||||
s2 := append(s[:i], make(S, tot-i)...) // See Insert
|
||||
copy(s2[i:], v)
|
||||
copy(s2[i+len(v):], s[j:])
|
||||
return s2
|
||||
}
|
||||
|
||||
r := s[:tot]
|
||||
|
||||
if i+len(v) <= j {
|
||||
// Easy, as v fits in the deleted portion.
|
||||
copy(r[i:], v)
|
||||
copy(r[i+len(v):], s[j:])
|
||||
clear(s[tot:]) // zero/nil out the obsolete elements, for GC
|
||||
return r
|
||||
}
|
||||
|
||||
// We are expanding (v is bigger than j-i).
|
||||
// The situation is something like this:
|
||||
// (example has i=4,j=8,len(s)=16,len(v)=6)
|
||||
// s: aaaaxxxxbbbbbbbbyy
|
||||
// ^ ^ ^ ^
|
||||
// i j len(s) tot
|
||||
// a: prefix of s
|
||||
// x: deleted range
|
||||
// b: more of s
|
||||
// y: area to expand into
|
||||
|
||||
if !overlaps(r[i+len(v):], v) {
|
||||
// Easy, as v is not clobbered by the first copy.
|
||||
copy(r[i+len(v):], s[j:])
|
||||
copy(r[i:], v)
|
||||
return r
|
||||
}
|
||||
|
||||
// This is a situation where we don't have a single place to which
|
||||
// we can copy v. Parts of it need to go to two different places.
|
||||
// We want to copy the prefix of v into y and the suffix into x, then
|
||||
// rotate |y| spots to the right.
|
||||
//
|
||||
// v[2:] v[:2]
|
||||
// | |
|
||||
// s: aaaavvvvbbbbbbbbvv
|
||||
// ^ ^ ^ ^
|
||||
// i j len(s) tot
|
||||
//
|
||||
// If either of those two destinations don't alias v, then we're good.
|
||||
y := len(v) - (j - i) // length of y portion
|
||||
|
||||
if !overlaps(r[i:j], v) {
|
||||
copy(r[i:j], v[y:])
|
||||
copy(r[len(s):], v[:y])
|
||||
rotateRight(r[i:], y)
|
||||
return r
|
||||
}
|
||||
if !overlaps(r[len(s):], v) {
|
||||
copy(r[len(s):], v[:y])
|
||||
copy(r[i:j], v[y:])
|
||||
rotateRight(r[i:], y)
|
||||
return r
|
||||
}
|
||||
|
||||
// Now we know that v overlaps both x and y.
|
||||
// That means that the entirety of b is *inside* v.
|
||||
// So we don't need to preserve b at all; instead we
|
||||
// can copy v first, then copy the b part of v out of
|
||||
// v to the right destination.
|
||||
k := startIdx(v, s[j:])
|
||||
copy(r[i:], v)
|
||||
copy(r[i+len(v):], r[i+k:])
|
||||
return r
|
||||
}
|
||||
|
||||
// Clone returns a copy of the slice.
|
||||
// The elements are copied using assignment, so this is a shallow clone.
|
||||
func Clone[S ~[]E, E any](s S) S {
|
||||
// The s[:0:0] preserves nil in case it matters.
|
||||
return append(s[:0:0], s...)
|
||||
}
|
||||
|
||||
// Compact replaces consecutive runs of equal elements with a single copy.
|
||||
// This is like the uniq command found on Unix.
|
||||
// Compact modifies the contents of the slice s and returns the modified slice,
|
||||
// which may have a smaller length.
|
||||
// Compact zeroes the elements between the new length and the original length.
|
||||
func Compact[S ~[]E, E comparable](s S) S {
|
||||
if len(s) < 2 {
|
||||
return s
|
||||
}
|
||||
i := 1
|
||||
for k := 1; k < len(s); k++ {
|
||||
if s[k] != s[k-1] {
|
||||
if i != k {
|
||||
s[i] = s[k]
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
clear(s[i:]) // zero/nil out the obsolete elements, for GC
|
||||
return s[:i]
|
||||
}
|
||||
|
||||
// CompactFunc is like [Compact] but uses an equality function to compare elements.
|
||||
// For runs of elements that compare equal, CompactFunc keeps the first one.
|
||||
// CompactFunc zeroes the elements between the new length and the original length.
|
||||
func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
|
||||
if len(s) < 2 {
|
||||
return s
|
||||
}
|
||||
i := 1
|
||||
for k := 1; k < len(s); k++ {
|
||||
if !eq(s[k], s[k-1]) {
|
||||
if i != k {
|
||||
s[i] = s[k]
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
clear(s[i:]) // zero/nil out the obsolete elements, for GC
|
||||
return s[:i]
|
||||
}
|
||||
|
||||
// Grow increases the slice's capacity, if necessary, to guarantee space for
|
||||
// another n elements. After Grow(n), at least n elements can be appended
|
||||
// to the slice without another allocation. If n is negative or too large to
|
||||
// allocate the memory, Grow panics.
|
||||
func Grow[S ~[]E, E any](s S, n int) S {
|
||||
if n < 0 {
|
||||
panic("cannot be negative")
|
||||
}
|
||||
if n -= cap(s) - len(s); n > 0 {
|
||||
s = append(s[:cap(s)], make([]E, n)...)[:len(s)]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
|
||||
func Clip[S ~[]E, E any](s S) S {
|
||||
return s[:len(s):len(s)]
|
||||
}
|
||||
|
||||
// Rotation algorithm explanation:
|
||||
//
|
||||
// rotate left by 2
|
||||
// start with
|
||||
// 0123456789
|
||||
// split up like this
|
||||
// 01 234567 89
|
||||
// swap first 2 and last 2
|
||||
// 89 234567 01
|
||||
// join first parts
|
||||
// 89234567 01
|
||||
// recursively rotate first left part by 2
|
||||
// 23456789 01
|
||||
// join at the end
|
||||
// 2345678901
|
||||
//
|
||||
// rotate left by 8
|
||||
// start with
|
||||
// 0123456789
|
||||
// split up like this
|
||||
// 01 234567 89
|
||||
// swap first 2 and last 2
|
||||
// 89 234567 01
|
||||
// join last parts
|
||||
// 89 23456701
|
||||
// recursively rotate second part left by 6
|
||||
// 89 01234567
|
||||
// join at the end
|
||||
// 8901234567
|
||||
|
||||
// TODO: There are other rotate algorithms.
|
||||
// This algorithm has the desirable property that it moves each element exactly twice.
|
||||
// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes.
|
||||
// The follow-cycles algorithm can be 1-write but it is not very cache friendly.
|
||||
|
||||
// rotateLeft rotates b left by n spaces.
|
||||
// s_final[i] = s_orig[i+r], wrapping around.
|
||||
func rotateLeft[E any](s []E, r int) {
|
||||
for r != 0 && r != len(s) {
|
||||
if r*2 <= len(s) {
|
||||
swap(s[:r], s[len(s)-r:])
|
||||
s = s[:len(s)-r]
|
||||
} else {
|
||||
swap(s[:len(s)-r], s[r:])
|
||||
s, r = s[len(s)-r:], r*2-len(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
func rotateRight[E any](s []E, r int) {
|
||||
rotateLeft(s, len(s)-r)
|
||||
}
|
||||
|
||||
// swap swaps the contents of x and y. x and y must be equal length and disjoint.
|
||||
func swap[E any](x, y []E) {
|
||||
for i := 0; i < len(x); i++ {
|
||||
x[i], y[i] = y[i], x[i]
|
||||
}
|
||||
}
|
||||
|
||||
// overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap.
|
||||
func overlaps[E any](a, b []E) bool {
|
||||
return false
|
||||
/* TODO(marc): restore the following
|
||||
if len(a) == 0 || len(b) == 0 {
|
||||
return false
|
||||
}
|
||||
elemSize := unsafe.Sizeof(a[0])
|
||||
if elemSize == 0 {
|
||||
return false
|
||||
}
|
||||
// TODO: use a runtime/unsafe facility once one becomes available. See issue 12445.
|
||||
// Also see crypto/internal/alias/alias.go:AnyOverlap
|
||||
return uintptr(unsafe.Pointer(&a[0])) <= uintptr(unsafe.Pointer(&b[len(b)-1]))+(elemSize-1) &&
|
||||
uintptr(unsafe.Pointer(&b[0])) <= uintptr(unsafe.Pointer(&a[len(a)-1]))+(elemSize-1)
|
||||
*/
|
||||
}
|
||||
|
||||
// startIdx returns the index in haystack where the needle starts.
|
||||
// prerequisite: the needle must be aliased entirely inside the haystack.
|
||||
func startIdx[E any](haystack, needle []E) int {
|
||||
p := &needle[0]
|
||||
for i := range haystack {
|
||||
if p == &haystack[i] {
|
||||
return i
|
||||
}
|
||||
}
|
||||
// TODO: what if the overlap is by a non-integral number of Es?
|
||||
panic("needle not found")
|
||||
}
|
||||
|
||||
// Reverse reverses the elements of the slice in place.
|
||||
func Reverse[S ~[]E, E any](s S) {
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Concat returns a new slice concatenating the passed in slices.
|
||||
func Concat[S ~[]E, E any](slices ...S) S {
|
||||
size := 0
|
||||
for _, s := range slices {
|
||||
size += len(s)
|
||||
if size < 0 {
|
||||
panic("len out of range")
|
||||
}
|
||||
}
|
||||
newslice := Grow[S](nil, size)
|
||||
for _, s := range slices {
|
||||
newslice = append(newslice, s...)
|
||||
}
|
||||
return newslice
|
||||
}
|
||||
194
stdlib/generic/go1_22_slices_sort.go.txt
Normal file
194
stdlib/generic/go1_22_slices_sort.go.txt
Normal file
@@ -0,0 +1,194 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -generic
|
||||
|
||||
package slices
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// Sort sorts a slice of any ordered type in ascending order.
|
||||
// When sorting floating-point numbers, NaNs are ordered before other values.
|
||||
func Sort[S ~[]E, E cmp.Ordered](x S) {
|
||||
n := len(x)
|
||||
pdqsortOrdered(x, 0, n, bits.Len(uint(n)))
|
||||
}
|
||||
|
||||
// SortFunc sorts the slice x in ascending order as determined by the cmp
|
||||
// function. This sort is not guaranteed to be stable.
|
||||
// cmp(a, b) should return a negative number when a < b, a positive number when
|
||||
// a > b and zero when a == b.
|
||||
//
|
||||
// SortFunc requires that cmp is a strict weak ordering.
|
||||
// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
|
||||
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
|
||||
n := len(x)
|
||||
pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)
|
||||
}
|
||||
|
||||
// SortStableFunc sorts the slice x while keeping the original order of equal
|
||||
// elements, using cmp to compare elements in the same way as [SortFunc].
|
||||
func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
|
||||
stableCmpFunc(x, len(x), cmp)
|
||||
}
|
||||
|
||||
// IsSorted reports whether x is sorted in ascending order.
|
||||
func IsSorted[S ~[]E, E cmp.Ordered](x S) bool {
|
||||
for i := len(x) - 1; i > 0; i-- {
|
||||
if cmp.Less(x[i], x[i-1]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
|
||||
// comparison function as defined by [SortFunc].
|
||||
func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
|
||||
for i := len(x) - 1; i > 0; i-- {
|
||||
if cmp(x[i], x[i-1]) < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Min returns the minimal value in x. It panics if x is empty.
|
||||
// For floating-point numbers, Min propagates NaNs (any NaN value in x
|
||||
// forces the output to be NaN).
|
||||
func Min[S ~[]E, E cmp.Ordered](x S) E {
|
||||
if len(x) < 1 {
|
||||
panic("slices.Min: empty list")
|
||||
}
|
||||
m := x[0]
|
||||
for i := 1; i < len(x); i++ {
|
||||
m = min(m, x[i])
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// MinFunc returns the minimal value in x, using cmp to compare elements.
|
||||
// It panics if x is empty. If there is more than one minimal element
|
||||
// according to the cmp function, MinFunc returns the first one.
|
||||
func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
|
||||
if len(x) < 1 {
|
||||
panic("slices.MinFunc: empty list")
|
||||
}
|
||||
m := x[0]
|
||||
for i := 1; i < len(x); i++ {
|
||||
if cmp(x[i], m) < 0 {
|
||||
m = x[i]
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Max returns the maximal value in x. It panics if x is empty.
|
||||
// For floating-point E, Max propagates NaNs (any NaN value in x
|
||||
// forces the output to be NaN).
|
||||
func Max[S ~[]E, E cmp.Ordered](x S) E {
|
||||
if len(x) < 1 {
|
||||
panic("slices.Max: empty list")
|
||||
}
|
||||
m := x[0]
|
||||
for i := 1; i < len(x); i++ {
|
||||
m = max(m, x[i])
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// MaxFunc returns the maximal value in x, using cmp to compare elements.
|
||||
// It panics if x is empty. If there is more than one maximal element
|
||||
// according to the cmp function, MaxFunc returns the first one.
|
||||
func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
|
||||
if len(x) < 1 {
|
||||
panic("slices.MaxFunc: empty list")
|
||||
}
|
||||
m := x[0]
|
||||
for i := 1; i < len(x); i++ {
|
||||
if cmp(x[i], m) > 0 {
|
||||
m = x[i]
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// BinarySearch searches for target in a sorted slice and returns the position
|
||||
// where target is found, or the position where target would appear in the
|
||||
// sort order; it also returns a bool saying whether the target is really found
|
||||
// in the slice. The slice must be sorted in increasing order.
|
||||
func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) {
|
||||
// Inlining is faster than calling BinarySearchFunc with a lambda.
|
||||
n := len(x)
|
||||
// Define x[-1] < target and x[n] >= target.
|
||||
// Invariant: x[i-1] < target, x[j] >= target.
|
||||
i, j := 0, n
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1) // avoid overflow when computing h
|
||||
// i ≤ h < j
|
||||
if cmp.Less(x[h], target) {
|
||||
i = h + 1 // preserves x[i-1] < target
|
||||
} else {
|
||||
j = h // preserves x[j] >= target
|
||||
}
|
||||
}
|
||||
// i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i.
|
||||
return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target)))
|
||||
}
|
||||
|
||||
// BinarySearchFunc works like [BinarySearch], but uses a custom comparison
|
||||
// function. The slice must be sorted in increasing order, where "increasing"
|
||||
// is defined by cmp. cmp should return 0 if the slice element matches
|
||||
// the target, a negative number if the slice element precedes the target,
|
||||
// or a positive number if the slice element follows the target.
|
||||
// cmp must implement the same ordering as the slice, such that if
|
||||
// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
|
||||
func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
|
||||
n := len(x)
|
||||
// Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 .
|
||||
// Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0.
|
||||
i, j := 0, n
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1) // avoid overflow when computing h
|
||||
// i ≤ h < j
|
||||
if cmp(x[h], target) < 0 {
|
||||
i = h + 1 // preserves cmp(x[i - 1], target) < 0
|
||||
} else {
|
||||
j = h // preserves cmp(x[j], target) >= 0
|
||||
}
|
||||
}
|
||||
// i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i.
|
||||
return i, i < n && cmp(x[i], target) == 0
|
||||
}
|
||||
|
||||
type sortedHint int // hint for pdqsort when choosing the pivot
|
||||
|
||||
const (
|
||||
unknownHint sortedHint = iota
|
||||
increasingHint
|
||||
decreasingHint
|
||||
)
|
||||
|
||||
// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
|
||||
type xorshift uint64
|
||||
|
||||
func (r *xorshift) Next() uint64 {
|
||||
*r ^= *r << 13
|
||||
*r ^= *r >> 17
|
||||
*r ^= *r << 5
|
||||
return uint64(*r)
|
||||
}
|
||||
|
||||
func nextPowerOfTwo(length int) uint {
|
||||
return 1 << bits.Len(uint(length))
|
||||
}
|
||||
|
||||
// isNaN reports whether x is a NaN without requiring the math package.
|
||||
// This will always return false if T is not floating-point.
|
||||
func isNaN[T cmp.Ordered](x T) bool {
|
||||
return x != x
|
||||
}
|
||||
479
stdlib/generic/go1_22_slices_zsortanyfunc.go.txt
Normal file
479
stdlib/generic/go1_22_slices_zsortanyfunc.go.txt
Normal file
@@ -0,0 +1,479 @@
|
||||
// Code generated by gen_sort_variants.go; DO NOT EDIT.
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package slices
|
||||
|
||||
// insertionSortCmpFunc sorts data[a:b] using insertion sort.
|
||||
func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
||||
for i := a + 1; i < b; i++ {
|
||||
for j := i; j > a && (cmp(data[j], data[j-1]) < 0); j-- {
|
||||
data[j], data[j-1] = data[j-1], data[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// siftDownCmpFunc implements the heap property on data[lo:hi].
|
||||
// first is an offset into the array where the root of the heap lies.
|
||||
func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) {
|
||||
root := lo
|
||||
for {
|
||||
child := 2*root + 1
|
||||
if child >= hi {
|
||||
break
|
||||
}
|
||||
if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) {
|
||||
child++
|
||||
}
|
||||
if !(cmp(data[first+root], data[first+child]) < 0) {
|
||||
return
|
||||
}
|
||||
data[first+root], data[first+child] = data[first+child], data[first+root]
|
||||
root = child
|
||||
}
|
||||
}
|
||||
|
||||
func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
||||
first := a
|
||||
lo := 0
|
||||
hi := b - a
|
||||
|
||||
// Build heap with greatest element at top.
|
||||
for i := (hi - 1) / 2; i >= 0; i-- {
|
||||
siftDownCmpFunc(data, i, hi, first, cmp)
|
||||
}
|
||||
|
||||
// Pop elements, largest first, into end of data.
|
||||
for i := hi - 1; i >= 0; i-- {
|
||||
data[first], data[first+i] = data[first+i], data[first]
|
||||
siftDownCmpFunc(data, lo, i, first, cmp)
|
||||
}
|
||||
}
|
||||
|
||||
// pdqsortCmpFunc sorts data[a:b].
|
||||
// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
|
||||
// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
|
||||
// C++ implementation: https://github.com/orlp/pdqsort
|
||||
// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
|
||||
// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
|
||||
func pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) {
|
||||
const maxInsertion = 12
|
||||
|
||||
var (
|
||||
wasBalanced = true // whether the last partitioning was reasonably balanced
|
||||
wasPartitioned = true // whether the slice was already partitioned
|
||||
)
|
||||
|
||||
for {
|
||||
length := b - a
|
||||
|
||||
if length <= maxInsertion {
|
||||
insertionSortCmpFunc(data, a, b, cmp)
|
||||
return
|
||||
}
|
||||
|
||||
// Fall back to heapsort if too many bad choices were made.
|
||||
if limit == 0 {
|
||||
heapSortCmpFunc(data, a, b, cmp)
|
||||
return
|
||||
}
|
||||
|
||||
// If the last partitioning was imbalanced, we need to breaking patterns.
|
||||
if !wasBalanced {
|
||||
breakPatternsCmpFunc(data, a, b, cmp)
|
||||
limit--
|
||||
}
|
||||
|
||||
pivot, hint := choosePivotCmpFunc(data, a, b, cmp)
|
||||
if hint == decreasingHint {
|
||||
reverseRangeCmpFunc(data, a, b, cmp)
|
||||
// The chosen pivot was pivot-a elements after the start of the array.
|
||||
// After reversing it is pivot-a elements before the end of the array.
|
||||
// The idea came from Rust's implementation.
|
||||
pivot = (b - 1) - (pivot - a)
|
||||
hint = increasingHint
|
||||
}
|
||||
|
||||
// The slice is likely already sorted.
|
||||
if wasBalanced && wasPartitioned && hint == increasingHint {
|
||||
if partialInsertionSortCmpFunc(data, a, b, cmp) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Probably the slice contains many duplicate elements, partition the slice into
|
||||
// elements equal to and elements greater than the pivot.
|
||||
if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) {
|
||||
mid := partitionEqualCmpFunc(data, a, b, pivot, cmp)
|
||||
a = mid
|
||||
continue
|
||||
}
|
||||
|
||||
mid, alreadyPartitioned := partitionCmpFunc(data, a, b, pivot, cmp)
|
||||
wasPartitioned = alreadyPartitioned
|
||||
|
||||
leftLen, rightLen := mid-a, b-mid
|
||||
balanceThreshold := length / 8
|
||||
if leftLen < rightLen {
|
||||
wasBalanced = leftLen >= balanceThreshold
|
||||
pdqsortCmpFunc(data, a, mid, limit, cmp)
|
||||
a = mid + 1
|
||||
} else {
|
||||
wasBalanced = rightLen >= balanceThreshold
|
||||
pdqsortCmpFunc(data, mid+1, b, limit, cmp)
|
||||
b = mid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// partitionCmpFunc does one quicksort partition.
|
||||
// Let p = data[pivot]
|
||||
// Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
|
||||
// On return, data[newpivot] = p
|
||||
func partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) {
|
||||
data[a], data[pivot] = data[pivot], data[a]
|
||||
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
|
||||
|
||||
for i <= j && (cmp(data[i], data[a]) < 0) {
|
||||
i++
|
||||
}
|
||||
for i <= j && !(cmp(data[j], data[a]) < 0) {
|
||||
j--
|
||||
}
|
||||
if i > j {
|
||||
data[j], data[a] = data[a], data[j]
|
||||
return j, true
|
||||
}
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
|
||||
for {
|
||||
for i <= j && (cmp(data[i], data[a]) < 0) {
|
||||
i++
|
||||
}
|
||||
for i <= j && !(cmp(data[j], data[a]) < 0) {
|
||||
j--
|
||||
}
|
||||
if i > j {
|
||||
break
|
||||
}
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
data[j], data[a] = data[a], data[j]
|
||||
return j, false
|
||||
}
|
||||
|
||||
// partitionEqualCmpFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
|
||||
// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
|
||||
func partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) {
|
||||
data[a], data[pivot] = data[pivot], data[a]
|
||||
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
|
||||
|
||||
for {
|
||||
for i <= j && !(cmp(data[a], data[i]) < 0) {
|
||||
i++
|
||||
}
|
||||
for i <= j && (cmp(data[a], data[j]) < 0) {
|
||||
j--
|
||||
}
|
||||
if i > j {
|
||||
break
|
||||
}
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end.
|
||||
func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool {
|
||||
const (
|
||||
maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
|
||||
shortestShifting = 50 // don't shift any elements on short arrays
|
||||
)
|
||||
i := a + 1
|
||||
for j := 0; j < maxSteps; j++ {
|
||||
for i < b && !(cmp(data[i], data[i-1]) < 0) {
|
||||
i++
|
||||
}
|
||||
|
||||
if i == b {
|
||||
return true
|
||||
}
|
||||
|
||||
if b-a < shortestShifting {
|
||||
return false
|
||||
}
|
||||
|
||||
data[i], data[i-1] = data[i-1], data[i]
|
||||
|
||||
// Shift the smaller one to the left.
|
||||
if i-a >= 2 {
|
||||
for j := i - 1; j >= 1; j-- {
|
||||
if !(cmp(data[j], data[j-1]) < 0) {
|
||||
break
|
||||
}
|
||||
data[j], data[j-1] = data[j-1], data[j]
|
||||
}
|
||||
}
|
||||
// Shift the greater one to the right.
|
||||
if b-i >= 2 {
|
||||
for j := i + 1; j < b; j++ {
|
||||
if !(cmp(data[j], data[j-1]) < 0) {
|
||||
break
|
||||
}
|
||||
data[j], data[j-1] = data[j-1], data[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns
|
||||
// that might cause imbalanced partitions in quicksort.
|
||||
func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
||||
length := b - a
|
||||
if length >= 8 {
|
||||
random := xorshift(length)
|
||||
modulus := nextPowerOfTwo(length)
|
||||
|
||||
for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
|
||||
other := int(uint(random.Next()) & (modulus - 1))
|
||||
if other >= length {
|
||||
other -= length
|
||||
}
|
||||
data[idx], data[a+other] = data[a+other], data[idx]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// choosePivotCmpFunc chooses a pivot in data[a:b].
|
||||
//
|
||||
// [0,8): chooses a static pivot.
|
||||
// [8,shortestNinther): uses the simple median-of-three method.
|
||||
// [shortestNinther,∞): uses the Tukey ninther method.
|
||||
func choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) {
|
||||
const (
|
||||
shortestNinther = 50
|
||||
maxSwaps = 4 * 3
|
||||
)
|
||||
|
||||
l := b - a
|
||||
|
||||
var (
|
||||
swaps int
|
||||
i = a + l/4*1
|
||||
j = a + l/4*2
|
||||
k = a + l/4*3
|
||||
)
|
||||
|
||||
if l >= 8 {
|
||||
if l >= shortestNinther {
|
||||
// Tukey ninther method, the idea came from Rust's implementation.
|
||||
i = medianAdjacentCmpFunc(data, i, &swaps, cmp)
|
||||
j = medianAdjacentCmpFunc(data, j, &swaps, cmp)
|
||||
k = medianAdjacentCmpFunc(data, k, &swaps, cmp)
|
||||
}
|
||||
// Find the median among i, j, k and stores it into j.
|
||||
j = medianCmpFunc(data, i, j, k, &swaps, cmp)
|
||||
}
|
||||
|
||||
switch swaps {
|
||||
case 0:
|
||||
return j, increasingHint
|
||||
case maxSwaps:
|
||||
return j, decreasingHint
|
||||
default:
|
||||
return j, unknownHint
|
||||
}
|
||||
}
|
||||
|
||||
// order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
|
||||
func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) {
|
||||
if cmp(data[b], data[a]) < 0 {
|
||||
*swaps++
|
||||
return b, a
|
||||
}
|
||||
return a, b
|
||||
}
|
||||
|
||||
// medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
|
||||
func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int {
|
||||
a, b = order2CmpFunc(data, a, b, swaps, cmp)
|
||||
b, c = order2CmpFunc(data, b, c, swaps, cmp)
|
||||
a, b = order2CmpFunc(data, a, b, swaps, cmp)
|
||||
return b
|
||||
}
|
||||
|
||||
// medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
|
||||
func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int {
|
||||
return medianCmpFunc(data, a-1, a, a+1, swaps, cmp)
|
||||
}
|
||||
|
||||
func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
||||
i := a
|
||||
j := b - 1
|
||||
for i < j {
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
}
|
||||
|
||||
func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) {
|
||||
for i := 0; i < n; i++ {
|
||||
data[a+i], data[b+i] = data[b+i], data[a+i]
|
||||
}
|
||||
}
|
||||
|
||||
func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) {
|
||||
blockSize := 20 // must be > 0
|
||||
a, b := 0, blockSize
|
||||
for b <= n {
|
||||
insertionSortCmpFunc(data, a, b, cmp)
|
||||
a = b
|
||||
b += blockSize
|
||||
}
|
||||
insertionSortCmpFunc(data, a, n, cmp)
|
||||
|
||||
for blockSize < n {
|
||||
a, b = 0, 2*blockSize
|
||||
for b <= n {
|
||||
symMergeCmpFunc(data, a, a+blockSize, b, cmp)
|
||||
a = b
|
||||
b += 2 * blockSize
|
||||
}
|
||||
if m := a + blockSize; m < n {
|
||||
symMergeCmpFunc(data, a, m, n, cmp)
|
||||
}
|
||||
blockSize *= 2
|
||||
}
|
||||
}
|
||||
|
||||
// symMergeCmpFunc merges the two sorted subsequences data[a:m] and data[m:b] using
|
||||
// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
|
||||
// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
|
||||
// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
|
||||
// Computer Science, pages 714-723. Springer, 2004.
|
||||
//
|
||||
// Let M = m-a and N = b-n. Wolog M < N.
|
||||
// The recursion depth is bound by ceil(log(N+M)).
|
||||
// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
|
||||
// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
|
||||
//
|
||||
// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
|
||||
// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
|
||||
// in the paper carries through for Swap operations, especially as the block
|
||||
// swapping rotate uses only O(M+N) Swaps.
|
||||
//
|
||||
// symMerge assumes non-degenerate arguments: a < m && m < b.
|
||||
// Having the caller check this condition eliminates many leaf recursion calls,
|
||||
// which improves performance.
|
||||
func symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
|
||||
// Avoid unnecessary recursions of symMerge
|
||||
// by direct insertion of data[a] into data[m:b]
|
||||
// if data[a:m] only contains one element.
|
||||
if m-a == 1 {
|
||||
// Use binary search to find the lowest index i
|
||||
// such that data[i] >= data[a] for m <= i < b.
|
||||
// Exit the search loop with i == b in case no such index exists.
|
||||
i := m
|
||||
j := b
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1)
|
||||
if cmp(data[h], data[a]) < 0 {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
// Swap values until data[a] reaches the position before i.
|
||||
for k := a; k < i-1; k++ {
|
||||
data[k], data[k+1] = data[k+1], data[k]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Avoid unnecessary recursions of symMerge
|
||||
// by direct insertion of data[m] into data[a:m]
|
||||
// if data[m:b] only contains one element.
|
||||
if b-m == 1 {
|
||||
// Use binary search to find the lowest index i
|
||||
// such that data[i] > data[m] for a <= i < m.
|
||||
// Exit the search loop with i == m in case no such index exists.
|
||||
i := a
|
||||
j := m
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1)
|
||||
if !(cmp(data[m], data[h]) < 0) {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
// Swap values until data[m] reaches the position i.
|
||||
for k := m; k > i; k-- {
|
||||
data[k], data[k-1] = data[k-1], data[k]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
mid := int(uint(a+b) >> 1)
|
||||
n := mid + m
|
||||
var start, r int
|
||||
if m > mid {
|
||||
start = n - b
|
||||
r = mid
|
||||
} else {
|
||||
start = a
|
||||
r = m
|
||||
}
|
||||
p := n - 1
|
||||
|
||||
for start < r {
|
||||
c := int(uint(start+r) >> 1)
|
||||
if !(cmp(data[p-c], data[c]) < 0) {
|
||||
start = c + 1
|
||||
} else {
|
||||
r = c
|
||||
}
|
||||
}
|
||||
|
||||
end := n - start
|
||||
if start < m && m < end {
|
||||
rotateCmpFunc(data, start, m, end, cmp)
|
||||
}
|
||||
if a < start && start < mid {
|
||||
symMergeCmpFunc(data, a, start, mid, cmp)
|
||||
}
|
||||
if mid < end && end < b {
|
||||
symMergeCmpFunc(data, mid, end, b, cmp)
|
||||
}
|
||||
}
|
||||
|
||||
// rotateCmpFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
|
||||
// Data of the form 'x u v y' is changed to 'x v u y'.
|
||||
// rotate performs at most b-a many calls to data.Swap,
|
||||
// and it assumes non-degenerate arguments: a < m && m < b.
|
||||
func rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
|
||||
i := m - a
|
||||
j := b - m
|
||||
|
||||
for i != j {
|
||||
if i > j {
|
||||
swapRangeCmpFunc(data, m-i, m, j, cmp)
|
||||
i -= j
|
||||
} else {
|
||||
swapRangeCmpFunc(data, m-i, m+j-i, i, cmp)
|
||||
j -= i
|
||||
}
|
||||
}
|
||||
// i == j
|
||||
swapRangeCmpFunc(data, m-i, m, i, cmp)
|
||||
}
|
||||
200
stdlib/generic/go1_22_sync_atomic_type.go.txt
Normal file
200
stdlib/generic/go1_22_sync_atomic_type.go.txt
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package atomic
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// A Bool is an atomic boolean value.
|
||||
// The zero value is false.
|
||||
type Bool struct {
|
||||
_ noCopy
|
||||
v uint32
|
||||
}
|
||||
|
||||
// Load atomically loads and returns the value stored in x.
|
||||
func (x *Bool) Load() bool { return LoadUint32(&x.v) != 0 }
|
||||
|
||||
// Store atomically stores val into x.
|
||||
func (x *Bool) Store(val bool) { StoreUint32(&x.v, b32(val)) }
|
||||
|
||||
// Swap atomically stores new into x and returns the previous value.
|
||||
func (x *Bool) Swap(new bool) (old bool) { return SwapUint32(&x.v, b32(new)) != 0 }
|
||||
|
||||
// CompareAndSwap executes the compare-and-swap operation for the boolean value x.
|
||||
func (x *Bool) CompareAndSwap(old, new bool) (swapped bool) {
|
||||
return CompareAndSwapUint32(&x.v, b32(old), b32(new))
|
||||
}
|
||||
|
||||
// b32 returns a uint32 0 or 1 representing b.
|
||||
func b32(b bool) uint32 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// For testing *Pointer[T]'s methods can be inlined.
|
||||
// Keep in sync with cmd/compile/internal/test/inl_test.go:TestIntendedInlining.
|
||||
var _ = &Pointer[int]{}
|
||||
|
||||
// A Pointer is an atomic pointer of type *T. The zero value is a nil *T.
|
||||
type Pointer[T any] struct {
|
||||
// Mention *T in a field to disallow conversion between Pointer types.
|
||||
// See go.dev/issue/56603 for more details.
|
||||
// Use *T, not T, to avoid spurious recursive type definition errors.
|
||||
_ [0]*T
|
||||
|
||||
_ noCopy
|
||||
v unsafe.Pointer
|
||||
}
|
||||
|
||||
// Load atomically loads and returns the value stored in x.
|
||||
func (x *Pointer[T]) Load() *T { return (*T)(LoadPointer(&x.v)) }
|
||||
|
||||
// Store atomically stores val into x.
|
||||
func (x *Pointer[T]) Store(val *T) { StorePointer(&x.v, unsafe.Pointer(val)) }
|
||||
|
||||
// Swap atomically stores new into x and returns the previous value.
|
||||
func (x *Pointer[T]) Swap(new *T) (old *T) { return (*T)(SwapPointer(&x.v, unsafe.Pointer(new))) }
|
||||
|
||||
// CompareAndSwap executes the compare-and-swap operation for x.
|
||||
func (x *Pointer[T]) CompareAndSwap(old, new *T) (swapped bool) {
|
||||
return CompareAndSwapPointer(&x.v, unsafe.Pointer(old), unsafe.Pointer(new))
|
||||
}
|
||||
|
||||
// An Int32 is an atomic int32. The zero value is zero.
|
||||
type Int32 struct {
|
||||
_ noCopy
|
||||
v int32
|
||||
}
|
||||
|
||||
// Load atomically loads and returns the value stored in x.
|
||||
func (x *Int32) Load() int32 { return LoadInt32(&x.v) }
|
||||
|
||||
// Store atomically stores val into x.
|
||||
func (x *Int32) Store(val int32) { StoreInt32(&x.v, val) }
|
||||
|
||||
// Swap atomically stores new into x and returns the previous value.
|
||||
func (x *Int32) Swap(new int32) (old int32) { return SwapInt32(&x.v, new) }
|
||||
|
||||
// CompareAndSwap executes the compare-and-swap operation for x.
|
||||
func (x *Int32) CompareAndSwap(old, new int32) (swapped bool) {
|
||||
return CompareAndSwapInt32(&x.v, old, new)
|
||||
}
|
||||
|
||||
// Add atomically adds delta to x and returns the new value.
|
||||
func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) }
|
||||
|
||||
// An Int64 is an atomic int64. The zero value is zero.
|
||||
type Int64 struct {
|
||||
_ noCopy
|
||||
_ align64
|
||||
v int64
|
||||
}
|
||||
|
||||
// Load atomically loads and returns the value stored in x.
|
||||
func (x *Int64) Load() int64 { return LoadInt64(&x.v) }
|
||||
|
||||
// Store atomically stores val into x.
|
||||
func (x *Int64) Store(val int64) { StoreInt64(&x.v, val) }
|
||||
|
||||
// Swap atomically stores new into x and returns the previous value.
|
||||
func (x *Int64) Swap(new int64) (old int64) { return SwapInt64(&x.v, new) }
|
||||
|
||||
// CompareAndSwap executes the compare-and-swap operation for x.
|
||||
func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) {
|
||||
return CompareAndSwapInt64(&x.v, old, new)
|
||||
}
|
||||
|
||||
// Add atomically adds delta to x and returns the new value.
|
||||
func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) }
|
||||
|
||||
// A Uint32 is an atomic uint32. The zero value is zero.
|
||||
type Uint32 struct {
|
||||
_ noCopy
|
||||
v uint32
|
||||
}
|
||||
|
||||
// Load atomically loads and returns the value stored in x.
|
||||
func (x *Uint32) Load() uint32 { return LoadUint32(&x.v) }
|
||||
|
||||
// Store atomically stores val into x.
|
||||
func (x *Uint32) Store(val uint32) { StoreUint32(&x.v, val) }
|
||||
|
||||
// Swap atomically stores new into x and returns the previous value.
|
||||
func (x *Uint32) Swap(new uint32) (old uint32) { return SwapUint32(&x.v, new) }
|
||||
|
||||
// CompareAndSwap executes the compare-and-swap operation for x.
|
||||
func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) {
|
||||
return CompareAndSwapUint32(&x.v, old, new)
|
||||
}
|
||||
|
||||
// Add atomically adds delta to x and returns the new value.
|
||||
func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) }
|
||||
|
||||
// A Uint64 is an atomic uint64. The zero value is zero.
|
||||
type Uint64 struct {
|
||||
_ noCopy
|
||||
_ align64
|
||||
v uint64
|
||||
}
|
||||
|
||||
// Load atomically loads and returns the value stored in x.
|
||||
func (x *Uint64) Load() uint64 { return LoadUint64(&x.v) }
|
||||
|
||||
// Store atomically stores val into x.
|
||||
func (x *Uint64) Store(val uint64) { StoreUint64(&x.v, val) }
|
||||
|
||||
// Swap atomically stores new into x and returns the previous value.
|
||||
func (x *Uint64) Swap(new uint64) (old uint64) { return SwapUint64(&x.v, new) }
|
||||
|
||||
// CompareAndSwap executes the compare-and-swap operation for x.
|
||||
func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) {
|
||||
return CompareAndSwapUint64(&x.v, old, new)
|
||||
}
|
||||
|
||||
// Add atomically adds delta to x and returns the new value.
|
||||
func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) }
|
||||
|
||||
// A Uintptr is an atomic uintptr. The zero value is zero.
|
||||
type Uintptr struct {
|
||||
_ noCopy
|
||||
v uintptr
|
||||
}
|
||||
|
||||
// Load atomically loads and returns the value stored in x.
|
||||
func (x *Uintptr) Load() uintptr { return LoadUintptr(&x.v) }
|
||||
|
||||
// Store atomically stores val into x.
|
||||
func (x *Uintptr) Store(val uintptr) { StoreUintptr(&x.v, val) }
|
||||
|
||||
// Swap atomically stores new into x and returns the previous value.
|
||||
func (x *Uintptr) Swap(new uintptr) (old uintptr) { return SwapUintptr(&x.v, new) }
|
||||
|
||||
// CompareAndSwap executes the compare-and-swap operation for x.
|
||||
func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool) {
|
||||
return CompareAndSwapUintptr(&x.v, old, new)
|
||||
}
|
||||
|
||||
// Add atomically adds delta to x and returns the new value.
|
||||
func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) }
|
||||
|
||||
// noCopy may be added to structs which must not be copied
|
||||
// after the first use.
|
||||
//
|
||||
// See https://golang.org/issues/8005#issuecomment-190753527
|
||||
// for details.
|
||||
//
|
||||
// Note that it must not be embedded, due to the Lock and Unlock methods.
|
||||
type noCopy struct{}
|
||||
|
||||
// Lock is a no-op used by -copylocks checker from `go vet`.
|
||||
func (*noCopy) Lock() {}
|
||||
func (*noCopy) Unlock() {}
|
||||
|
||||
// align64 may be added to structs that must be 64-bit aligned.
|
||||
// This struct is recognized by a special case in the compiler
|
||||
// and will not work if copied to any other package.
|
||||
type align64 struct{}
|
||||
100
stdlib/generic/go1_22_sync_oncefunc.go.txt
Normal file
100
stdlib/generic/go1_22_sync_oncefunc.go.txt
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sync
|
||||
|
||||
// OnceFunc returns a function that invokes f only once. The returned function
|
||||
// may be called concurrently.
|
||||
//
|
||||
// If f panics, the returned function will panic with the same value on every call.
|
||||
func OnceFunc(f func()) func() {
|
||||
var (
|
||||
once Once
|
||||
valid bool
|
||||
p any
|
||||
)
|
||||
// Construct the inner closure just once to reduce costs on the fast path.
|
||||
g := func() {
|
||||
defer func() {
|
||||
p = recover()
|
||||
if !valid {
|
||||
// Re-panic immediately so on the first call the user gets a
|
||||
// complete stack trace into f.
|
||||
panic(p)
|
||||
}
|
||||
}()
|
||||
f()
|
||||
f = nil // Do not keep f alive after invoking it.
|
||||
valid = true // Set only if f does not panic.
|
||||
}
|
||||
return func() {
|
||||
once.Do(g)
|
||||
if !valid {
|
||||
panic(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnceValue returns a function that invokes f only once and returns the value
|
||||
// returned by f. The returned function may be called concurrently.
|
||||
//
|
||||
// If f panics, the returned function will panic with the same value on every call.
|
||||
func OnceValue[T any](f func() T) func() T {
|
||||
var (
|
||||
once Once
|
||||
valid bool
|
||||
p any
|
||||
result T
|
||||
)
|
||||
g := func() {
|
||||
defer func() {
|
||||
p = recover()
|
||||
if !valid {
|
||||
panic(p)
|
||||
}
|
||||
}()
|
||||
result = f()
|
||||
f = nil
|
||||
valid = true
|
||||
}
|
||||
return func() T {
|
||||
once.Do(g)
|
||||
if !valid {
|
||||
panic(p)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// OnceValues returns a function that invokes f only once and returns the values
|
||||
// returned by f. The returned function may be called concurrently.
|
||||
//
|
||||
// If f panics, the returned function will panic with the same value on every call.
|
||||
func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
|
||||
var (
|
||||
once Once
|
||||
valid bool
|
||||
p any
|
||||
r1 T1
|
||||
r2 T2
|
||||
)
|
||||
g := func() {
|
||||
defer func() {
|
||||
p = recover()
|
||||
if !valid {
|
||||
panic(p)
|
||||
}
|
||||
}()
|
||||
r1, r2 = f()
|
||||
f = nil
|
||||
valid = true
|
||||
}
|
||||
return func() (T1, T2) {
|
||||
once.Do(g)
|
||||
if !valid {
|
||||
panic(p)
|
||||
}
|
||||
return r1, r2
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
// Code generated by 'yaegi extract crypto/tls'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.20 && !go1.21
|
||||
// +build go1.20,!go1.21
|
||||
|
||||
package stdlib
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Symbols["crypto/tls/tls"] = map[string]reflect.Value{
|
||||
// function, constant and variable definitions
|
||||
"CipherSuiteName": reflect.ValueOf(tls.CipherSuiteName),
|
||||
"CipherSuites": reflect.ValueOf(tls.CipherSuites),
|
||||
"Client": reflect.ValueOf(tls.Client),
|
||||
"CurveP256": reflect.ValueOf(tls.CurveP256),
|
||||
"CurveP384": reflect.ValueOf(tls.CurveP384),
|
||||
"CurveP521": reflect.ValueOf(tls.CurveP521),
|
||||
"Dial": reflect.ValueOf(tls.Dial),
|
||||
"DialWithDialer": reflect.ValueOf(tls.DialWithDialer),
|
||||
"ECDSAWithP256AndSHA256": reflect.ValueOf(tls.ECDSAWithP256AndSHA256),
|
||||
"ECDSAWithP384AndSHA384": reflect.ValueOf(tls.ECDSAWithP384AndSHA384),
|
||||
"ECDSAWithP521AndSHA512": reflect.ValueOf(tls.ECDSAWithP521AndSHA512),
|
||||
"ECDSAWithSHA1": reflect.ValueOf(tls.ECDSAWithSHA1),
|
||||
"Ed25519": reflect.ValueOf(tls.Ed25519),
|
||||
"InsecureCipherSuites": reflect.ValueOf(tls.InsecureCipherSuites),
|
||||
"Listen": reflect.ValueOf(tls.Listen),
|
||||
"LoadX509KeyPair": reflect.ValueOf(tls.LoadX509KeyPair),
|
||||
"NewLRUClientSessionCache": reflect.ValueOf(tls.NewLRUClientSessionCache),
|
||||
"NewListener": reflect.ValueOf(tls.NewListener),
|
||||
"NoClientCert": reflect.ValueOf(tls.NoClientCert),
|
||||
"PKCS1WithSHA1": reflect.ValueOf(tls.PKCS1WithSHA1),
|
||||
"PKCS1WithSHA256": reflect.ValueOf(tls.PKCS1WithSHA256),
|
||||
"PKCS1WithSHA384": reflect.ValueOf(tls.PKCS1WithSHA384),
|
||||
"PKCS1WithSHA512": reflect.ValueOf(tls.PKCS1WithSHA512),
|
||||
"PSSWithSHA256": reflect.ValueOf(tls.PSSWithSHA256),
|
||||
"PSSWithSHA384": reflect.ValueOf(tls.PSSWithSHA384),
|
||||
"PSSWithSHA512": reflect.ValueOf(tls.PSSWithSHA512),
|
||||
"RenegotiateFreelyAsClient": reflect.ValueOf(tls.RenegotiateFreelyAsClient),
|
||||
"RenegotiateNever": reflect.ValueOf(tls.RenegotiateNever),
|
||||
"RenegotiateOnceAsClient": reflect.ValueOf(tls.RenegotiateOnceAsClient),
|
||||
"RequestClientCert": reflect.ValueOf(tls.RequestClientCert),
|
||||
"RequireAndVerifyClientCert": reflect.ValueOf(tls.RequireAndVerifyClientCert),
|
||||
"RequireAnyClientCert": reflect.ValueOf(tls.RequireAnyClientCert),
|
||||
"Server": reflect.ValueOf(tls.Server),
|
||||
"TLS_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_AES_128_GCM_SHA256),
|
||||
"TLS_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_AES_256_GCM_SHA384),
|
||||
"TLS_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_CHACHA20_POLY1305_SHA256),
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256),
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256),
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384),
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305),
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256),
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA),
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA),
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256),
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256),
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305),
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256),
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA),
|
||||
"TLS_FALLBACK_SCSV": reflect.ValueOf(tls.TLS_FALLBACK_SCSV),
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA),
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_CBC_SHA),
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_CBC_SHA256),
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256": reflect.ValueOf(tls.TLS_RSA_WITH_AES_128_GCM_SHA256),
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_AES_256_CBC_SHA),
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384": reflect.ValueOf(tls.TLS_RSA_WITH_AES_256_GCM_SHA384),
|
||||
"TLS_RSA_WITH_RC4_128_SHA": reflect.ValueOf(tls.TLS_RSA_WITH_RC4_128_SHA),
|
||||
"VerifyClientCertIfGiven": reflect.ValueOf(tls.VerifyClientCertIfGiven),
|
||||
"VersionSSL30": reflect.ValueOf(constant.MakeFromLiteral("768", token.INT, 0)),
|
||||
"VersionTLS10": reflect.ValueOf(constant.MakeFromLiteral("769", token.INT, 0)),
|
||||
"VersionTLS11": reflect.ValueOf(constant.MakeFromLiteral("770", token.INT, 0)),
|
||||
"VersionTLS12": reflect.ValueOf(constant.MakeFromLiteral("771", token.INT, 0)),
|
||||
"VersionTLS13": reflect.ValueOf(constant.MakeFromLiteral("772", token.INT, 0)),
|
||||
"X25519": reflect.ValueOf(tls.X25519),
|
||||
"X509KeyPair": reflect.ValueOf(tls.X509KeyPair),
|
||||
|
||||
// type definitions
|
||||
"Certificate": reflect.ValueOf((*tls.Certificate)(nil)),
|
||||
"CertificateRequestInfo": reflect.ValueOf((*tls.CertificateRequestInfo)(nil)),
|
||||
"CertificateVerificationError": reflect.ValueOf((*tls.CertificateVerificationError)(nil)),
|
||||
"CipherSuite": reflect.ValueOf((*tls.CipherSuite)(nil)),
|
||||
"ClientAuthType": reflect.ValueOf((*tls.ClientAuthType)(nil)),
|
||||
"ClientHelloInfo": reflect.ValueOf((*tls.ClientHelloInfo)(nil)),
|
||||
"ClientSessionCache": reflect.ValueOf((*tls.ClientSessionCache)(nil)),
|
||||
"ClientSessionState": reflect.ValueOf((*tls.ClientSessionState)(nil)),
|
||||
"Config": reflect.ValueOf((*tls.Config)(nil)),
|
||||
"Conn": reflect.ValueOf((*tls.Conn)(nil)),
|
||||
"ConnectionState": reflect.ValueOf((*tls.ConnectionState)(nil)),
|
||||
"CurveID": reflect.ValueOf((*tls.CurveID)(nil)),
|
||||
"Dialer": reflect.ValueOf((*tls.Dialer)(nil)),
|
||||
"RecordHeaderError": reflect.ValueOf((*tls.RecordHeaderError)(nil)),
|
||||
"RenegotiationSupport": reflect.ValueOf((*tls.RenegotiationSupport)(nil)),
|
||||
"SignatureScheme": reflect.ValueOf((*tls.SignatureScheme)(nil)),
|
||||
|
||||
// interface wrapper definitions
|
||||
"_ClientSessionCache": reflect.ValueOf((*_crypto_tls_ClientSessionCache)(nil)),
|
||||
}
|
||||
}
|
||||
|
||||
// _crypto_tls_ClientSessionCache is an interface wrapper for ClientSessionCache type
|
||||
type _crypto_tls_ClientSessionCache struct {
|
||||
IValue interface{}
|
||||
WGet func(sessionKey string) (session *tls.ClientSessionState, ok bool)
|
||||
WPut func(sessionKey string, cs *tls.ClientSessionState)
|
||||
}
|
||||
|
||||
func (W _crypto_tls_ClientSessionCache) Get(sessionKey string) (session *tls.ClientSessionState, ok bool) {
|
||||
return W.WGet(sessionKey)
|
||||
}
|
||||
func (W _crypto_tls_ClientSessionCache) Put(sessionKey string, cs *tls.ClientSessionState) {
|
||||
W.WPut(sessionKey, cs)
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// Code generated by 'yaegi extract errors'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.20 && !go1.21
|
||||
// +build go1.20,!go1.21
|
||||
|
||||
package stdlib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Symbols["errors/errors"] = map[string]reflect.Value{
|
||||
// function, constant and variable definitions
|
||||
"As": reflect.ValueOf(errors.As),
|
||||
"Is": reflect.ValueOf(errors.Is),
|
||||
"Join": reflect.ValueOf(errors.Join),
|
||||
"New": reflect.ValueOf(errors.New),
|
||||
"Unwrap": reflect.ValueOf(errors.Unwrap),
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract archive/tar'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract archive/zip'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract bufio'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract bytes'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract cmp'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract compress/bzip2'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract compress/flate'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract compress/gzip'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract compress/lzw'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract compress/zlib'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract container/heap'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract container/list'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract container/ring'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract context'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/aes'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/cipher'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/des'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/dsa'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/ecdh'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/ecdsa'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/ed25519'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/elliptic'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/hmac'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/md5'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/rand'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/rc4'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/rsa'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/sha1'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/sha256'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/sha512'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/subtle'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/tls'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/x509'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract crypto/x509/pkix'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract database/sql'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract database/sql/driver'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract debug/buildinfo'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract debug/dwarf'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract debug/elf'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract debug/gosym'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract debug/macho'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract debug/pe'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract debug/plan9obj'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/ascii85'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/asn1'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/base32'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/base64'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/binary'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/csv'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/gob'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/hex'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/json'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/pem'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract encoding/xml'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract errors'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract expvar'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract flag'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract fmt'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/ast'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/build'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/build/constraint'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/constant'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/doc'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/doc/comment'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/format'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/importer'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/parser'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/printer'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/scanner'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/token'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract go/types'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract hash'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract hash/adler32'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract hash/crc32'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract hash/crc64'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract hash/fnv'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract hash/maphash'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by 'yaegi extract html'. DO NOT EDIT.
|
||||
|
||||
//go:build go1.21
|
||||
// +build go1.21
|
||||
//go:build go1.21 && !go1.22
|
||||
// +build go1.21,!go1.22
|
||||
|
||||
package stdlib
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user