From fd76d6d3a9c99b90b037ec2220d20331b1e91f44 Mon Sep 17 00:00:00 2001 From: Maksim Litvinov Date: Fri, 21 Jun 2024 01:11:55 +0300 Subject: [PATCH] remove Element interface as it complicates nil checks --- element.go | 21 +++++++-------------- extra.go | 2 +- jsonmap.go | 21 ++++++++++++--------- simplemap/element.go | 30 ++++++++++++++---------------- slow.go | 2 +- test/interface_test.go | 16 ++++++++++++---- test/jsonmap_test.go | 34 ++++++++++++++++++++++++++++++++-- 7 files changed, 79 insertions(+), 47 deletions(-) diff --git a/element.go b/element.go index 99d693f..e2d8284 100644 --- a/element.go +++ b/element.go @@ -3,36 +3,29 @@ package jsonmap type Key = string type Value = any -type Element interface { - Key() Key - Value() Value - Next() Element - Prev() Element -} - -// element is an element of a map, to be used in iteration. +// Element of a map, to be used in iteration. // // for elem := m.First(); elem != nil; elem = elem.Next() { // fmt.Println(elem.Key(), elem.Value()) // } -type element struct { +type Element struct { key Key value Value - next, prev *element + next, prev *Element } // Key returns the key of the element. // // key := elem.Key() -func (e *element) Key() Key { +func (e *Element) Key() Key { return e.key } // Value returns the value of the element. // // value := elem.Value() -func (e *element) Value() Value { +func (e *Element) Value() Value { return e.value } @@ -43,7 +36,7 @@ func (e *element) Value() Value { // for elem := m.First(); elem != nil; elem = elem.Next() { // fmt.Println(elem.Key(), elem.Value()) // } -func (e *element) Next() Element { +func (e *Element) Next() *Element { return e.next } @@ -54,6 +47,6 @@ func (e *element) Next() Element { // for elem := m.Last(); elem != nil; elem = elem.Prev() { // fmt.Println(elem.Key(), elem.Value()) // } -func (e *element) Prev() Element { +func (e *Element) Prev() *Element { return e.prev } diff --git a/extra.go b/extra.go index 0ee40da..ff7d0e3 100644 --- a/extra.go +++ b/extra.go @@ -9,7 +9,7 @@ func (m *Map) SetFront(key Key, value Value) { elem.value = value return } - elem := &element{ + elem := &Element{ key: key, value: value, } diff --git a/jsonmap.go b/jsonmap.go index 0acd203..d05d245 100644 --- a/jsonmap.go +++ b/jsonmap.go @@ -7,8 +7,8 @@ package jsonmap // serializing to JSON, and has additional methods to iterate from any element. // Similar to native map, user has to take care of concurrent access and nil map value. type Map struct { - elements map[Key]*element - first, last *element + elements map[Key]*Element + first, last *Element } // New returns a new map. O(1) time. @@ -16,7 +16,7 @@ type Map struct { // m := jsonmap.New() func New() *Map { return &Map{ - elements: make(map[Key]*element), + elements: make(map[Key]*Element), } } @@ -24,7 +24,7 @@ func New() *Map { // // m.Clear() func (m *Map) Clear() { - m.elements = make(map[Key]*element) + m.elements = make(map[Key]*Element) m.first = nil m.last = nil } @@ -72,7 +72,7 @@ func (m *Map) Set(key Key, value Value) { elem.value = value return } - elem := &element{ + elem := &Element{ key: key, value: value, } @@ -136,20 +136,23 @@ func (m *Map) Pop() (key Key, value Value, ok bool) { // First returns the first element in the map, for iteration. // Returns nil if the map is empty. // O(1) time. -func (m *Map) First() Element { +func (m *Map) First() *Element { return m.first } // Last returns the last element in the map, for iteration for backwards iteration. // Returns nil if the map is empty. // O(1) time. -func (m *Map) Last() Element { +func (m *Map) Last() *Element { return m.last } // GetElement returns the element for the key, for iteration from a needle. // Returns nil if the key is not in the map. // O(1) time. -func (m *Map) GetElement(key Key) Element { - return m.elements[key] +func (m *Map) GetElement(key Key) *Element { + if el, ok := m.elements[key]; ok { + return el + } + return nil } diff --git a/simplemap/element.go b/simplemap/element.go index 762ed51..b91d59c 100644 --- a/simplemap/element.go +++ b/simplemap/element.go @@ -1,13 +1,11 @@ package jsonmap -import "github.com/metalim/jsonmap" - -// element is an element of a map, to be used in iteration. +// Element of a map, to be used in iteration. // // for elem := m.First(); elem != nil; elem = elem.Next() { // fmt.Println(elem.Key(), elem.Value()) // } -type element struct { +type Element struct { m *Map index int } @@ -15,14 +13,14 @@ type element struct { // Key returns the key of the element. // // key := elem.Key() -func (e *element) Key() Key { +func (e *Element) Key() Key { return e.m.keys[e.index] } // Value returns the value of the element. // // value := elem.Value() -func (e *element) Value() Value { +func (e *Element) Value() Value { return e.m.values[e.Key()] } @@ -33,11 +31,11 @@ func (e *element) Value() Value { // for elem := m.First(); elem != nil; elem = elem.Next() { // fmt.Println(elem.Key(), elem.Value()) // } -func (e *element) Next() jsonmap.Element { +func (e *Element) Next() *Element { if e.index == len(e.m.keys)-1 { return nil } - return &element{ + return &Element{ m: e.m, index: e.index + 1, } @@ -50,11 +48,11 @@ func (e *element) Next() jsonmap.Element { // for elem := m.Last(); elem != nil; elem = elem.Prev() { // fmt.Println(elem.Key(), elem.Value()) // } -func (e *element) Prev() jsonmap.Element { +func (e *Element) Prev() *Element { if e.index == 0 { return nil } - return &element{ + return &Element{ m: e.m, index: e.index - 1, } @@ -67,8 +65,8 @@ func (e *element) Prev() jsonmap.Element { // for elem := m.First(); elem != nil; elem = elem.Next() { // fmt.Println(elem.Key(), elem.Value()) // } -func (m *Map) First() jsonmap.Element { - return &element{ +func (m *Map) First() *Element { + return &Element{ m: m, index: 0, } @@ -81,8 +79,8 @@ func (m *Map) First() jsonmap.Element { // for elem := m.Last(); elem != nil; elem = elem.Prev() { // fmt.Println(elem.Key(), elem.Value()) // } -func (m *Map) Last() jsonmap.Element { - return &element{ +func (m *Map) Last() *Element { + return &Element{ m: m, index: len(m.keys) - 1, } @@ -91,11 +89,11 @@ func (m *Map) Last() jsonmap.Element { // GetElement returns the element for the key, for iteration from a needle. // Returns nil if the key is not in the map. // O(n) for existing keys, because it uses KeyIndex(). -func (m *Map) GetElement(key Key) jsonmap.Element { +func (m *Map) GetElement(key Key) *Element { if _, ok := m.values[key]; !ok { return nil } - return &element{ + return &Element{ m: m, index: m.KeyIndex(key), } diff --git a/slow.go b/slow.go index aeba579..0187815 100644 --- a/slow.go +++ b/slow.go @@ -52,7 +52,7 @@ func (m *Map) SortKeys(less func(a, b Key) bool) { if m.Len() < 2 { return } - elements := make([]*element, 0, len(m.elements)) + elements := make([]*Element, 0, len(m.elements)) for elem := m.first; elem != nil; elem = elem.next { elements = append(elements, elem) } diff --git a/test/interface_test.go b/test/interface_test.go index b1a8300..faeb514 100644 --- a/test/interface_test.go +++ b/test/interface_test.go @@ -27,11 +27,19 @@ type IMap interface { String() string Keys() []Key Values() []Value - - First() jsonmap.Element - Last() jsonmap.Element - GetElement(key Key) jsonmap.Element +} +type IJSONMap interface { + First() *jsonmap.Element + Last() *jsonmap.Element + GetElement(key Key) *jsonmap.Element +} +type ISimpleMap interface { + First() *simplemap.Element + Last() *simplemap.Element + GetElement(key Key) *simplemap.Element } var _ IMap = (*jsonmap.Map)(nil) var _ IMap = (*simplemap.Map)(nil) +var _ IJSONMap = (*jsonmap.Map)(nil) +var _ ISimpleMap = (*simplemap.Map)(nil) diff --git a/test/jsonmap_test.go b/test/jsonmap_test.go index 3610e11..0a1a96d 100644 --- a/test/jsonmap_test.go +++ b/test/jsonmap_test.go @@ -18,8 +18,38 @@ func TestJSONMap(t *testing.T) { func testJSONMapOnce(t *testing.T, i int) { m := jsonmap.New() + // no elements + assert.Equal(t, m.Len(), 0) + assert.Equal(t, len(m.Keys()), 0) + assert.Equal(t, m.String(), "map[]") + assert.Nil(t, m.First()) + assert.Nil(t, m.Last()) + + // 1 element m.Set("a", 1) + assert.Equal(t, m.Len(), 1) + assert.Equal(t, len(m.Keys()), 1) + assert.Equal(t, m.Keys()[0], "a") + assert.Equal(t, m.First().Key(), m.Keys()[0]) + assert.Equal(t, m.First().Key(), m.Last().Key()) + assert.Nil(t, m.First().Next()) + assert.Nil(t, m.Last().Prev()) + assert.Equal(t, m.String(), "map[a:1]") + + // 2 elements m.Set("d", "2") + assert.Equal(t, m.Len(), 2) + assert.Equal(t, len(m.Keys()), 2) + assert.Equal(t, m.Keys()[0], "a") + assert.Equal(t, m.Keys()[1], "d") + assert.Equal(t, m.First().Key(), m.Keys()[0]) + assert.Equal(t, m.Last().Key(), m.Keys()[1]) + assert.Nil(t, m.First().Prev()) + assert.Equal(t, m.First().Next(), m.Last()) + assert.Equal(t, m.Last().Prev(), m.First()) + assert.Nil(t, m.Last().Next()) + assert.Equal(t, m.String(), "map[a:1 d:2]") + m.Set("c", 3) m.Set("e", 5) m.Set("b", 6) @@ -61,8 +91,8 @@ func testJSONMapOnce(t *testing.T, i int) { assert.Equal(t, v.(int), 7) v, ok = m.Get("c") assert.True(t, !ok) - assert.Equal(t, v, nil) + assert.Nil(t, v) v, ok = m.Get("e") assert.True(t, !ok) - assert.Equal(t, v, nil) + assert.Nil(t, v) }