Skip to content

Commit

Permalink
Add go1.21 compat funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Oct 19, 2024
1 parent c635464 commit d59ac57
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 0 deletions.
15 changes: 15 additions & 0 deletions common/minmax.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build go1.21

package common

import (
"cmp"
)

func Min[T cmp.Ordered](x, y T) T {
return min(x, y)
}

func Max[T cmp.Ordered](x, y T) T {
return max(x, y)
}
19 changes: 19 additions & 0 deletions common/minmax_compat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//go:build go1.20 && !go1.21

package common

import "github.com/sagernet/sing/common/x/constraints"

func Min[T constraints.Ordered](x, y T) T {
if x < y {
return x
}
return y
}

func Max[T constraints.Ordered](x, y T) T {
if x < y {
return y
}
return x
}
20 changes: 20 additions & 0 deletions common/oncefunc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//go:build go1.21

package common

import "sync"

// OnceFunc is a wrapper around sync.OnceFunc.
func OnceFunc(f func()) func() {
return sync.OnceFunc(f)
}

// OnceValue is a wrapper around sync.OnceValue.
func OnceValue[T any](f func() T) func() T {
return sync.OnceValue(f)
}

// OnceValues is a wrapper around sync.OnceValues.
func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
return sync.OnceValues(f)
}
104 changes: 104 additions & 0 deletions common/oncefunc_compat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// 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.

//go:build go1.20 && !go1.21

package common

import "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 sync.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 sync.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 sync.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
}
}

0 comments on commit d59ac57

Please sign in to comment.