package decodebudget
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
func mapInsertCost(field protoreflect.FieldDescriptor, n int) int {
slot, pointers := mapSlot(field)
return mapGrowth(n, slot, pointers)
}
func mapSlot(field protoreflect.FieldDescriptor) (size int, pointers bool) {
key, value := field.MapKey(), field.MapValue()
return (goValueSize(key) + goValueSize(value) + 7) &^ 7, hasPointers(key) || hasPointers(value)
}
func mapBoxCost(field protoreflect.FieldDescriptor) int {
if field.Message() != nil {
return 0
}
return 2 * allocSize(goValueSize(field))
}
func reflectAppendCost(field protoreflect.FieldDescriptor) int {
const sliceHeader = 24
if field.Message() != nil {
return sliceHeader
}
return sliceHeader + goValueSize(field)
}
func oneofWrapperCost(field protoreflect.FieldDescriptor) int {
return allocSize(goValueSize(field))
}
func presenceCost(field protoreflect.FieldDescriptor) int {
if !field.HasPresence() || field.IsList() || field.Message() != nil || field.IsExtension() ||
(field.ContainingOneof() != nil && !field.ContainingOneof().IsSynthetic()) ||
field.ContainingMessage().IsMapEntry() {
return 0
}
return allocSize(goValueSize(field))
}
func fieldExtraCost(field protoreflect.FieldDescriptor, payloadLen int) int {
return fieldCost(field, payloadLen, 0)
}
func fieldCost(field protoreflect.FieldDescriptor, payloadLen, msgCost int) int {
cost := 0
if !field.ContainingMessage().IsMapEntry() {
cost += msgCost
}
if k := field.Kind(); k == protoreflect.StringKind || k == protoreflect.BytesKind {
cost += allocSize(payloadLen)
}
switch {
case field.IsMap():
cost += mapBoxCost(field.MapKey()) + mapBoxCost(field.MapValue())
case field.IsList():
case field.ContainingOneof() != nil && !field.ContainingOneof().IsSynthetic():
cost += oneofWrapperCost(field)
}
return cost
}
type generatedModel struct{}
func (g generatedModel) root(info *messageInfo) int {
return info.layout.size
}
func (g generatedModel) message(m *messageState, f *fieldInfo) (int, *fieldState) {
if f.list || f.isMap {
return g.occurrence(m, f, 0), nil
}
fs, isNew := m.add(f)
cost := 0
if f.extension {
cost = extensionCost(m, f, isNew)
}
m.setOneof(f, fs)
if fs.child != nil {
return cost, fs
}
return cost + f.allocCost, fs
}
func (g generatedModel) occurrence(m *messageState, f *fieldInfo, payloadLen int) int {
cost := f.allocCost
if f.payload {
cost += allocSize(payloadLen)
}
if f.extension {
fs, isNew := m.add(f)
cost += extensionCost(m, f, isNew)
if f.list {
cost += extensionListCost(fs, f, 1, payloadLen, isNew)
}
return cost
}
switch {
case f.list:
fs := m.get(f)
grow := appendGrow
if f.pointers {
grow = appendGrowPointers
}
var mem int
mem, fs.cap = grow(fs.len, fs.cap, 1, f.elemSize)
fs.len++
cost += mem
case f.isMap:
fs := m.get(f)
cost += g.allocateMap(fs)
cost += mapGrowth(fs.entries, f.mapSlot, f.mapPointers)
fs.entries++
case f.presence > 0:
if fs := m.get(f); !fs.present {
fs.present = true
cost += f.presence
}
case f.oneof != nil:
m.setOneof(f, m.get(f))
}
return cost
}
func (g generatedModel) packed(m *messageState, f *fieldInfo, count int) int {
if f.extension {
fs, isNew := m.add(f)
return extensionCost(m, f, isNew) + extensionListCost(fs, f, count, 0, isNew)
}
if count == 0 {
return 0
}
fs := m.get(f)
fs.len += count
fs.cap = fs.len
return allocSize(fs.len * f.elemSize)
}
func (g generatedModel) mismatch(m *messageState, f *fieldInfo) int {
if f.extension {
cost := extensionMapHeader(m)
if !f.generatedExt {
cost += uncachedExtensionCost
}
if m.find(f) == nil {
cost += f.valueCost
}
return cost
}
if f.isMap {
return g.allocateMap(m.get(f))
}
if f.oneof == nil || m.isSet(f) {
return 0
}
return allocSize(f.elemSize)
}
func (g generatedModel) unknown(m *messageState, info *messageInfo) int {
if !info.extendable {
return 0
}
return extensionMapHeader(m)
}
func (g generatedModel) allocateMap(fs *fieldState) int {
if fs.allocated {
return 0
}
fs.allocated = true
return allocSize(mapHeaderSize)
}