redefiniendo el builder

packs2
DEV 3 years ago
parent bc0d45885a
commit 3752aca0d8

@ -24,29 +24,18 @@
package main package main
import ( import (
"actiovething.com/go/gogo/packs/_pjson"
"activething.com/go/gogo/core/errs" "activething.com/go/gogo/core/errs"
"activething.com/go/gogo/packs" "activething.com/go/gogo/packs/jjson"
"fmt" "fmt"
) )
func main() { func main() {
p := _pjson.NewBuilder(func (pk *_pjson.Builder) {
}) p := jjson.JSONPacker{}
d,e := p.Pack(22)
errs.Test(e,false)
fmt.Printf("Data = %s\n",d)
p.Object(func(b packs.BuilderObject) {
b.FieldBinary("0", []byte{43,53,32,34,53,35})
})
errs.Test(p.Error())
fmt.Printf("Data \n%s",p.Data())
/*
d,_ := json.Marshal("<html>asdadasd<html>")
fmt.Printf("Data \n%s",d)
*/
} }

@ -116,9 +116,11 @@ func getStackTrace(err error) StackTrace {
return nil return nil
} }
func Test(err error) { func Test(err error, halt bool) {
if err != nil { if err != nil {
fmt.Printf("err %v\n", err.Error()) fmt.Printf("err %v\n", err.Error())
panic(err) if halt {
panic(err)
}
} }
} }

@ -25,7 +25,13 @@ package packs
import "time" import "time"
type ( type (
Builder interface { Builder interface {
Data () []byte Data () []byte
Error () error Error () error

@ -30,7 +30,7 @@ type (
BuilderMap interface { BuilderMap interface {
ElemAny (key any, value any) ElemAny (key any, value any)
ElemBinary (key any, value []byte) ElemBinary (key any, value []byte)
ElemString (key any, value string) ElemString (key any, value string)

@ -25,29 +25,44 @@ package packs
import ( import (
"activething.com/go/gogo/core/bins" "activething.com/go/gogo/core/bins"
"activething.com/go/gogo/core/slices"
"activething.com/go/gogo/core/syncs" "activething.com/go/gogo/core/syncs"
"sync/atomic" "sync/atomic"
) )
const maxCyclesCheckIdle = 100
type ( type (
State struct { State struct {
*bins.Buffer/*Embedded*/ *bins.Buffer/*Embedded*/
Node *StateNode Node *StateNode
Error error Temp [64]byte
Seen map[any]struct{}
Error error
} }
) )
func AcquireState () *State { func AcquireState () *State {
if atomic.CompareAndSwapUint32(&G.stateSem,0,1) { if atomic.CompareAndSwapUint32(&G.poolsSem,0,1) {
G.nodePool = syncs.NewPool[StateNode](
syncs.PoolWithNew[StateNode](func()*StateNode{
return &StateNode{
Kind: NodeKindValue,
keys: make(slices.String, 0, 10),
}
}),
)
G.statePool = syncs.NewPool[State]( G.statePool = syncs.NewPool[State](
syncs.PoolWithNew[State](func() *State { syncs.PoolWithNew[State](func() *State {
return &State{ return &State{
Node : AcquireNode(nil, NodeKindValue, 0), Node : G.nodePool.Get().Init(nil, NodeKindValue, 0),
Buffer: bins.NewBuffer(), Buffer: bins.NewBuffer(),
Seen: make(map[any]struct{}),
} }
}), }),
) )
@ -57,7 +72,7 @@ func AcquireState () *State {
func ReleaseState (state *State) { func ReleaseState (state *State) {
if state == nil { if state == nil && atomic.LoadUint32(&G.poolsSem) == 1 {
return return
} }
state.Buffer.Reset() state.Buffer.Reset()
@ -112,7 +127,7 @@ func (s *State) Open(kind NodeKind) bool {
} }
s.Node.Init(s.Node.Parent, kind, s.Len()) s.Node.Init(s.Node.Parent, kind, s.Len())
} else { } else {
s.Node = AcquireNode(s.Node, kind, s.Len()) s.Node = G.nodePool.Get().Init(s.Node, kind, s.Len())
} }
return true return true
} }
@ -124,10 +139,11 @@ func (s *State) Close() bool {
if s.Node.Kind == NodeKindValue { if s.Node.Kind == NodeKindValue {
return !s.SetError(G.ErrInvalidNode) return !s.SetError(G.ErrInvalidNode)
} }
if s.Node.Parent != nil { if s.Node.Parent != nil {
p := s.Node p := s.Node
s.Node = s.Node.Parent s.Node = s.Node.Parent
ReleaseNode(p.Reset()) G.nodePool.Put(p.Reset())
} }
s.Node.Count++ s.Node.Count++
return true return true

@ -25,8 +25,6 @@ package packs
import ( import (
"activething.com/go/gogo/core/slices" "activething.com/go/gogo/core/slices"
"activething.com/go/gogo/core/syncs"
"sync/atomic"
) )
type ( type (
@ -41,27 +39,6 @@ type (
} }
) )
func AcquireNode(parent *StateNode, kind NodeKind, start int) *StateNode {
if atomic.CompareAndSwapUint32(&G.nodeSem, 0, 1) {
G.nodePool = syncs.NewPool[StateNode](
syncs.PoolWithNew[StateNode](func()*StateNode{
return &StateNode{
Kind: NodeKindValue,
keys: make(slices.String, 0, 10),
}
}),
)
}
return G.nodePool.Get().Init(parent, kind, start)
}
func ReleaseNode(node *StateNode) {
if node != nil {
G.nodePool.Put(node.Reset())
}
}
func (n *StateNode) Init(parent *StateNode, kind NodeKind, start int) *StateNode { func (n *StateNode) Init(parent *StateNode, kind NodeKind, start int) *StateNode {
n.Parent = parent n.Parent = parent
if parent != nil { if parent != nil {

@ -24,6 +24,7 @@
package packs package packs
const ( const (
NodeKindValue NodeKind = iota NodeKindValue NodeKind = iota
NodeKindList NodeKindList
NodeKindMap NodeKindMap

@ -33,11 +33,10 @@ import (
var ( var (
G = struct { G = struct {
nodeSem uint32
nodePool *syncs.Pool[StateNode]
stateSem uint32 poolsSem uint32
statePool *syncs.Pool[State] statePool *syncs.Pool[State]
nodePool *syncs.Pool[StateNode]
ErrInvalidNode errs.ErrCode ErrInvalidNode errs.ErrCode
ErrInvalidElement errs.ErrCode ErrInvalidElement errs.ErrCode
@ -46,6 +45,7 @@ var (
ErrKeyRequired errs.ErrCode ErrKeyRequired errs.ErrCode
ErrValueRequired errs.ErrCode ErrValueRequired errs.ErrCode
ErrInvalidList errs.ErrCode ErrInvalidList errs.ErrCode
ErrRedundantPack errs.ErrCode
}{ }{
ErrInvalidNode : errs.ErrCode("packs.invalid-StateNode"), ErrInvalidNode : errs.ErrCode("packs.invalid-StateNode"),
ErrInvalidElement: errs.ErrCode("packs.invalid-element"), ErrInvalidElement: errs.ErrCode("packs.invalid-element"),
@ -54,6 +54,7 @@ var (
ErrKeyRequired : errs.ErrCode("packs:key-required"), ErrKeyRequired : errs.ErrCode("packs:key-required"),
ErrValueRequired : errs.ErrCode("packs:value-required"), ErrValueRequired : errs.ErrCode("packs:value-required"),
ErrInvalidList : errs.ErrCode("packs:invalid-list"), ErrInvalidList : errs.ErrCode("packs:invalid-list"),
ErrRedundantPack : errs.ErrCode("packs:redundant-pack"),
} }
) )

@ -28,10 +28,16 @@ import (
"activething.com/go/gogo/core/syncs" "activething.com/go/gogo/core/syncs"
"activething.com/go/gogo/packs" "activething.com/go/gogo/packs"
"encoding/json" "encoding/json"
"reflect"
"sort"
"sync/atomic" "sync/atomic"
"time" "time"
) )
const(
maxDeepUncheck = 100
)
type ( type (
@ -46,6 +52,7 @@ type (
) )
func AcquireBuilder (options ...opts.OptionFnc[Builder]) *Builder { func AcquireBuilder (options ...opts.OptionFnc[Builder]) *Builder {
if atomic.CompareAndSwapUint32(&G.sentinel,0,1) { if atomic.CompareAndSwapUint32(&G.sentinel,0,1) {
G.builderPool = syncs.NewPool[Builder]( G.builderPool = syncs.NewPool[Builder](
@ -70,7 +77,22 @@ func ReleaseBuilder (builder *Builder) {
func (b *Builder) Any (value any) {} func (b *Builder) Any (value any) {
switch value.(type) {
default:
rv := reflect.ValueOf(value)
switch rv.Kind() {
case reflect.Struct : b.objPacker(rv)
case reflect.Map : b.mapPacker(rv)
case reflect.Slice : b.listPacker(rv)
}
}
}
func (b *Builder) Map (builder func(packer packs.BuilderMap)) {}
@ -82,4 +104,126 @@ func (b *Builder) reset () *Builder {
b.dateLayout = time.RFC822Z b.dateLayout = time.RFC822Z
b.state.Reset() b.state.Reset()
return b return b
}
func (b *Builder) mapPacker (rv reflect.Value) {
if rv.IsNil() {
b.state.Write(G.nullValue)
return
}
if rv.Len() == 0 {
b.state.Write2Byte('{','}')
return
}
if b.state.Node.Level > maxDeepUncheck {
p := rv.UnsafePointer()
if _,ok := b.state.Seen[p]; ok {
b.state.SetError(packs.G.ErrRedundantPack)
return
}
b.state.Seen[p] = struct{}{}
defer delete(b.state.Seen,p)
}
mi := rv.MapRange()
if b.options.SortMapKeys() {
ls := make([]reflectMapElem, rv.Len())
for i := 0; mi.Next(); i++ {
ls[i].k = mi.Key()
ls[i].v = mi.Value()
if !ls[i].stringifyKey(b.options) {
b.state.SetError(packs.G.ErrInvalidKey)
return
}
}
if b.options.SortMapKeys() {
sort.Slice(ls, func(i, j int) bool { return ls[i].s < ls[j].s })
}
b.Map(func(bm packs.BuilderMap) {
for _, e := range ls {
bm.ElemAny(e.s, e.v)
if b.state.Error != nil {
return
}
}
})
return
}
b.Map(func(bm packs.BuilderMap) {
for i:=0; mi.Next(); i++ {
bm.ElemAny(mi.Key(),mi.Value())
if b.state.Error != nil {
return
}
}
})
}
func (b *Builder) objPacker (rv reflect.Value) {
if rv.IsNil() {
b.state.Write(G.nullValue)
return
}
if rv.Len() == 0 {
b.state.Write2Byte('{','}')
return
}
}
func (b *Builder) listPacker(rv reflect.Value) {
if rv.IsNil() {
b.state.Write(G.nullValue)
return
}
if rv.Len() == 0 {
b.state.Write2Byte('[',']')
return
}
if b.state.Node.Level > maxDeepUncheck {
p := struct {
ptr interface{} // always an unsafe.Pointer, but avoids a dependency on package unsafe
len int
}{
ptr: rv.UnsafePointer(),
len: rv.Len(),
}
if _,ok := b.state.Seen[p]; ok {
b.state.SetError(packs.G.ErrRedundantPack)
return
}
b.state.Seen[p] = struct{}{}
defer delete(b.state.Seen,p)
}
switch rv.Type().Elem().Kind() {
case reflect.Int : b._listPacker (rv, func(lb packs.BuilderList, ev reflect.Value) { lb.ItemInt64(int64(ev.Int())) })
}
}
func (b *Builder) _listPacker (rlist reflect.Value, add func(lb packs.BuilderList, ev reflect.Value)) {
for i:=0; i< rlist.Len(); i++ {
add(b,rlist.Index(i))
if b.state.Error != nil {
return
}
}
}
func stringifyKey(key reflect.Value, ops Options) (string,bool) {
return "ss",true
} }

@ -25,12 +25,16 @@ package jjson
import ( import (
"activething.com/go/gogo/core/syncs" "activething.com/go/gogo/core/syncs"
"sync"
"unicode/utf8" "unicode/utf8"
) )
var ( var (
G = struct { G = struct {
objectCache sync.Map
sentinel uint32 sentinel uint32
builderPool *syncs.Pool[Builder] builderPool *syncs.Pool[Builder]

@ -30,6 +30,7 @@ const (
JSONOptionsIgnoreKeys JSONOptionsIgnoreKeys
JSONOptionsQuoteFloats JSONOptionsQuoteFloats
JSONOptionsIgnoreDefaults JSONOptionsIgnoreDefaults
JSONOptionsSortMapKeys
jsonOptionsDefaults = JSONOptionsQuote | JSONOptionsEscapeHTML jsonOptionsDefaults = JSONOptionsQuote | JSONOptionsEscapeHTML
@ -59,3 +60,7 @@ func (o Options) IgnoreKeys() bool {
func (o Options) IgnoreDefaults() bool { func (o Options) IgnoreDefaults() bool {
return o&JSONOptionsIgnoreDefaults != 0 return o&JSONOptionsIgnoreDefaults != 0
} }
func (o Options) SortMapKeys() bool {
return o&JSONOptionsSortMapKeys != 0
}

@ -37,16 +37,17 @@ type (
func (p JSONPacker) Pack (value any) (d []byte, e error) { func (p JSONPacker) Pack (value any) (d []byte, e error) {
dn := false dn := false
defer func (v *bool, er *error) { bl := AcquireBuilder()
defer func (b *Builder, v *bool, er *error) {
if !(*v) { if !(*v) {
*er = errs.ToError(recover()) *er = errs.ToError(recover())
} }
}(&dn,&e) ReleaseBuilder(b)
}(bl,&dn,&e)
bd := AcquireBuilder() bl.Any(value)
bd.Any(value)
dn = true dn = true
return bd.state.Bytes(),bd.state.Error return bl.state.Bytes(),bl.state.Error
} }

@ -0,0 +1,31 @@
// ------------------------------------------------------------------------
// Project atila
// Active Thing (activething.com) git.activething.com/go
//
// File name packer_cache.go
// Created by DEV
// Modified 23/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 jjson

@ -0,0 +1,43 @@
// ------------------------------------------------------------------------
// Project atila
// Active Thing (activething.com) git.activething.com/go
//
// File name reflect_map_elem.go
// Created by DEV
// Modified 22/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 jjson
import "reflect"
type (
reflectMapElem struct {
k reflect.Value
v reflect.Value
s string
}
)
func (b *reflectMapElem) stringifyKey(ops Options) (is bool) {
b.s,is = stringifyKey(b.k,ops)
return
}

@ -27,7 +27,9 @@ type (
Packer interface { Packer interface {
Pack(value any) ([]byte, error) Pack(value any) ([]byte, error)
} }
) )

Loading…
Cancel
Save

Powered by TurnKey Linux.