github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/structure/maps/treebidimap/treebidimap.go (about)

     1  // Package treebidimap implements a bidirectional map backed by two red-black tree.
     2  //
     3  // This structure guarantees that the map will be in both ascending key and value order.
     4  //
     5  // 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.
     6  //
     7  // A bidirectional map, or hash bag, is an associative data structure in which the (key,value) pairs form a one-to-one correspondence.
     8  // Thus the binary relation is functional in each direction: value can also act as a key to key.
     9  // 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.
    10  //
    11  // Structure is not thread safe.
    12  //
    13  // Reference: https://en.wikipedia.org/wiki/Bidirectional_map
    14  package treebidimap
    15  
    16  import (
    17  	"encoding/json"
    18  	"fmt"
    19  	"strings"
    20  
    21  	banytostring "github.com/songzhibin97/go-baseutils/base/banytostring"
    22  	"github.com/songzhibin97/go-baseutils/base/bcomparator"
    23  	"github.com/songzhibin97/go-baseutils/structure/maps"
    24  	"github.com/songzhibin97/go-baseutils/structure/trees/redblacktree"
    25  )
    26  
    27  // Assert Map implementation
    28  var _ maps.BidiMap[int, int] = (*Map[int, int])(nil)
    29  
    30  // Map holds the elements in two red-black trees.
    31  type Map[K, V any] struct {
    32  	forwardMap      redblacktree.Tree[K, V]
    33  	inverseMap      redblacktree.Tree[V, K]
    34  	keyComparator   bcomparator.Comparator[K]
    35  	valueComparator bcomparator.Comparator[V]
    36  	zeroK           K
    37  	zeroV           V
    38  }
    39  
    40  // NewWith instantiates a bidirectional map.
    41  func NewWith[K, V any](keyComparator bcomparator.Comparator[K], valueComparator bcomparator.Comparator[V]) *Map[K, V] {
    42  	return &Map[K, V]{
    43  		forwardMap:      *redblacktree.NewWith[K, V](keyComparator),
    44  		inverseMap:      *redblacktree.NewWith[V, K](valueComparator),
    45  		keyComparator:   keyComparator,
    46  		valueComparator: valueComparator,
    47  	}
    48  }
    49  
    50  // NewWithIntComparators instantiates a bidirectional map with the IntComparator for key and value, i.e. keys and values are of type int.
    51  func NewWithIntComparators() *Map[int, int] {
    52  	return NewWith(bcomparator.IntComparator(), bcomparator.IntComparator())
    53  }
    54  
    55  // NewWithStringComparators instantiates a bidirectional map with the StringComparator for key and value, i.e. keys and values are of type string.
    56  func NewWithStringComparators() *Map[string, string] {
    57  	return NewWith(bcomparator.StringComparator(), bcomparator.StringComparator())
    58  }
    59  
    60  // Put inserts element into the map.
    61  func (m *Map[K, V]) Put(key K, value V) {
    62  	if d, ok := m.forwardMap.Get(key); ok {
    63  		m.inverseMap.Remove(d)
    64  	}
    65  	if d, ok := m.inverseMap.Get(value); ok {
    66  		m.forwardMap.Remove(d)
    67  	}
    68  	m.forwardMap.Put(key, value)
    69  	m.inverseMap.Put(value, key)
    70  }
    71  
    72  // Get searches the element in the map by key and returns its value or nil if key is not found in map.
    73  // Second return parameter is true if key was found, otherwise false.
    74  func (m *Map[K, V]) Get(key K) (value V, found bool) {
    75  	if d, ok := m.forwardMap.Get(key); ok {
    76  		return d, true
    77  	}
    78  	return m.zeroV, false
    79  }
    80  
    81  // GetKey searches the element in the map by value and returns its key or nil if value is not found in map.
    82  // Second return parameter is true if value was found, otherwise false.
    83  func (m *Map[K, V]) GetKey(value V) (key K, found bool) {
    84  	if d, ok := m.inverseMap.Get(value); ok {
    85  		return d, true
    86  	}
    87  	return m.zeroK, false
    88  }
    89  
    90  // Remove removes the element from the map by key.
    91  func (m *Map[K, V]) Remove(key K) {
    92  	if d, found := m.forwardMap.Get(key); found {
    93  		m.forwardMap.Remove(key)
    94  		m.inverseMap.Remove(d)
    95  	}
    96  }
    97  
    98  // Empty returns true if map does not contain any elements
    99  func (m *Map[K, V]) Empty() bool {
   100  	return m.Size() == 0
   101  }
   102  
   103  // Size returns number of elements in the map.
   104  func (m *Map[K, V]) Size() int {
   105  	return m.forwardMap.Size()
   106  }
   107  
   108  // Keys returns all keys (ordered).
   109  func (m *Map[K, V]) Keys() []K {
   110  	return m.forwardMap.Keys()
   111  }
   112  
   113  // Values returns all values (ordered).
   114  func (m *Map[K, V]) Values() []V {
   115  	return m.inverseMap.Keys()
   116  }
   117  
   118  // Clear removes all elements from the map.
   119  func (m *Map[K, V]) Clear() {
   120  	m.forwardMap.Clear()
   121  	m.inverseMap.Clear()
   122  }
   123  
   124  // String returns a string representation of container
   125  func (m *Map[K, V]) String() string {
   126  	bf := strings.Builder{}
   127  	bf.WriteString("TreeBidiMap\nmap[")
   128  	it := m.Iterator()
   129  	for it.Next() {
   130  		bf.WriteString(fmt.Sprintf("(%v:%v) ", it.Key(), it.Value()))
   131  	}
   132  	bf.WriteString("]")
   133  	return bf.String()
   134  }
   135  
   136  // UnmarshalJSON @implements json.Unmarshaler
   137  func (m *Map[K, V]) UnmarshalJSON(bytes []byte) error {
   138  	elements := make(map[string]interface{})
   139  	err := json.Unmarshal(bytes, &elements)
   140  	if err == nil {
   141  		m.Clear()
   142  		for key, value := range elements {
   143  			var nk K
   144  			err = m.keyComparator.Unmarshal([]byte(key), &nk)
   145  			if err != nil {
   146  				return err
   147  			}
   148  			var nv V
   149  			err = m.valueComparator.Unmarshal([]byte(banytostring.ToString(value)), &nv)
   150  			if err != nil {
   151  				return err
   152  			}
   153  			m.Put(nk, nv)
   154  		}
   155  	}
   156  	return err
   157  }
   158  
   159  // MarshalJSON @implements json.Marshaler
   160  func (m *Map[K, V]) MarshalJSON() ([]byte, error) {
   161  	elements := make(map[string]string)
   162  	it := m.Iterator()
   163  	for it.Next() {
   164  		k, err := m.keyComparator.Marshal(it.Key())
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  		v, err := m.valueComparator.Marshal(it.Value())
   169  		if err != nil {
   170  			return nil, err
   171  		}
   172  		elements[string(k)] = string(v)
   173  	}
   174  	return json.Marshal(&elements)
   175  }