summaryrefslogtreecommitdiff
path: root/vendor/github.com/bytedance/sonic/internal/encoder/alg/mapiter.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/bytedance/sonic/internal/encoder/alg/mapiter.go')
-rw-r--r--vendor/github.com/bytedance/sonic/internal/encoder/alg/mapiter.go206
1 files changed, 206 insertions, 0 deletions
diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/alg/mapiter.go b/vendor/github.com/bytedance/sonic/internal/encoder/alg/mapiter.go
new file mode 100644
index 000000000..5d9956a90
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/internal/encoder/alg/mapiter.go
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2021 ByteDance Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package alg
+
+import (
+ "encoding"
+ "reflect"
+ "strconv"
+ "sync"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/encoder/vars"
+ "github.com/bytedance/sonic/internal/rt"
+)
+
+type _MapPair struct {
+ k string // when the map key is integer, k is pointed to m
+ v unsafe.Pointer
+ m [32]byte
+}
+
+type MapIterator struct {
+ It rt.GoMapIterator // must be the first field
+ kv rt.GoSlice // slice of _MapPair
+ ki int
+}
+
+var (
+ iteratorPool = sync.Pool{}
+ iteratorPair = rt.UnpackType(reflect.TypeOf(_MapPair{}))
+)
+
+func init() {
+ if unsafe.Offsetof(MapIterator{}.It) != 0 {
+ panic("_MapIterator.it is not the first field")
+ }
+}
+
+
+func newIterator() *MapIterator {
+ if v := iteratorPool.Get(); v == nil {
+ return new(MapIterator)
+ } else {
+ return resetIterator(v.(*MapIterator))
+ }
+}
+
+func resetIterator(p *MapIterator) *MapIterator {
+ p.ki = 0
+ p.It = rt.GoMapIterator{}
+ p.kv.Len = 0
+ return p
+}
+
+func (self *MapIterator) at(i int) *_MapPair {
+ return (*_MapPair)(unsafe.Pointer(uintptr(self.kv.Ptr) + uintptr(i) * unsafe.Sizeof(_MapPair{})))
+}
+
+func (self *MapIterator) add() (p *_MapPair) {
+ p = self.at(self.kv.Len)
+ self.kv.Len++
+ return
+}
+
+func (self *MapIterator) data() (p []_MapPair) {
+ *(*rt.GoSlice)(unsafe.Pointer(&p)) = self.kv
+ return
+}
+
+func (self *MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointer) (err error) {
+ p := self.add()
+ p.v = v
+
+ /* check for strings */
+ if tk := t.Kind(); tk != reflect.String {
+ return self.appendGeneric(p, t, tk, k)
+ }
+
+ /* fast path for strings */
+ p.k = *(*string)(k)
+ return nil
+}
+
+func (self *MapIterator) appendGeneric(p *_MapPair, t *rt.GoType, v reflect.Kind, k unsafe.Pointer) error {
+ switch v {
+ case reflect.Int : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int)(k)), 10)) ; return nil
+ case reflect.Int8 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int8)(k)), 10)) ; return nil
+ case reflect.Int16 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int16)(k)), 10)) ; return nil
+ case reflect.Int32 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int32)(k)), 10)) ; return nil
+ case reflect.Int64 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int64)(k)), 10)) ; return nil
+ case reflect.Uint : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint)(k)), 10)) ; return nil
+ case reflect.Uint8 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint8)(k)), 10)) ; return nil
+ case reflect.Uint16 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint16)(k)), 10)) ; return nil
+ case reflect.Uint32 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint32)(k)), 10)) ; return nil
+ case reflect.Uint64 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint64)(k)), 10)) ; return nil
+ case reflect.Uintptr : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uintptr)(k)), 10)) ; return nil
+ case reflect.Interface : return self.appendInterface(p, t, k)
+ case reflect.Struct, reflect.Ptr : return self.appendConcrete(p, t, k)
+ default : panic("unexpected map key type")
+ }
+}
+
+func (self *MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
+ // compiler has already checked that the type implements the encoding.MarshalText interface
+ if !t.Indirect() {
+ k = *(*unsafe.Pointer)(k)
+ }
+ eface := rt.GoEface{Value: k, Type: t}.Pack()
+ out, err := eface.(encoding.TextMarshaler).MarshalText()
+ if err != nil {
+ return err
+ }
+ p.k = rt.Mem2Str(out)
+ return
+}
+
+func (self *MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
+ if len(rt.IfaceType(t).Methods) == 0 {
+ panic("unexpected map key type")
+ } else if p.k, err = asText(k); err == nil {
+ return nil
+ } else {
+ return
+ }
+}
+
+func IteratorStop(p *MapIterator) {
+ iteratorPool.Put(p)
+}
+
+func IteratorNext(p *MapIterator) {
+ i := p.ki
+ t := &p.It
+
+ /* check for unordered iteration */
+ if i < 0 {
+ rt.Mapiternext(t)
+ return
+ }
+
+ /* check for end of iteration */
+ if p.ki >= p.kv.Len {
+ t.K = nil
+ t.V = nil
+ return
+ }
+
+ /* update the key-value pair, and increase the pointer */
+ t.K = unsafe.Pointer(&p.at(p.ki).k)
+ t.V = p.at(p.ki).v
+ p.ki++
+}
+
+func IteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*MapIterator, error) {
+ it := newIterator()
+ rt.Mapiterinit(t, m, &it.It)
+
+ /* check for key-sorting, empty map don't need sorting */
+ if m.Count == 0 || (fv & (1<<BitSortMapKeys)) == 0 {
+ it.ki = -1
+ return it, nil
+ }
+
+ /* pre-allocate space if needed */
+ if m.Count > it.kv.Cap {
+ it.kv = rt.GrowSlice(iteratorPair, it.kv, m.Count)
+ }
+
+ /* dump all the key-value pairs */
+ for ; it.It.K != nil; rt.Mapiternext(&it.It) {
+ if err := it.append(t.Key, it.It.K, it.It.V); err != nil {
+ IteratorStop(it)
+ return nil, err
+ }
+ }
+
+ /* sort the keys, map with only 1 item don't need sorting */
+ if it.ki = 1; m.Count > 1 {
+ radixQsort(it.data(), 0, maxDepth(it.kv.Len))
+ }
+
+ /* load the first pair into iterator */
+ it.It.V = it.at(0).v
+ it.It.K = unsafe.Pointer(&it.at(0).k)
+ return it, nil
+}
+
+func asText(v unsafe.Pointer) (string, error) {
+ text := rt.AssertI2I(rt.UnpackType(vars.EncodingTextMarshalerType), *(*rt.GoIface)(v))
+ r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText()
+ return rt.Mem2Str(r), e
+}