From 51b175307a14cf90cfb3cb838172fe3056d5423c Mon Sep 17 00:00:00 2001 From: DEV Date: Wed, 31 Jan 2024 01:58:06 +0100 Subject: [PATCH] redefiniendo el builder --- app/main.go | 4 + app/tests/benchmarks_test.go | 19 ++++ packs/js/cache.go | 6 +- packs/js/type_map_entry.go | 41 ++++++++ packs/js/type_map_packer.go | 180 +++++++++++++++++++++++++++++++++++ packs/js/type_packer.go | 6 ++ 6 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 packs/js/type_map_entry.go create mode 100644 packs/js/type_map_packer.go diff --git a/app/main.go b/app/main.go index 4b42efd..1a0c668 100644 --- a/app/main.go +++ b/app/main.go @@ -41,5 +41,9 @@ func main() { st.Reset() + a := map[int]string {1:"344343",3:"4343434",5:"frtrtrtr"} + js.RPacker(st,a,0) + fmt.Printf("JSON \n%s\n",st.Bytes()) + st.Reset() } diff --git a/app/tests/benchmarks_test.go b/app/tests/benchmarks_test.go index a2d6377..f1a210e 100644 --- a/app/tests/benchmarks_test.go +++ b/app/tests/benchmarks_test.go @@ -147,3 +147,22 @@ func BenchmarkListJSON (b *testing.B) { j.Marshal(cas) } } + +var ma = map[int]string {1:"344343",3:"4343434",5:"frtrtrtr"} + + +func BenchmarkMapPack (b *testing.B) { + s := packs.NewState() + for i:=0; i< b.N; i++ { + js.RPacker(s,ma,0) + s.Reset() + } +} + + + +func BenchmarkMapJSON (b *testing.B) { + for i:=0; i< b.N; i++ { + j.Marshal(ma) + } +} \ No newline at end of file diff --git a/packs/js/cache.go b/packs/js/cache.go index 6fded79..369493f 100644 --- a/packs/js/cache.go +++ b/packs/js/cache.go @@ -32,12 +32,16 @@ type ( cachePackers struct { sync.RWMutex - packers map[reflect.Type]packerFn + packers map[reflect.Type]packerFn + + keyers map[reflect.Type]StringerFn + } ) func NewCachePackers () *cachePackers { return &cachePackers{ + keyers : make(map[reflect.Type]StringerFn), packers: make(map[reflect.Type]packerFn), } } diff --git a/packs/js/type_map_entry.go b/packs/js/type_map_entry.go new file mode 100644 index 0000000..01accad --- /dev/null +++ b/packs/js/type_map_entry.go @@ -0,0 +1,41 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name type_map_entry.go +// Created by DEV +// Modified 30/01/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// 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 js + +import "reflect" + +type ( + + typeMapEntry struct { + val reflect.Value + key string + } +) + +func newTypeMapEntry (v reflect.Value, k string) *typeMapEntry { + return &typeMapEntry{ + val : v, + key : k, + } +} diff --git a/packs/js/type_map_packer.go b/packs/js/type_map_packer.go new file mode 100644 index 0000000..3d9e08f --- /dev/null +++ b/packs/js/type_map_packer.go @@ -0,0 +1,180 @@ +// ------------------------------------------------------------------------ +// Project atila +// Active Thing (activething.com) git.activething.com/go +// +// File name type_map_packer.go +// Created by DEV +// Modified 30/01/2024 +// +// Copyright 2024 activething.com +// ------------------------------------------------------------------------ +// 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 js + +import ( + "activething.com/go/gogo/packs" + "encoding" + "reflect" + "strconv" +) + +type ( + + typeMapPacker struct { + keyStringer StringerFn + valPacker packerFn + } + + + StringerFn func(value reflect.Value, entry *typeMapEntry) error +) + +func newTypeMapPacker (rtype reflect.Type) *typeMapPacker { + var kp StringerFn + + switch rtype.Key().Kind() { + case reflect.String : + kp = func(v reflect.Value, e *typeMapEntry) error { + e.key = v.String() + return nil + } + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64: + kp = func(v reflect.Value, e *typeMapEntry) error { + e.key = strconv.FormatInt(v.Int(),10) + return nil + } + case reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Uintptr: + kp = func(v reflect.Value, e *typeMapEntry) error { + e.key = strconv.FormatUint(v.Uint(),10) + return nil + } + default: + kp = func(v reflect.Value, e *typeMapEntry) error { + if tm,hs := v.Interface().(encoding.TextMarshaler); hs { + bf,er := tm.MarshalText() + if er != nil { + return er + } + e.key = string(bf) + return nil + } + + return packs.G.ErrInvalidKey + } + } + return &typeMapPacker{ + valPacker : typePacker(rtype.Elem()), + keyStringer: kp, + } +} + + +func (m typeMapPacker) pack (s *packs.State, v reflect.Value, f Flags) { + if v.IsNil() { + _,_ = s.Write(G.nullValue) + return + } + + var er error + mi := v.MapRange() + ls := make([]typeMapEntry,v.Len()) + + s.Open ('{') + for i:=0; mi.Next(); i++ { + ls[i] = typeMapEntry { + val: mi.Value(), + } + if er = m.keyStringer(mi.Key(),&ls[i]); er != nil { + s.SetError(er) + return + } + if i>0 { + s.WriteByte(',') + } + s.WriteString(ls[i].key) + s.WriteByte(':') + m.valPacker(s,mi.Value(),f) + } + s.Close('}') +} + + + + +func buildKeyPacker (rt reflect.Type) func(me *typeMapEntry, key reflect.Value) error { + if rt.Key().Kind() == reflect.String { + return func(e *typeMapEntry, k reflect.Value ) error { + e.key = k.String() + return nil + } + } + + if rt.Implements(reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()) { + return func(e *typeMapEntry, k reflect.Value) error { + if k.Kind() == reflect.Pointer && k.IsNil() { + return nil + } + bf,er := (k.Interface().(encoding.TextMarshaler)).MarshalText() + if er == nil { + e.key = string(bf) + } + return er + } + } + + switch rt.Kind() { + + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64: + return func(e *typeMapEntry, k reflect.Value) error { + e.key = strconv.FormatInt(k.Int(),10) + return nil + } + case reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Uintptr: + return func(e *typeMapEntry, k reflect.Value) error { + e.key = strconv.FormatUint(k.Uint(),10) + return nil + } + } + + return func(e *typeMapEntry, k reflect.Value) error { + + + if rt.Key().Kind() == reflect.String { + e.key = k.String() + } + + + return packs.G.ErrInvalidKey + } + +} \ No newline at end of file diff --git a/packs/js/type_packer.go b/packs/js/type_packer.go index 0f65eb2..357bd93 100644 --- a/packs/js/type_packer.go +++ b/packs/js/type_packer.go @@ -87,7 +87,13 @@ func buildTypePacker(t reflect.Type) packerFn { case reflect.Slice : return (typeSlicePacker{ packer: typePacker(t.Elem()) }).pack + + case reflect.Map : + return newTypeMapPacker(t).pack } + + + return func (s *packs.State, v reflect.Value, _ Flags) { unsupportedTypePacker(s,v,0)} }