hashmap_get.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package hashmap
  2. import (
  3. "bytes"
  4. "reflect"
  5. "unsafe"
  6. "github.com/dchest/siphash"
  7. )
  8. // Get retrieves an element from the map under given hash key.
  9. // Using interface{} adds a performance penalty.
  10. // Please consider using GetUintKey or GetStringKey instead.
  11. func (m *HashMap) Get(key interface{}) (value interface{}, ok bool) {
  12. h := getKeyHash(key)
  13. data, element := m.indexElement(h)
  14. if data == nil {
  15. return nil, false
  16. }
  17. // inline HashMap.searchItem()
  18. for element != nil {
  19. if element.keyHash == h {
  20. switch key.(type) {
  21. case []byte:
  22. if bytes.Compare(element.key.([]byte), key.([]byte)) == 0 {
  23. return element.Value(), true
  24. }
  25. default:
  26. if element.key == key {
  27. return element.Value(), true
  28. }
  29. }
  30. }
  31. if element.keyHash > h {
  32. return nil, false
  33. }
  34. element = element.Next()
  35. }
  36. return nil, false
  37. }
  38. // GetUintKey retrieves an element from the map under given integer key.
  39. func (m *HashMap) GetUintKey(key uintptr) (value interface{}, ok bool) {
  40. // inline getUintptrHash()
  41. bh := reflect.SliceHeader{
  42. Data: uintptr(unsafe.Pointer(&key)),
  43. Len: intSizeBytes,
  44. Cap: intSizeBytes,
  45. }
  46. buf := *(*[]byte)(unsafe.Pointer(&bh))
  47. h := uintptr(siphash.Hash(sipHashKey1, sipHashKey2, buf))
  48. data, element := m.indexElement(h)
  49. if data == nil {
  50. return nil, false
  51. }
  52. // inline HashMap.searchItem()
  53. for element != nil {
  54. if element.keyHash == h && element.key == key {
  55. return element.Value(), true
  56. }
  57. if element.keyHash > h {
  58. return nil, false
  59. }
  60. element = element.Next()
  61. }
  62. return nil, false
  63. }
  64. // GetStringKey retrieves an element from the map under given string key.
  65. func (m *HashMap) GetStringKey(key string) (value interface{}, ok bool) {
  66. // inline getStringHash()
  67. sh := (*reflect.StringHeader)(unsafe.Pointer(&key))
  68. bh := reflect.SliceHeader{
  69. Data: sh.Data,
  70. Len: sh.Len,
  71. Cap: sh.Len,
  72. }
  73. buf := *(*[]byte)(unsafe.Pointer(&bh))
  74. h := uintptr(siphash.Hash(sipHashKey1, sipHashKey2, buf))
  75. data, element := m.indexElement(h)
  76. if data == nil {
  77. return nil, false
  78. }
  79. // inline HashMap.searchItem()
  80. for element != nil {
  81. if element.keyHash == h && element.key == key {
  82. return element.Value(), true
  83. }
  84. if element.keyHash > h {
  85. return nil, false
  86. }
  87. element = element.Next()
  88. }
  89. return nil, false
  90. }
  91. // GetHashedKey retrieves an element from the map under given hashed key.
  92. func (m *HashMap) GetHashedKey(hashedKey uintptr) (value interface{}, ok bool) {
  93. data, element := m.indexElement(hashedKey)
  94. if data == nil {
  95. return nil, false
  96. }
  97. // inline HashMap.searchItem()
  98. for element != nil {
  99. if element.keyHash == hashedKey {
  100. return element.Value(), true
  101. }
  102. if element.keyHash > hashedKey {
  103. return nil, false
  104. }
  105. element = element.Next()
  106. }
  107. return nil, false
  108. }
  109. // GetOrInsert returns the existing value for the key if present.
  110. // Otherwise, it stores and returns the given value.
  111. // The loaded result is true if the value was loaded, false if stored.
  112. func (m *HashMap) GetOrInsert(key interface{}, value interface{}) (actual interface{}, loaded bool) {
  113. h := getKeyHash(key)
  114. var newelement *ListElement
  115. for {
  116. data, element := m.indexElement(h)
  117. if data == nil {
  118. m.allocate(DefaultSize)
  119. continue
  120. }
  121. for element != nil {
  122. if element.keyHash == h {
  123. switch key.(type) {
  124. case []byte:
  125. if bytes.Compare(element.key.([]byte), key.([]byte)) == 0 {
  126. return element.Value(), true
  127. }
  128. default:
  129. if element.key == key {
  130. actual = element.Value()
  131. return actual, true
  132. }
  133. }
  134. }
  135. if element.keyHash > h {
  136. break
  137. }
  138. element = element.Next()
  139. }
  140. if newelement == nil { // allocate only once
  141. newelement = &ListElement{
  142. key: key,
  143. keyHash: h,
  144. value: unsafe.Pointer(&value),
  145. }
  146. }
  147. if m.insertListElement(newelement, false) {
  148. return value, false
  149. }
  150. }
  151. }