gitee.com/quant1x/gox@v1.21.2/util/treebidimap/treebidimap.go (about) 1 // Copyright (c) 2015, Emir Pasic. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package treebidimap implements a bidirectional map backed by two red-black tree. 6 // 7 // This structure guarantees that the map will be in both ascending key and value order. 8 // 9 // Other than key and value ordering, the goal with this structure is to avoid duplication of elements, which can be significant if contained elements are large. 10 // 11 // A bidirectional map, or hash bag, is an associative data structure in which the (key,value) pairs form a one-to-one correspondence. 12 // Thus the binary relation is functional in each direction: value can also act as a key to key. 13 // A pair (a,b) thus provides a unique coupling between 'a' and 'b' so that 'b' can be found when 'a' is used as a key and 'a' can be found when 'b' is used as a key. 14 // 15 // Structure is not thread safe. 16 // 17 // Reference: https://en.wikipedia.org/wiki/Bidirectional_map 18 package treebidimap 19 20 import ( 21 "fmt" 22 "gitee.com/quant1x/gox/util/internal" 23 "gitee.com/quant1x/gox/util/redblacktree" 24 "strings" 25 ) 26 27 func assertMapImplementation() { 28 var _ internal.BidiMap = (*Map)(nil) 29 } 30 31 // Map holds the elements in two red-black trees. 32 type Map struct { 33 forwardMap redblacktree.Tree 34 inverseMap redblacktree.Tree 35 keyComparator internal.Comparator 36 valueComparator internal.Comparator 37 } 38 39 type data struct { 40 key interface{} 41 value interface{} 42 } 43 44 // NewWith instantiates a bidirectional map. 45 func NewWith(keyComparator internal.Comparator, valueComparator internal.Comparator) *Map { 46 return &Map{ 47 forwardMap: *redblacktree.NewWith(keyComparator), 48 inverseMap: *redblacktree.NewWith(valueComparator), 49 keyComparator: keyComparator, 50 valueComparator: valueComparator, 51 } 52 } 53 54 // NewWithIntComparators instantiates a bidirectional map with the IntComparator for key and value, i.e. keys and values are of type int. 55 func NewWithIntComparators() *Map { 56 return NewWith(internal.IntComparator, internal.IntComparator) 57 } 58 59 // NewWithStringComparators instantiates a bidirectional map with the StringComparator for key and value, i.e. keys and values are of type string. 60 func NewWithStringComparators() *Map { 61 return NewWith(internal.StringComparator, internal.StringComparator) 62 } 63 64 // Put inserts element into the map. 65 func (m *Map) Put(key interface{}, value interface{}) { 66 if d, ok := m.forwardMap.Get(key); ok { 67 m.inverseMap.Remove(d.(*data).value) 68 } 69 if d, ok := m.inverseMap.Get(value); ok { 70 m.forwardMap.Remove(d.(*data).key) 71 } 72 d := &data{key: key, value: value} 73 m.forwardMap.Put(key, d) 74 m.inverseMap.Put(value, d) 75 } 76 77 // Get searches the element in the map by key and returns its value or nil if key is not found in map. 78 // Second return parameter is true if key was found, otherwise false. 79 func (m *Map) Get(key interface{}) (value interface{}, found bool) { 80 if d, ok := m.forwardMap.Get(key); ok { 81 return d.(*data).value, true 82 } 83 return nil, false 84 } 85 86 // GetKey searches the element in the map by value and returns its key or nil if value is not found in map. 87 // Second return parameter is true if value was found, otherwise false. 88 func (m *Map) GetKey(value interface{}) (key interface{}, found bool) { 89 if d, ok := m.inverseMap.Get(value); ok { 90 return d.(*data).key, true 91 } 92 return nil, false 93 } 94 95 // Remove removes the element from the map by key. 96 func (m *Map) Remove(key interface{}) { 97 if d, found := m.forwardMap.Get(key); found { 98 m.forwardMap.Remove(key) 99 m.inverseMap.Remove(d.(*data).value) 100 } 101 } 102 103 // Empty returns true if map does not contain any elements 104 func (m *Map) Empty() bool { 105 return m.Size() == 0 106 } 107 108 // Size returns number of elements in the map. 109 func (m *Map) Size() int { 110 return m.forwardMap.Size() 111 } 112 113 // Keys returns all keys (ordered). 114 func (m *Map) Keys() []interface{} { 115 return m.forwardMap.Keys() 116 } 117 118 // Values returns all values (ordered). 119 func (m *Map) Values() []interface{} { 120 return m.inverseMap.Keys() 121 } 122 123 // Clear removes all elements from the map. 124 func (m *Map) Clear() { 125 m.forwardMap.Clear() 126 m.inverseMap.Clear() 127 } 128 129 // String returns a string representation of container 130 func (m *Map) String() string { 131 str := "TreeBidiMap\nmap[" 132 it := m.Iterator() 133 for it.Next() { 134 str += fmt.Sprintf("%v:%v ", it.Key(), it.Value()) 135 } 136 return strings.TrimRight(str, " ") + "]" 137 }