Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / debounce.go
1 // Copyright 2020 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 lsp
6
7 import (
8         "sync"
9         "time"
10 )
11
12 type debounceFunc struct {
13         order uint64
14         done  chan struct{}
15 }
16
17 type debouncer struct {
18         mu    sync.Mutex
19         funcs map[string]*debounceFunc
20 }
21
22 func newDebouncer() *debouncer {
23         return &debouncer{
24                 funcs: make(map[string]*debounceFunc),
25         }
26 }
27
28 // debounce waits timeout before running f, if no subsequent call is made with
29 // the same key in the intervening time. If a later call to debounce with the
30 // same key occurs while the original call is blocking, the original call will
31 // return immediately without running its f.
32 //
33 // If order is specified, it will be used to order calls logically, so calls
34 // with lesser order will not cancel calls with greater order.
35 func (d *debouncer) debounce(key string, order uint64, timeout time.Duration, f func()) {
36         if timeout == 0 {
37                 // Degenerate case: no debouncing.
38                 f()
39                 return
40         }
41
42         // First, atomically acquire the current func, cancel it, and insert this
43         // call into d.funcs.
44         d.mu.Lock()
45         current, ok := d.funcs[key]
46         if ok && current.order > order {
47                 // If we have a logical ordering of events (as is the case for snapshots),
48                 // don't overwrite a later event with an earlier event.
49                 d.mu.Unlock()
50                 return
51         }
52         if ok {
53                 close(current.done)
54         }
55         done := make(chan struct{})
56         next := &debounceFunc{
57                 order: order,
58                 done:  done,
59         }
60         d.funcs[key] = next
61         d.mu.Unlock()
62
63         // Next, wait to be cancelled or for our wait to expire. There is a race here
64         // that we must handle: our timer could expire while another goroutine holds
65         // d.mu.
66         select {
67         case <-done:
68         case <-time.After(timeout):
69                 d.mu.Lock()
70                 if d.funcs[key] != next {
71                         // We lost the race: another event has arrived for the key and started
72                         // waiting. We could reasonably choose to run f at this point, but doing
73                         // nothing is simpler.
74                         d.mu.Unlock()
75                         return
76                 }
77                 delete(d.funcs, key)
78                 d.mu.Unlock()
79                 f()
80         }
81 }