github.com/aristanetworks/goarista@v0.0.0-20240514173732-cca2755bbd44/monitor/map.go (about)

     1  // Copyright (c) 2017 Arista Networks, Inc.
     2  // Use of this source code is governed by the Apache License 2.0
     3  // that can be found in the COPYING file.
     4  
     5  // This code was forked from the Go project, here's the original copyright header:
     6  
     7  // Copyright 2009 The Go Authors. All rights reserved.
     8  // Use of this source code is governed by a BSD-style
     9  // license that can be found in the LICENSE file.
    10  
    11  package monitor
    12  
    13  import (
    14  	"expvar"
    15  	"fmt"
    16  	"strings"
    17  	"sync"
    18  )
    19  
    20  // Map is a string-to-Var map variable that satisfies the Var interface.
    21  // This a streamlined, more efficient version of expvar.Map, that also
    22  // supports deletion.
    23  type Map struct {
    24  	m sync.Map // map[string]expvar.Var
    25  }
    26  
    27  func (v *Map) String() string {
    28  	var b strings.Builder
    29  	b.WriteByte('{')
    30  	first := true
    31  	v.m.Range(func(k, value interface{}) bool {
    32  		if !first {
    33  			b.WriteString(", ")
    34  		}
    35  		fmt.Fprintf(&b, "%q: %v", k, value)
    36  		first = false
    37  		return true
    38  	})
    39  	b.WriteByte('}')
    40  	return b.String()
    41  }
    42  
    43  // Get atomically returns the Var for the given key or nil.
    44  func (v *Map) Get(key string) expvar.Var {
    45  	i, _ := v.m.Load(key)
    46  	av, _ := i.(expvar.Var)
    47  	return av
    48  }
    49  
    50  // Set atomically associates the given Var to the given key.
    51  func (v *Map) Set(key string, av expvar.Var) {
    52  	// Before we store the value, check to see whether the key is new. Try a Load
    53  	// before LoadOrStore: LoadOrStore causes the key interface to escape even on
    54  	// the Load path.
    55  	if _, ok := v.m.Load(key); !ok {
    56  		if _, dup := v.m.LoadOrStore(key, av); !dup {
    57  			return
    58  		}
    59  	}
    60  
    61  	v.m.Store(key, av)
    62  }
    63  
    64  // Delete atomically deletes the given key if it exists.
    65  func (v *Map) Delete(key string) {
    66  	v.m.Delete(key)
    67  }
    68  
    69  // Do calls f for each entry in the map.
    70  // The map is locked during the iteration,
    71  // but existing entries may be concurrently updated.
    72  func (v *Map) Do(f func(expvar.KeyValue)) {
    73  	v.m.Range(func(k, value interface{}) bool {
    74  		f(expvar.KeyValue{Key: k.(string), Value: value.(expvar.Var)})
    75  		return true
    76  	})
    77  }
    78  
    79  // NewMap creates a new Map and publishes it with the given name.
    80  func NewMap(name string) *Map {
    81  	v := new(Map)
    82  	expvar.Publish(name, v)
    83  	return v
    84  }