mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 02:22:26 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			199 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|  * 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 encoder
 | |
| 
 | |
| import (
 | |
| 	"encoding"
 | |
| 	"reflect"
 | |
| 	"sync"
 | |
| 	"unsafe"
 | |
| 
 | |
| 	"github.com/bytedance/sonic/internal/native"
 | |
| 	"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(p.m[:native.I64toa(&p.m[0], int64(*(*int)(k)))])      ; return nil
 | |
|         case reflect.Int8      : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int8)(k)))])     ; return nil
 | |
|         case reflect.Int16     : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int16)(k)))])    ; return nil
 | |
|         case reflect.Int32     : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int32)(k)))])    ; return nil
 | |
|         case reflect.Int64     : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], *(*int64)(k))])           ; return nil
 | |
|         case reflect.Uint      : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint)(k)))])    ; return nil
 | |
|         case reflect.Uint8     : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint8)(k)))])   ; return nil
 | |
|         case reflect.Uint16    : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint16)(k)))])  ; return nil
 | |
|         case reflect.Uint32    : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint32)(k)))])  ; return nil
 | |
|         case reflect.Uint64    : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], *(*uint64)(k))])          ; return nil
 | |
|         case reflect.Uintptr   : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uintptr)(k)))]) ; 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 {
 | |
|         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()
 | |
|     mapiterinit(t, m, &it.it)
 | |
| 
 | |
|     /* check for key-sorting, empty map don't need sorting */
 | |
|     if m.Count == 0 || (fv & uint64(SortMapKeys)) == 0 {
 | |
|         it.ki = -1
 | |
|         return it, nil
 | |
|     }
 | |
| 
 | |
|     /* pre-allocate space if needed */
 | |
|     if m.Count > it.kv.Cap {
 | |
|         it.kv = growslice(iteratorPair, it.kv, m.Count)
 | |
|     }
 | |
| 
 | |
|     /* dump all the key-value pairs */
 | |
|     for ; it.it.K != nil; 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
 | |
| }
 |