fcache.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Copyright 2021 ByteDance Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package caching
  17. import (
  18. `strings`
  19. `unsafe`
  20. `github.com/bytedance/sonic/internal/rt`
  21. )
  22. type FieldMap struct {
  23. N uint64
  24. b unsafe.Pointer
  25. m map[string]int
  26. }
  27. type FieldEntry struct {
  28. ID int
  29. Name string
  30. Hash uint64
  31. }
  32. const (
  33. FieldMap_N = int64(unsafe.Offsetof(FieldMap{}.N))
  34. FieldMap_b = int64(unsafe.Offsetof(FieldMap{}.b))
  35. FieldEntrySize = int64(unsafe.Sizeof(FieldEntry{}))
  36. )
  37. func newBucket(n int) unsafe.Pointer {
  38. v := make([]FieldEntry, n)
  39. return (*rt.GoSlice)(unsafe.Pointer(&v)).Ptr
  40. }
  41. func CreateFieldMap(n int) *FieldMap {
  42. return &FieldMap {
  43. N: uint64(n * 2),
  44. b: newBucket(n * 2), // LoadFactor = 0.5
  45. m: make(map[string]int, n * 2),
  46. }
  47. }
  48. func (self *FieldMap) At(p uint64) *FieldEntry {
  49. off := uintptr(p) * uintptr(FieldEntrySize)
  50. return (*FieldEntry)(unsafe.Pointer(uintptr(self.b) + off))
  51. }
  52. // Get searches FieldMap by name. JIT generated assembly does NOT call this
  53. // function, rather it implements its own version directly in assembly. So
  54. // we must ensure this function stays in sync with the JIT generated one.
  55. func (self *FieldMap) Get(name string) int {
  56. h := StrHash(name)
  57. p := h % self.N
  58. s := self.At(p)
  59. /* find the element;
  60. * the hash map is never full, so the loop will always terminate */
  61. for s.Hash != 0 {
  62. if s.Hash == h && s.Name == name {
  63. return s.ID
  64. } else {
  65. p = (p + 1) % self.N
  66. s = self.At(p)
  67. }
  68. }
  69. /* not found */
  70. return -1
  71. }
  72. func (self *FieldMap) Set(name string, i int) {
  73. h := StrHash(name)
  74. p := h % self.N
  75. s := self.At(p)
  76. /* searching for an empty slot;
  77. * the hash map is never full, so the loop will always terminate */
  78. for s.Hash != 0 {
  79. p = (p + 1) % self.N
  80. s = self.At(p)
  81. }
  82. /* set the value */
  83. s.ID = i
  84. s.Hash = h
  85. s.Name = name
  86. /* add the case-insensitive version, prefer the one with smaller field ID */
  87. key := strings.ToLower(name)
  88. if v, ok := self.m[key]; !ok || i < v {
  89. self.m[key] = i
  90. }
  91. }
  92. func (self *FieldMap) GetCaseInsensitive(name string) int {
  93. if i, ok := self.m[strings.ToLower(name)]; ok {
  94. return i
  95. } else {
  96. return -1
  97. }
  98. }