Commit cc2af4a2 authored by Eric Myhre's avatar Eric Myhre

codegen: speciated lookups and iterators for typed lists.

parent 95501bb0
......@@ -29,7 +29,74 @@ func (g listGenerator) EmitNativeType(w io.Writer) {
}
func (g listGenerator) EmitNativeAccessors(w io.Writer) {
// FUTURE: come back to this -- surely something nice can be done here.
// Generate a speciated Lookup as well as LookupMaybe method.
// The Lookup method returns nil in case of *either* an out-of-range/absent value or a null value,
// and so should only be used if the list type doesn't allow nullable keys or if the caller doesn't care about the difference.
// The LookupMaybe method returns a MaybeT type for the list value,
// and is needed if the list allows nullable values and the caller wishes to distinguish between null and out-of-range/absent.
// (The Lookup method should be preferred for lists that have non-nullable keys, because LookupMaybe may incur additional costs;
// boxing something into a maybe when it wasn't already stored that way costs an alloc(!),
// and may additionally incur a memcpy if the maybe for the value type doesn't use pointers internally).
doTemplate(`
func (n *_{{ .Type | TypeSymbol }}) Lookup(idx int) {{ .Type.ValueType | TypeSymbol }} {
if n.Length() <= idx {
return nil
}
v := &n.x[idx]
{{- if .Type.ValueIsNullable }}
if v.m == schema.Maybe_Null {
return nil
}
return {{ if not (MaybeUsesPtr .Type.ValueType) }}&{{end}}v.v
{{- else}}
return v
{{- end}}
}
func (n *_{{ .Type | TypeSymbol }}) LookupMaybe(idx int) Maybe{{ .Type.ValueType | TypeSymbol }} {
if n.Length() <= idx {
return nil
}
v := &n.x[idx]
{{- if .Type.ValueIsNullable }}
return v
{{- else}}
return &_{{ .Type.ValueType | TypeSymbol }}__Maybe{
m: schema.Maybe_Value,
v: {{ if not (MaybeUsesPtr .Type.ValueType) }}*{{end}}v,
}
{{- end}}
}
var _{{ .Type | TypeSymbol }}__valueAbsent = _{{ .Type.ValueType | TypeSymbol }}__Maybe{m:schema.Maybe_Absent}
`, w, g.AdjCfg, g)
// Generate a speciated iterator.
// The main advantage of this over the general ipld.ListIterator is of course keeping types visible (and concrete, to the compiler's eyes in optimizations, too).
// It also elides the error return from the iterator's Next method. (Overreads will result in -1 as an index and nil values; this is both easily avoidable, and unambiguous if you do goof and hit it.)
doTemplate(`
func (n {{ .Type | TypeSymbol }}) Iterator() *{{ .Type | TypeSymbol }}__Itr {
return &{{ .Type | TypeSymbol }}__Itr{n, 0}
}
type {{ .Type | TypeSymbol }}__Itr struct {
n {{ .Type | TypeSymbol }}
idx int
}
func (itr *{{ .Type | TypeSymbol }}__Itr) Next() (idx int, v {{if .Type.ValueIsNullable }}Maybe{{end}}{{ .Type.ValueType | TypeSymbol }}) {
if itr.idx >= len(itr.n.x) {
return -1, nil
}
idx = itr.idx
v = &itr.n.x[itr.idx]
itr.idx++
return
}
func (itr *{{ .Type | TypeSymbol }}__Itr) Done() bool {
return itr.idx >= len(itr.n.x)
}
`, w, g.AdjCfg, g)
}
func (g listGenerator) EmitNativeBuilder(w io.Writer) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment