github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/maps/linkedhashmap/linkedhashmap.go (about) 1 // Package linkedhashmap is a map that preserves insertion-order. 2 // 3 // It is backed by a hash table to store values and doubly-linked list to store ordering. 4 // 5 // Structure is not thread safe. 6 // 7 // Reference: http://en.wikipedia.org/wiki/Associative_array 8 package linkedhashmap 9 10 import ( 11 "bytes" 12 "encoding/json" 13 "fmt" 14 "strings" 15 16 "github.com/songzhibin97/go-baseutils/base/bcomparator" 17 "github.com/songzhibin97/go-baseutils/structure/lists/doublylinkedlist" 18 "github.com/songzhibin97/go-baseutils/structure/maps" 19 ) 20 21 // Assert Map implementation 22 var _ maps.Map[int, any] = (*Map[int, any])(nil) 23 24 // Map holds the elements in a regular hash table, and uses doubly-linked list to store key ordering. 25 type Map[K comparable, V any] struct { 26 table map[K]V 27 ordering *doublylinkedlist.List[K] 28 zeroK K 29 zeroV V 30 } 31 32 // New instantiates a linked-hash-map. 33 func New[K comparable, V any]() *Map[K, V] { 34 return &Map[K, V]{ 35 table: make(map[K]V), 36 ordering: doublylinkedlist.New[K](), 37 } 38 } 39 40 // Put inserts key-value pair into the map. 41 // Key should adhere to the comparator's type assertion, otherwise method panics. 42 func (m *Map[K, V]) Put(key K, value V) { 43 if _, contains := m.table[key]; !contains { 44 m.ordering.Append(key) 45 } 46 m.table[key] = value 47 } 48 49 // Get searches the element in the map by key and returns its value or nil if key is not found in tree. 50 // Second return parameter is true if key was found, otherwise false. 51 // Key should adhere to the comparator's type assertion, otherwise method panics. 52 func (m *Map[K, V]) Get(key K) (value V, found bool) { 53 value, found = m.table[key] 54 return 55 } 56 57 // Remove removes the element from the map by key. 58 // Key should adhere to the comparator's type assertion, otherwise method panics. 59 func (m *Map[K, V]) Remove(key K) { 60 if _, contains := m.table[key]; contains { 61 delete(m.table, key) 62 index := m.ordering.IndexOf(key) 63 m.ordering.Remove(index) 64 } 65 } 66 67 // Empty returns true if map does not contain any elements 68 func (m *Map[K, V]) Empty() bool { 69 return m.Size() == 0 70 } 71 72 // Size returns number of elements in the map. 73 func (m *Map[K, V]) Size() int { 74 return m.ordering.Size() 75 } 76 77 // Keys returns all keys in-order 78 func (m *Map[K, V]) Keys() []K { 79 return m.ordering.Values() 80 } 81 82 // Values returns all values in-order based on the key. 83 func (m *Map[K, V]) Values() []V { 84 values := make([]V, m.Size()) 85 count := 0 86 it := m.Iterator() 87 for it.Next() { 88 values[count] = it.Value() 89 count++ 90 } 91 return values 92 } 93 94 // Clear removes all elements from the map. 95 func (m *Map[K, V]) Clear() { 96 m.table = make(map[K]V) 97 m.ordering.Clear() 98 } 99 100 // String returns a string representation of container 101 func (m *Map[K, V]) String() string { 102 bf := strings.Builder{} 103 bf.WriteString("LinkedHashMap\nmap[") 104 it := m.Iterator() 105 for it.Next() { 106 bf.WriteString(fmt.Sprintf("(%v:%v) ", it.Key(), it.Value())) 107 } 108 bf.WriteString("]") 109 return bf.String() 110 } 111 112 // UnmarshalJSON @implements json.Unmarshaler 113 func (m *Map[K, V]) UnmarshalJSON(data []byte) error { 114 elements := make(map[K]V) 115 err := json.Unmarshal(data, &elements) 116 if err != nil { 117 return err 118 } 119 120 index := make(map[K]int) 121 var keys []K 122 for key := range elements { 123 keys = append(keys, key) 124 esc, _ := json.Marshal(key) 125 index[key] = bytes.Index(data, esc) 126 } 127 128 byIndex := func(a, b K) int { 129 key1 := a 130 key2 := b 131 index1 := index[key1] 132 index2 := index[key2] 133 return index1 - index2 134 } 135 136 bcomparator.Sort(keys, byIndex) 137 138 m.Clear() 139 140 for _, key := range keys { 141 m.Put(key, elements[key]) 142 } 143 144 return nil 145 } 146 147 // MarshalJSON @implements json.Marshaler 148 func (m *Map[K, V]) MarshalJSON() ([]byte, error) { 149 var b []byte 150 buf := bytes.NewBuffer(b) 151 152 buf.WriteRune('{') 153 154 it := m.Iterator() 155 lastIndex := m.Size() - 1 156 index := 0 157 158 for it.Next() { 159 km, err := json.Marshal(it.Key()) 160 if err != nil { 161 return nil, err 162 } 163 buf.Write(km) 164 165 buf.WriteRune(':') 166 167 vm, err := json.Marshal(it.Value()) 168 if err != nil { 169 return nil, err 170 } 171 buf.Write(vm) 172 173 if index != lastIndex { 174 buf.WriteRune(',') 175 } 176 177 index++ 178 } 179 180 buf.WriteRune('}') 181 182 return buf.Bytes(), nil 183 }