From 9c712376e197d45c07bd56f74174347c32752ffa Mon Sep 17 00:00:00 2001 From: spekary Date: Wed, 7 Aug 2019 14:21:29 -0700 Subject: [PATCH] Some interfaces are not comparable, so SetChanged will not work on them. --- pkg/maps/map.go | 21 +----- pkg/maps/map_test.go | 25 -------- pkg/maps/safemap.go | 23 +------ pkg/maps/safemap_test.go | 25 -------- pkg/maps/safeslicemap.go | 64 ++++++++----------- pkg/maps/safeslicemap_test.go | 19 +----- pkg/maps/safestrmap.go | 19 ++++++ pkg/maps/safestrslicemap.go | 58 ++++++++++++++++- pkg/maps/slicemap.go | 64 ++++++++----------- pkg/maps/slicemap_test.go | 19 +----- pkg/maps/strmap.go | 17 +++++ pkg/maps/strslicemap.go | 54 +++++++++++++++- templates/map_src/safe_string_interface.json | 3 +- templates/map_src/slice_map.tmpl | 64 ++++++++++++++++++- templates/map_src/standard_map.tmpl | 23 +++++++ templates/map_src/string_interface.json | 3 +- .../map_src/string_interface_slice_test.tmpl | 19 +----- templates/map_src/string_interface_test.tmpl | 25 -------- 18 files changed, 299 insertions(+), 246 deletions(-) diff --git a/pkg/maps/map.go b/pkg/maps/map.go index e843a30..06c06e3 100644 --- a/pkg/maps/map.go +++ b/pkg/maps/map.go @@ -47,26 +47,7 @@ func (o *Map) Clear() { o.items = nil } -// SetChanged sets the key to the value and returns a boolean indicating whether doing this caused -// the map to change. It will return true if the key did not first exist, or if the value associated -// with the key was different than the new value. -func (o *Map) SetChanged(key string, val interface{}) (changed bool) { - var ok bool - var oldVal interface{} - if o == nil { - panic("The map must be created before being used.") - } - if o.items == nil { - o.items = make(map[string]interface{}) - } - - if oldVal, ok = o.items[key]; !ok || oldVal != val { - o.items[key] = val - changed = true - } - return -} // Set sets the key to the given value func (o *Map) Set(key string, val interface{}) { @@ -159,6 +140,8 @@ func (o *Map) Has(key string) (exists bool) { return } + + // Values returns a slice of the values. It will return a nil slice if the map is empty. // Multiple calls to Values will result in the same list of values, but may be in a different order. func (o *Map) Values() (vals []interface{}) { diff --git a/pkg/maps/map_test.go b/pkg/maps/map_test.go index e8c9942..8989cb9 100644 --- a/pkg/maps/map_test.go +++ b/pkg/maps/map_test.go @@ -70,12 +70,6 @@ func TestMap(t *testing.T) { t.Error("Set after clear failed.") } - m.Clear() - m.SetChanged("E", 15.5) - if m.Get("E") != 15.5 { - t.Error("SetChanged after clear failed.") - } - n := m.Copy() if n.Get("E") != 15.5 { t.Error("Copy failed.") @@ -133,25 +127,6 @@ func TestEmpty(t *testing.T) { } -func TestMapChange(t *testing.T) { - m := NewMap() - - m.Set("B", "This") - m.Set("A", "That") - m.Set("C", 5) - - if changed := m.SetChanged("D", 6); !changed { - t.Error("Set did not produce a change flag") - } - - if changed := m.SetChanged("D", 6); changed { - t.Error("Set again erroneously produced a change flag") - } - - if changed := m.SetChanged("D", "That"); !changed { - t.Error("Set again did not produce a change flag") - } -} func TestMapNotEqual(t *testing.T) { m := NewMap() diff --git a/pkg/maps/safemap.go b/pkg/maps/safemap.go index fe800af..72c0844 100644 --- a/pkg/maps/safemap.go +++ b/pkg/maps/safemap.go @@ -52,28 +52,7 @@ func (o *SafeMap) Clear() { o.Unlock() } -// SetChanged sets the key to the value and returns a boolean indicating whether doing this caused -// the map to change. It will return true if the key did not first exist, or if the value associated -// with the key was different than the new value. -func (o *SafeMap) SetChanged(key string, val interface{}) (changed bool) { - var ok bool - var oldVal interface{} - if o == nil { - panic("The map must be created before being used.") - } - o.Lock() - if o.items == nil { - o.items = make(map[string]interface{}) - } - - if oldVal, ok = o.items[key]; !ok || oldVal != val { - o.items[key] = val - changed = true - } - o.Unlock() - return -} // Set sets the key to the given value func (o *SafeMap) Set(key string, val interface{}) { @@ -174,6 +153,8 @@ func (o *SafeMap) Has(key string) (exists bool) { return } + + // Values returns a slice of the values. It will return a nil slice if the map is empty. // Multiple calls to Values will result in the same list of values, but may be in a different order. func (o *SafeMap) Values() (vals []interface{}) { diff --git a/pkg/maps/safemap_test.go b/pkg/maps/safemap_test.go index 0339c4c..1b9154c 100644 --- a/pkg/maps/safemap_test.go +++ b/pkg/maps/safemap_test.go @@ -70,12 +70,6 @@ func TestSafeMap(t *testing.T) { t.Error("Set after clear failed.") } - m.Clear() - m.SetChanged("E", 15.5) - if m.Get("E") != 15.5 { - t.Error("SetChanged after clear failed.") - } - n := m.Copy() if n.Get("E") != 15.5 { t.Error("Copy failed.") @@ -133,25 +127,6 @@ func TestSafeEmpty(t *testing.T) { } -func TestSafeMapChange(t *testing.T) { - m := NewSafeMap() - - m.Set("B", "This") - m.Set("A", "That") - m.Set("C", 5) - - if changed := m.SetChanged("D", 6); !changed { - t.Error("Set did not produce a change flag") - } - - if changed := m.SetChanged("D", 6); changed { - t.Error("Set again erroneously produced a change flag") - } - - if changed := m.SetChanged("D", "That"); !changed { - t.Error("Set again did not produce a change flag") - } -} func TestSafeMapNotEqual(t *testing.T) { m := NewSafeMap() diff --git a/pkg/maps/safeslicemap.go b/pkg/maps/safeslicemap.go index 499634f..6e40b05 100644 --- a/pkg/maps/safeslicemap.go +++ b/pkg/maps/safeslicemap.go @@ -82,13 +82,11 @@ func keySortSafeSliceMap(key1, key2 string, val1, val2 interface{}) bool { -// SetChanged sets the value. -// It returns true if something in the map changed. If the key -// was already in the map, and you have not provided a sort function, -// the order will not change, but the value will be replaced. If you wanted the -// order to change, you must Delete then call SetChanged. If you have previously set a sort function, -// the order will be updated. -func (o *SafeSliceMap) SetChanged(key string, val interface{}) (changed bool) { + + +// Set sets the given key to the given value. +// If the key already exists, the range order will not change. +func (o *SafeSliceMap) Set(key string, val interface{}) { var ok bool var oldVal interface{} @@ -101,42 +99,34 @@ func (o *SafeSliceMap) SetChanged(key string, val interface{}) (changed bool) { o.items = make(map[string]interface{}) } - if oldVal, ok = o.items[key]; !ok || oldVal != val { - if o.lessF != nil { - if ok { - // delete old key location - loc := sort.Search (len(o.items), func(n int) bool { - return !o.lessF(o.order[n], key, o.items[o.order[n]], oldVal) - }) - o.order = append(o.order[:loc], o.order[loc+1:]...) - } - - loc := sort.Search (len(o.order), func(n int) bool { - return o.lessF(key, o.order[n], val, o.items[o.order[n]]) + _, ok = o.items[key] + if o.lessF != nil { + if ok { + // delete old key location + loc := sort.Search (len(o.items), func(n int) bool { + return !o.lessF(o.order[n], key, o.items[o.order[n]], oldVal) }) - // insert + o.order = append(o.order[:loc], o.order[loc+1:]...) + } + + loc := sort.Search (len(o.order), func(n int) bool { + return o.lessF(key, o.order[n], val, o.items[o.order[n]]) + }) + // insert + o.order = append(o.order, key) + copy(o.order[loc+1:], o.order[loc:]) + o.order[loc] = key + } else { + if !ok { o.order = append(o.order, key) - copy(o.order[loc+1:], o.order[loc:]) - o.order[loc] = key - } else { - if !ok { - o.order = append(o.order, key) - } - } - o.items[key] = val - changed = true - } + } + } + o.items[key] = val o.Unlock() return } -// Set sets the given key to the given value. -// If the key already exists, the range order will not change. -func (o *SafeSliceMap) Set(key string, val interface{}) { - o.SetChanged(key, val) -} - // SetAt sets the given key to the given value, but also inserts it at the index specified. If the index is bigger than // the length, it puts it at the end. Negative indexes are backwards from the end. func (o *SafeSliceMap) SetAt(index int, key string, val interface{}) { @@ -272,6 +262,8 @@ func (o *SafeSliceMap) Has(key string) (ok bool) { return } + + // GetAt returns the value based on its position. If the position is out of bounds, an empty value is returned. func (o *SafeSliceMap) GetAt(position int) (val interface{}) { if o == nil { diff --git a/pkg/maps/safeslicemap_test.go b/pkg/maps/safeslicemap_test.go index f6fad6c..82c31db 100644 --- a/pkg/maps/safeslicemap_test.go +++ b/pkg/maps/safeslicemap_test.go @@ -59,9 +59,7 @@ func TestSafeSliceMap(t *testing.T) { t.Error("MapI interface test failed.") } - if changed := m.SetChanged("F", 9); !changed { - t.Error("Add non-string value failed.") - } + m.Set("F", 9) if m.Get("F") != 9 { t.Error("Add non-string value failed.") } @@ -73,21 +71,6 @@ func TestSafeSliceMap(t *testing.T) { } -func TestSafeSliceMapChange(t *testing.T) { - m := new (SafeSliceMap) - - m.Set("B", "This") - m.Set("A", "That") - m.Set("C", "Other") - - if changed := m.SetChanged("D", "And another"); !changed { - t.Error("Set did not produce a change flag") - } - - if changed := m.SetChanged("D", "And another"); changed { - t.Error("Set again erroneously produced a change flag") - } -} func ExampleSafeSliceMap_Range() { m := new (SafeSliceMap) diff --git a/pkg/maps/safestrmap.go b/pkg/maps/safestrmap.go index 7270636..22db285 100644 --- a/pkg/maps/safestrmap.go +++ b/pkg/maps/safestrmap.go @@ -52,6 +52,7 @@ func (o *SafeStringMap) Clear() { o.Unlock() } + // SetChanged sets the key to the value and returns a boolean indicating whether doing this caused // the map to change. It will return true if the key did not first exist, or if the value associated // with the key was different than the new value. @@ -75,6 +76,7 @@ func (o *SafeStringMap) SetChanged(key string, val string) (changed bool) { return } + // Set sets the key to the given value func (o *SafeStringMap) Set(key string, val string) { if o == nil { @@ -138,6 +140,23 @@ func (o *SafeStringMap) Has(key string) (exists bool) { return } + +// Is returns true if the given key exists in the map and has the given value. +func (o *SafeStringMap) Is(key string, val string) (is bool) { + if o == nil { + return + } + + var v string + o.RLock() + if o.items != nil { + v, is = o.items[key] + } + o.RUnlock() + return is && v == val +} + + // Values returns a slice of the values. It will return a nil slice if the map is empty. // Multiple calls to Values will result in the same list of values, but may be in a different order. func (o *SafeStringMap) Values() (vals []string) { diff --git a/pkg/maps/safestrslicemap.go b/pkg/maps/safestrslicemap.go index 06f8c01..c4f8345 100644 --- a/pkg/maps/safestrslicemap.go +++ b/pkg/maps/safestrslicemap.go @@ -91,6 +91,7 @@ func valueSortSafeStringSliceMap(key1, key2 string, val1, val2 string) bool { } + // SetChanged sets the value. // It returns true if something in the map changed. If the key // was already in the map, and you have not provided a sort function, @@ -140,10 +141,48 @@ func (o *SafeStringSliceMap) SetChanged(key string, val string) (changed bool) { return } + // Set sets the given key to the given value. // If the key already exists, the range order will not change. func (o *SafeStringSliceMap) Set(key string, val string) { - o.SetChanged(key, val) + var ok bool + var oldVal string + + if o == nil { + panic("You must initialize the map before using it.") + } + o.Lock() + + if o.items == nil { + o.items = make(map[string]string) + } + + _, ok = o.items[key] + if o.lessF != nil { + if ok { + // delete old key location + loc := sort.Search (len(o.items), func(n int) bool { + return !o.lessF(o.order[n], key, o.items[o.order[n]], oldVal) + }) + o.order = append(o.order[:loc], o.order[loc+1:]...) + } + + loc := sort.Search (len(o.order), func(n int) bool { + return o.lessF(key, o.order[n], val, o.items[o.order[n]]) + }) + // insert + o.order = append(o.order, key) + copy(o.order[loc+1:], o.order[loc:]) + o.order[loc] = key + } else { + if !ok { + o.order = append(o.order, key) + } + } + o.items[key] = val + o.Unlock() + + return } // SetAt sets the given key to the given value, but also inserts it at the index specified. If the index is bigger than @@ -245,6 +284,23 @@ func (o *SafeStringSliceMap) Has(key string) (ok bool) { return } + +// Is returns true if the given key exists in the map and has the given value. +func (o *SafeStringSliceMap) Is(key string, val string) (is bool) { + if o == nil { + return + } + + var v string + o.RLock() + if o.items != nil { + v, is = o.items[key] + } + o.RUnlock() + return is && v == val +} + + // GetAt returns the value based on its position. If the position is out of bounds, an empty value is returned. func (o *SafeStringSliceMap) GetAt(position int) (val string) { if o == nil { diff --git a/pkg/maps/slicemap.go b/pkg/maps/slicemap.go index 9f392e2..b4bbb4a 100644 --- a/pkg/maps/slicemap.go +++ b/pkg/maps/slicemap.go @@ -78,13 +78,11 @@ func keySortSliceMap(key1, key2 string, val1, val2 interface{}) bool { -// SetChanged sets the value. -// It returns true if something in the map changed. If the key -// was already in the map, and you have not provided a sort function, -// the order will not change, but the value will be replaced. If you wanted the -// order to change, you must Delete then call SetChanged. If you have previously set a sort function, -// the order will be updated. -func (o *SliceMap) SetChanged(key string, val interface{}) (changed bool) { + + +// Set sets the given key to the given value. +// If the key already exists, the range order will not change. +func (o *SliceMap) Set(key string, val interface{}) { var ok bool var oldVal interface{} @@ -96,41 +94,33 @@ func (o *SliceMap) SetChanged(key string, val interface{}) (changed bool) { o.items = make(map[string]interface{}) } - if oldVal, ok = o.items[key]; !ok || oldVal != val { - if o.lessF != nil { - if ok { - // delete old key location - loc := sort.Search (len(o.items), func(n int) bool { - return !o.lessF(o.order[n], key, o.items[o.order[n]], oldVal) - }) - o.order = append(o.order[:loc], o.order[loc+1:]...) - } - - loc := sort.Search (len(o.order), func(n int) bool { - return o.lessF(key, o.order[n], val, o.items[o.order[n]]) + _, ok = o.items[key] + if o.lessF != nil { + if ok { + // delete old key location + loc := sort.Search (len(o.items), func(n int) bool { + return !o.lessF(o.order[n], key, o.items[o.order[n]], oldVal) }) - // insert + o.order = append(o.order[:loc], o.order[loc+1:]...) + } + + loc := sort.Search (len(o.order), func(n int) bool { + return o.lessF(key, o.order[n], val, o.items[o.order[n]]) + }) + // insert + o.order = append(o.order, key) + copy(o.order[loc+1:], o.order[loc:]) + o.order[loc] = key + } else { + if !ok { o.order = append(o.order, key) - copy(o.order[loc+1:], o.order[loc:]) - o.order[loc] = key - } else { - if !ok { - o.order = append(o.order, key) - } - } - o.items[key] = val - changed = true - } + } + } + o.items[key] = val return } -// Set sets the given key to the given value. -// If the key already exists, the range order will not change. -func (o *SliceMap) Set(key string, val interface{}) { - o.SetChanged(key, val) -} - // SetAt sets the given key to the given value, but also inserts it at the index specified. If the index is bigger than // the length, it puts it at the end. Negative indexes are backwards from the end. func (o *SliceMap) SetAt(index int, key string, val interface{}) { @@ -258,6 +248,8 @@ func (o *SliceMap) Has(key string) (ok bool) { return } + + // GetAt returns the value based on its position. If the position is out of bounds, an empty value is returned. func (o *SliceMap) GetAt(position int) (val interface{}) { if o == nil { diff --git a/pkg/maps/slicemap_test.go b/pkg/maps/slicemap_test.go index d7f9d46..739bc4b 100644 --- a/pkg/maps/slicemap_test.go +++ b/pkg/maps/slicemap_test.go @@ -59,9 +59,7 @@ func TestSliceMap(t *testing.T) { t.Error("MapI interface test failed.") } - if changed := m.SetChanged("F", 9); !changed { - t.Error("Add non-string value failed.") - } + m.Set("F", 9) if m.Get("F") != 9 { t.Error("Add non-string value failed.") } @@ -73,21 +71,6 @@ func TestSliceMap(t *testing.T) { } -func TestSliceMapChange(t *testing.T) { - m := new (SliceMap) - - m.Set("B", "This") - m.Set("A", "That") - m.Set("C", "Other") - - if changed := m.SetChanged("D", "And another"); !changed { - t.Error("Set did not produce a change flag") - } - - if changed := m.SetChanged("D", "And another"); changed { - t.Error("Set again erroneously produced a change flag") - } -} func ExampleSliceMap_Range() { m := new (SliceMap) diff --git a/pkg/maps/strmap.go b/pkg/maps/strmap.go index 509ffeb..6373b2d 100644 --- a/pkg/maps/strmap.go +++ b/pkg/maps/strmap.go @@ -47,6 +47,7 @@ func (o *StringMap) Clear() { o.items = nil } + // SetChanged sets the key to the value and returns a boolean indicating whether doing this caused // the map to change. It will return true if the key did not first exist, or if the value associated // with the key was different than the new value. @@ -68,6 +69,7 @@ func (o *StringMap) SetChanged(key string, val string) (changed bool) { return } + // Set sets the key to the given value func (o *StringMap) Set(key string, val string) { if o == nil { @@ -123,6 +125,21 @@ func (o *StringMap) Has(key string) (exists bool) { return } + +// Is returns true if the given key exists in the map and has the given value. +func (o *StringMap) Is(key string, val string) (is bool) { + if o == nil { + return + } + + var v string + if o.items != nil { + v, is = o.items[key] + } + return is && v == val +} + + // Values returns a slice of the values. It will return a nil slice if the map is empty. // Multiple calls to Values will result in the same list of values, but may be in a different order. func (o *StringMap) Values() (vals []string) { diff --git a/pkg/maps/strslicemap.go b/pkg/maps/strslicemap.go index 17cffba..db5f281 100644 --- a/pkg/maps/strslicemap.go +++ b/pkg/maps/strslicemap.go @@ -87,6 +87,7 @@ func valueSortStringSliceMap(key1, key2 string, val1, val2 string) bool { } + // SetChanged sets the value. // It returns true if something in the map changed. If the key // was already in the map, and you have not provided a sort function, @@ -134,10 +135,46 @@ func (o *StringSliceMap) SetChanged(key string, val string) (changed bool) { return } + // Set sets the given key to the given value. // If the key already exists, the range order will not change. func (o *StringSliceMap) Set(key string, val string) { - o.SetChanged(key, val) + var ok bool + var oldVal string + + if o == nil { + panic("You must initialize the map before using it.") + } + + if o.items == nil { + o.items = make(map[string]string) + } + + _, ok = o.items[key] + if o.lessF != nil { + if ok { + // delete old key location + loc := sort.Search (len(o.items), func(n int) bool { + return !o.lessF(o.order[n], key, o.items[o.order[n]], oldVal) + }) + o.order = append(o.order[:loc], o.order[loc+1:]...) + } + + loc := sort.Search (len(o.order), func(n int) bool { + return o.lessF(key, o.order[n], val, o.items[o.order[n]]) + }) + // insert + o.order = append(o.order, key) + copy(o.order[loc+1:], o.order[loc:]) + o.order[loc] = key + } else { + if !ok { + o.order = append(o.order, key) + } + } + o.items[key] = val + + return } // SetAt sets the given key to the given value, but also inserts it at the index specified. If the index is bigger than @@ -231,6 +268,21 @@ func (o *StringSliceMap) Has(key string) (ok bool) { return } + +// Is returns true if the given key exists in the map and has the given value. +func (o *StringSliceMap) Is(key string, val string) (is bool) { + if o == nil { + return + } + + var v string + if o.items != nil { + v, is = o.items[key] + } + return is && v == val +} + + // GetAt returns the value based on its position. If the position is out of bounds, an empty value is returned. func (o *StringSliceMap) GetAt(position int) (val string) { if o == nil { diff --git a/templates/map_src/safe_string_interface.json b/templates/map_src/safe_string_interface.json index 584c903..319edff 100644 --- a/templates/map_src/safe_string_interface.json +++ b/templates/map_src/safe_string_interface.json @@ -9,5 +9,6 @@ for these maps, and makes it easier to type. "ValType": "", "keytype": "string", "valtype": "interface{}", - "Safe": "Safe" + "Safe": "Safe", + "valueIsComparable": false } \ No newline at end of file diff --git a/templates/map_src/slice_map.tmpl b/templates/map_src/slice_map.tmpl index 0e1b56c..c462298 100644 --- a/templates/map_src/slice_map.tmpl +++ b/templates/map_src/slice_map.tmpl @@ -123,6 +123,7 @@ func valueSort{{.Safe}}{{.KeyType}}{{.ValType}}SliceMap(key1, key2 {{.keytype}}, } {{end}} +{{if .valueIsComparable}} // SetChanged sets the value. // It returns true if something in the map changed. If the key // was already in the map, and you have not provided a sort function, @@ -175,11 +176,53 @@ func (o *{{.Safe}}{{.KeyType}}{{.ValType}}SliceMap) SetChanged(key {{.keytype}}, return } +{{end}} // Set sets the given key to the given value. // If the key already exists, the range order will not change. func (o *{{.Safe}}{{.KeyType}}{{.ValType}}SliceMap) Set(key {{.keytype}}, val {{.valtype}}) { - o.SetChanged(key, val) + var ok bool + var oldVal {{.valtype}} + + if o == nil { + panic("You must initialize the map before using it.") + } + +{{- if .Safe}} + o.Lock(){{end}} + + if o.items == nil { + o.items = make(map[{{.keytype}}]{{.valtype}}) + } + + _, ok = o.items[key] + if o.lessF != nil { + if ok { + // delete old key location + loc := sort.Search (len(o.items), func(n int) bool { + return !o.lessF(o.order[n], key, o.items[o.order[n]], oldVal) + }) + o.order = append(o.order[:loc], o.order[loc+1:]...) + } + + loc := sort.Search (len(o.order), func(n int) bool { + return o.lessF(key, o.order[n], val, o.items[o.order[n]]) + }) + // insert + o.order = append(o.order, key) + copy(o.order[loc+1:], o.order[loc:]) + o.order[loc] = key + } else { + if !ok { + o.order = append(o.order, key) + } + } + o.items[key] = val + +{{- if .Safe}} + o.Unlock(){{end}} + + return } // SetAt sets the given key to the given value, but also inserts it at the index specified. If the index is bigger than @@ -327,6 +370,25 @@ func (o *{{.Safe}}{{.KeyType}}{{.ValType}}SliceMap) Has(key {{.keytype}}) (ok bo return } +{{if .valueIsComparable}} +// Is returns true if the given key exists in the map and has the given value. +func (o *{{.Safe}}{{.KeyType}}{{.ValType}}SliceMap) Is(key {{.keytype}}, val {{.valtype}}) (is bool) { + if o == nil { + return + } + + var v {{.valtype}} +{{- if .Safe}} + o.RLock(){{end}} + if o.items != nil { + v, is = o.items[key] + } +{{- if .Safe}} + o.RUnlock(){{end}} + return is && v == val +} +{{end}} + // GetAt returns the value based on its position. If the position is out of bounds, an empty value is returned. func (o *{{.Safe}}{{.KeyType}}{{.ValType}}SliceMap) GetAt(position int) (val {{.valtype}}) { if o == nil { diff --git a/templates/map_src/standard_map.tmpl b/templates/map_src/standard_map.tmpl index 81f5d5c..3a871da 100644 --- a/templates/map_src/standard_map.tmpl +++ b/templates/map_src/standard_map.tmpl @@ -20,6 +20,8 @@ valueIsCopier: If true, the value implements a Copy function which returns a val be used to make a copy. keyIsCopier: If true, the key implements a Copy function which returns a value type. Otherwise, a golang = will be used to make a copy. +valueIsComparable: Set this to true if standard golang == will work for comparing values. This will produce a + Is() function that lets you see if a value exists in the map. */ -}} package {{.package}} @@ -82,6 +84,7 @@ func (o *{{.Safe}}{{.KeyType}}{{.ValType}}Map) Clear() { o.Unlock(){{end}} } +{{if .valueIsComparable}} // SetChanged sets the key to the value and returns a boolean indicating whether doing this caused // the map to change. It will return true if the key did not first exist, or if the value associated // with the key was different than the new value. @@ -106,6 +109,7 @@ func (o *{{.Safe}}{{.KeyType}}{{.ValType}}Map) SetChanged(key {{.keytype}}, val o.Unlock(){{end}} return } +{{end}} // Set sets the key to the given value func (o *{{.Safe}}{{.KeyType}}{{.ValType}}Map) Set(key {{.keytype}}, val {{.valtype}}) { @@ -214,6 +218,25 @@ func (o *{{.Safe}}{{.KeyType}}{{.ValType}}Map) Has(key {{.keytype}}) (exists boo return } +{{if .valueIsComparable}} +// Is returns true if the given key exists in the map and has the given value. +func (o *{{.Safe}}{{.KeyType}}{{.ValType}}Map) Is(key {{.keytype}}, val {{.valtype}}) (is bool) { + if o == nil { + return + } + + var v {{.valtype}} +{{- if .Safe}} + o.RLock(){{end}} + if o.items != nil { + v, is = o.items[key] + } +{{- if .Safe}} + o.RUnlock(){{end}} + return is && v == val +} +{{end}} + // Values returns a slice of the values. It will return a nil slice if the map is empty. // Multiple calls to Values will result in the same list of values, but may be in a different order. func (o *{{.Safe}}{{.KeyType}}{{.ValType}}Map) Values() (vals []{{.valtype}}) { diff --git a/templates/map_src/string_interface.json b/templates/map_src/string_interface.json index b87ff6b..5bca92a 100644 --- a/templates/map_src/string_interface.json +++ b/templates/map_src/string_interface.json @@ -9,5 +9,6 @@ for these maps, and makes it easier to type. "ValType": "", "keytype": "string", "valtype": "interface{}", - "Safe": "" + "Safe": "", + "valueIsComparable": false } \ No newline at end of file diff --git a/templates/map_src/string_interface_slice_test.tmpl b/templates/map_src/string_interface_slice_test.tmpl index c8bdd53..77b1a99 100644 --- a/templates/map_src/string_interface_slice_test.tmpl +++ b/templates/map_src/string_interface_slice_test.tmpl @@ -59,9 +59,7 @@ func Test{{.MapType}}SliceMap(t *testing.T) { t.Error("MapI interface test failed.") } - if changed := m.SetChanged("F", 9); !changed { - t.Error("Add non-string value failed.") - } + m.Set("F", 9) if m.Get("F") != 9 { t.Error("Add non-string value failed.") } @@ -73,21 +71,6 @@ func Test{{.MapType}}SliceMap(t *testing.T) { } -func Test{{.MapType}}SliceMapChange(t *testing.T) { - m := new ({{.MapType}}SliceMap) - - m.Set("B", "This") - m.Set("A", "That") - m.Set("C", "Other") - - if changed := m.SetChanged("D", "And another"); !changed { - t.Error("Set did not produce a change flag") - } - - if changed := m.SetChanged("D", "And another"); changed { - t.Error("Set again erroneously produced a change flag") - } -} func Example{{.MapType}}SliceMap_Range() { m := new ({{.MapType}}SliceMap) diff --git a/templates/map_src/string_interface_test.tmpl b/templates/map_src/string_interface_test.tmpl index 549c929..20cab74 100644 --- a/templates/map_src/string_interface_test.tmpl +++ b/templates/map_src/string_interface_test.tmpl @@ -70,12 +70,6 @@ func Test{{.MapType}}Map(t *testing.T) { t.Error("Set after clear failed.") } - m.Clear() - m.SetChanged("E", 15.5) - if m.Get("E") != 15.5 { - t.Error("SetChanged after clear failed.") - } - n := m.Copy() if n.Get("E") != 15.5 { t.Error("Copy failed.") @@ -133,25 +127,6 @@ func Test{{.MapType}}Empty(t *testing.T) { } -func Test{{.MapType}}MapChange(t *testing.T) { - m := New{{.MapType}}Map() - - m.Set("B", "This") - m.Set("A", "That") - m.Set("C", 5) - - if changed := m.SetChanged("D", 6); !changed { - t.Error("Set did not produce a change flag") - } - - if changed := m.SetChanged("D", 6); changed { - t.Error("Set again erroneously produced a change flag") - } - - if changed := m.SetChanged("D", "That"); !changed { - t.Error("Set again did not produce a change flag") - } -} func Test{{.MapType}}MapNotEqual(t *testing.T) { m := New{{.MapType}}Map()