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 }