]> Cypherpunks.ru repositories - gostls13.git/blob - src/sync/oncefunc.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / sync / oncefunc.go
1 // Copyright 2022 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package sync
6
7 // OnceFunc returns a function that invokes f only once. The returned function
8 // may be called concurrently.
9 //
10 // If f panics, the returned function will panic with the same value on every call.
11 func OnceFunc(f func()) func() {
12         var (
13                 once  Once
14                 valid bool
15                 p     any
16         )
17         // Construct the inner closure just once to reduce costs on the fast path.
18         g := func() {
19                 defer func() {
20                         p = recover()
21                         if !valid {
22                                 // Re-panic immediately so on the first call the user gets a
23                                 // complete stack trace into f.
24                                 panic(p)
25                         }
26                 }()
27                 f()
28                 valid = true // Set only if f does not panic
29         }
30         return func() {
31                 once.Do(g)
32                 if !valid {
33                         panic(p)
34                 }
35         }
36 }
37
38 // OnceValue returns a function that invokes f only once and returns the value
39 // returned by f. The returned function may be called concurrently.
40 //
41 // If f panics, the returned function will panic with the same value on every call.
42 func OnceValue[T any](f func() T) func() T {
43         var (
44                 once   Once
45                 valid  bool
46                 p      any
47                 result T
48         )
49         g := func() {
50                 defer func() {
51                         p = recover()
52                         if !valid {
53                                 panic(p)
54                         }
55                 }()
56                 result = f()
57                 valid = true
58         }
59         return func() T {
60                 once.Do(g)
61                 if !valid {
62                         panic(p)
63                 }
64                 return result
65         }
66 }
67
68 // OnceValues returns a function that invokes f only once and returns the values
69 // returned by f. The returned function may be called concurrently.
70 //
71 // If f panics, the returned function will panic with the same value on every call.
72 func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
73         var (
74                 once  Once
75                 valid bool
76                 p     any
77                 r1    T1
78                 r2    T2
79         )
80         g := func() {
81                 defer func() {
82                         p = recover()
83                         if !valid {
84                                 panic(p)
85                         }
86                 }()
87                 r1, r2 = f()
88                 valid = true
89         }
90         return func() (T1, T2) {
91                 once.Do(g)
92                 if !valid {
93                         panic(p)
94                 }
95                 return r1, r2
96         }
97 }