Skip to content

Commit aa997dd

Browse files
committed
std/encoding/json: minor optimizations for struct caching
1 parent 99402cc commit aa997dd

1 file changed

Lines changed: 20 additions & 10 deletions

File tree

std/encoding/json/encode.jule

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -569,12 +569,13 @@ struct field {
569569
}
570570

571571
// Field cache data for structure types and associated RWMutex.
572-
let mut fieldMap = map[uintptr][]&field{}
572+
let mut fieldMap = map[uintptr][]field{}
573573
let mut fieldMapLock = runtime::rwmutex{}
574574

575575
// Returns field cache data for the structure type T.
576576
// If the structure is not cached yet, it will cache it.
577-
fn cachedFields[T](): []&field {
577+
#disable nilptr boundary
578+
fn cachedFields[T](): []field {
578579
const t = comptime::TypeOf(T)
579580
fieldMapLock.rLock()
580581
mut cache, mut exist := fieldMap[t.Hash()]
@@ -597,16 +598,24 @@ fn cachedFields[T](): []&field {
597598
p := unsafe { (*T)(0) }
598599
const pv = comptime::ValueOf(unsafe { *p })
599600
const fields = t.Fields()
600-
const for i, f in t.Decl().Fields() {
601-
const tag = f.Tag("json")
601+
mut n := 0
602+
// Grow cache by field count,
603+
// a typical JSON structure is encoded with all fields.
604+
cache = make([]field, len(fields))
605+
const for i, f in fields {
606+
const fd = f.Decl()
607+
const tag = fd.Tag("json")
602608
const match {
603-
| f.Public() | tag != "":
604-
name := getFieldName[T](f.Public(), f.Name(), tag)
609+
| fd.Public() | tag != "":
610+
name := getFieldName[T](fd.Public(), fd.Name(), tag)
605611
if name != "" {
606-
comptime::TypeAlias(fieldType, fields[i].Type())
612+
comptime::TypeAlias(fieldType, f.Type())
607613

608-
mut fieldCache := new(field)
614+
// Initialize directly the slice's memory.
615+
// This is efficient than appending a temporary cache object.
616+
mut &fieldCache := unsafe { &(*&cache[n]) }
609617
fieldCache.offset = uintptr(&pv.FieldByIndex(i).Unwrap())
618+
n++
610619

611620
// Cache name for non-escape.
612621
fieldCache.nameNonEsc = name
@@ -624,11 +633,12 @@ fn cachedFields[T](): []&field {
624633
fieldCache.encodePlain = typeEncoderPlain[fieldType]
625634
fieldCache.encodeIndent = typeEncoderIndent[fieldType]
626635
fieldCache.decode = typeDecoder[fieldType]
627-
628-
cache = append(cache, fieldCache)
629636
}
630637
}
631638
}
639+
// Truncate the cache, there may be skipped fields.
640+
cache = cache[:n]
641+
// Save the cache and return.
632642
fieldMap[t.Hash()] = cache
633643
fieldMapLock.unlock()
634644
ret cache

0 commit comments

Comments
 (0)