github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/map.go (about)

     1  package goja
     2  
     3  import (
     4  	"hash/maphash"
     5  )
     6  
     7  type mapEntry struct {
     8  	key, value Value
     9  
    10  	iterPrev, iterNext *mapEntry
    11  	hNext              *mapEntry
    12  }
    13  
    14  type orderedMap struct {
    15  	hash                *maphash.Hash
    16  	hashTable           map[uint64]*mapEntry
    17  	iterFirst, iterLast *mapEntry
    18  	size                int
    19  }
    20  
    21  type orderedMapIter struct {
    22  	m   *orderedMap
    23  	cur *mapEntry
    24  }
    25  
    26  func (m *orderedMap) lookup(key Value) (h uint64, entry, hPrev *mapEntry) {
    27  	if key == _negativeZero {
    28  		key = intToValue(0)
    29  	}
    30  	h = key.hash(m.hash)
    31  	for entry = m.hashTable[h]; entry != nil && !entry.key.SameAs(key); hPrev, entry = entry, entry.hNext {
    32  	}
    33  	return
    34  }
    35  
    36  func (m *orderedMap) set(key, value Value) {
    37  	h, entry, hPrev := m.lookup(key)
    38  	if entry != nil {
    39  		entry.value = value
    40  	} else {
    41  		if key == _negativeZero {
    42  			key = intToValue(0)
    43  		}
    44  		entry = &mapEntry{key: key, value: value}
    45  		if hPrev == nil {
    46  			m.hashTable[h] = entry
    47  		} else {
    48  			hPrev.hNext = entry
    49  		}
    50  		if m.iterLast != nil {
    51  			entry.iterPrev = m.iterLast
    52  			m.iterLast.iterNext = entry
    53  		} else {
    54  			m.iterFirst = entry
    55  		}
    56  		m.iterLast = entry
    57  		m.size++
    58  	}
    59  }
    60  
    61  func (m *orderedMap) get(key Value) Value {
    62  	_, entry, _ := m.lookup(key)
    63  	if entry != nil {
    64  		return entry.value
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  func (m *orderedMap) remove(key Value) bool {
    71  	h, entry, hPrev := m.lookup(key)
    72  	if entry != nil {
    73  		entry.key = nil
    74  		entry.value = nil
    75  
    76  		// remove from the doubly-linked list
    77  		if entry.iterPrev != nil {
    78  			entry.iterPrev.iterNext = entry.iterNext
    79  		} else {
    80  			m.iterFirst = entry.iterNext
    81  		}
    82  		if entry.iterNext != nil {
    83  			entry.iterNext.iterPrev = entry.iterPrev
    84  		} else {
    85  			m.iterLast = entry.iterPrev
    86  		}
    87  
    88  		// remove from the hashTable
    89  		if hPrev == nil {
    90  			if entry.hNext == nil {
    91  				delete(m.hashTable, h)
    92  			} else {
    93  				m.hashTable[h] = entry.hNext
    94  			}
    95  		} else {
    96  			hPrev.hNext = entry.hNext
    97  		}
    98  
    99  		m.size--
   100  		return true
   101  	}
   102  
   103  	return false
   104  }
   105  
   106  func (m *orderedMap) has(key Value) bool {
   107  	_, entry, _ := m.lookup(key)
   108  	return entry != nil
   109  }
   110  
   111  func (iter *orderedMapIter) next() *mapEntry {
   112  	if iter.m == nil {
   113  		// closed iterator
   114  		return nil
   115  	}
   116  
   117  	cur := iter.cur
   118  	// if the current item was deleted, track back to find the latest that wasn't
   119  	for cur != nil && cur.key == nil {
   120  		cur = cur.iterPrev
   121  	}
   122  
   123  	if cur != nil {
   124  		cur = cur.iterNext
   125  	} else {
   126  		cur = iter.m.iterFirst
   127  	}
   128  
   129  	if cur == nil {
   130  		iter.close()
   131  	} else {
   132  		iter.cur = cur
   133  	}
   134  
   135  	return cur
   136  }
   137  
   138  func (iter *orderedMapIter) close() {
   139  	iter.m = nil
   140  	iter.cur = nil
   141  }
   142  
   143  func newOrderedMap(h *maphash.Hash) *orderedMap {
   144  	return &orderedMap{
   145  		hash:      h,
   146  		hashTable: make(map[uint64]*mapEntry),
   147  	}
   148  }
   149  
   150  func (m *orderedMap) newIter() *orderedMapIter {
   151  	iter := &orderedMapIter{
   152  		m: m,
   153  	}
   154  	return iter
   155  }
   156  
   157  func (m *orderedMap) clear() {
   158  	for item := m.iterFirst; item != nil; item = item.iterNext {
   159  		item.key = nil
   160  		item.value = nil
   161  		if item.iterPrev != nil {
   162  			item.iterPrev.iterNext = nil
   163  		}
   164  	}
   165  	m.iterFirst = nil
   166  	m.iterLast = nil
   167  	m.hashTable = make(map[uint64]*mapEntry)
   168  	m.size = 0
   169  }