xref: /aosp_15_r20/external/golang-protobuf/internal/order/range.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2020 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsen// Package order provides ordered access to messages and maps.
6*1c12ee1eSDan Willemsenpackage order
7*1c12ee1eSDan Willemsen
8*1c12ee1eSDan Willemsenimport (
9*1c12ee1eSDan Willemsen	"sort"
10*1c12ee1eSDan Willemsen	"sync"
11*1c12ee1eSDan Willemsen
12*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
13*1c12ee1eSDan Willemsen)
14*1c12ee1eSDan Willemsen
15*1c12ee1eSDan Willemsentype messageField struct {
16*1c12ee1eSDan Willemsen	fd protoreflect.FieldDescriptor
17*1c12ee1eSDan Willemsen	v  protoreflect.Value
18*1c12ee1eSDan Willemsen}
19*1c12ee1eSDan Willemsen
20*1c12ee1eSDan Willemsenvar messageFieldPool = sync.Pool{
21*1c12ee1eSDan Willemsen	New: func() interface{} { return new([]messageField) },
22*1c12ee1eSDan Willemsen}
23*1c12ee1eSDan Willemsen
24*1c12ee1eSDan Willemsentype (
25*1c12ee1eSDan Willemsen	// FieldRnger is an interface for visiting all fields in a message.
26*1c12ee1eSDan Willemsen	// The protoreflect.Message type implements this interface.
27*1c12ee1eSDan Willemsen	FieldRanger interface{ Range(VisitField) }
28*1c12ee1eSDan Willemsen	// VisitField is called every time a message field is visited.
29*1c12ee1eSDan Willemsen	VisitField = func(protoreflect.FieldDescriptor, protoreflect.Value) bool
30*1c12ee1eSDan Willemsen)
31*1c12ee1eSDan Willemsen
32*1c12ee1eSDan Willemsen// RangeFields iterates over the fields of fs according to the specified order.
33*1c12ee1eSDan Willemsenfunc RangeFields(fs FieldRanger, less FieldOrder, fn VisitField) {
34*1c12ee1eSDan Willemsen	if less == nil {
35*1c12ee1eSDan Willemsen		fs.Range(fn)
36*1c12ee1eSDan Willemsen		return
37*1c12ee1eSDan Willemsen	}
38*1c12ee1eSDan Willemsen
39*1c12ee1eSDan Willemsen	// Obtain a pre-allocated scratch buffer.
40*1c12ee1eSDan Willemsen	p := messageFieldPool.Get().(*[]messageField)
41*1c12ee1eSDan Willemsen	fields := (*p)[:0]
42*1c12ee1eSDan Willemsen	defer func() {
43*1c12ee1eSDan Willemsen		if cap(fields) < 1024 {
44*1c12ee1eSDan Willemsen			*p = fields
45*1c12ee1eSDan Willemsen			messageFieldPool.Put(p)
46*1c12ee1eSDan Willemsen		}
47*1c12ee1eSDan Willemsen	}()
48*1c12ee1eSDan Willemsen
49*1c12ee1eSDan Willemsen	// Collect all fields in the message and sort them.
50*1c12ee1eSDan Willemsen	fs.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
51*1c12ee1eSDan Willemsen		fields = append(fields, messageField{fd, v})
52*1c12ee1eSDan Willemsen		return true
53*1c12ee1eSDan Willemsen	})
54*1c12ee1eSDan Willemsen	sort.Slice(fields, func(i, j int) bool {
55*1c12ee1eSDan Willemsen		return less(fields[i].fd, fields[j].fd)
56*1c12ee1eSDan Willemsen	})
57*1c12ee1eSDan Willemsen
58*1c12ee1eSDan Willemsen	// Visit the fields in the specified ordering.
59*1c12ee1eSDan Willemsen	for _, f := range fields {
60*1c12ee1eSDan Willemsen		if !fn(f.fd, f.v) {
61*1c12ee1eSDan Willemsen			return
62*1c12ee1eSDan Willemsen		}
63*1c12ee1eSDan Willemsen	}
64*1c12ee1eSDan Willemsen}
65*1c12ee1eSDan Willemsen
66*1c12ee1eSDan Willemsentype mapEntry struct {
67*1c12ee1eSDan Willemsen	k protoreflect.MapKey
68*1c12ee1eSDan Willemsen	v protoreflect.Value
69*1c12ee1eSDan Willemsen}
70*1c12ee1eSDan Willemsen
71*1c12ee1eSDan Willemsenvar mapEntryPool = sync.Pool{
72*1c12ee1eSDan Willemsen	New: func() interface{} { return new([]mapEntry) },
73*1c12ee1eSDan Willemsen}
74*1c12ee1eSDan Willemsen
75*1c12ee1eSDan Willemsentype (
76*1c12ee1eSDan Willemsen	// EntryRanger is an interface for visiting all fields in a message.
77*1c12ee1eSDan Willemsen	// The protoreflect.Map type implements this interface.
78*1c12ee1eSDan Willemsen	EntryRanger interface{ Range(VisitEntry) }
79*1c12ee1eSDan Willemsen	// VisitEntry is called every time a map entry is visited.
80*1c12ee1eSDan Willemsen	VisitEntry = func(protoreflect.MapKey, protoreflect.Value) bool
81*1c12ee1eSDan Willemsen)
82*1c12ee1eSDan Willemsen
83*1c12ee1eSDan Willemsen// RangeEntries iterates over the entries of es according to the specified order.
84*1c12ee1eSDan Willemsenfunc RangeEntries(es EntryRanger, less KeyOrder, fn VisitEntry) {
85*1c12ee1eSDan Willemsen	if less == nil {
86*1c12ee1eSDan Willemsen		es.Range(fn)
87*1c12ee1eSDan Willemsen		return
88*1c12ee1eSDan Willemsen	}
89*1c12ee1eSDan Willemsen
90*1c12ee1eSDan Willemsen	// Obtain a pre-allocated scratch buffer.
91*1c12ee1eSDan Willemsen	p := mapEntryPool.Get().(*[]mapEntry)
92*1c12ee1eSDan Willemsen	entries := (*p)[:0]
93*1c12ee1eSDan Willemsen	defer func() {
94*1c12ee1eSDan Willemsen		if cap(entries) < 1024 {
95*1c12ee1eSDan Willemsen			*p = entries
96*1c12ee1eSDan Willemsen			mapEntryPool.Put(p)
97*1c12ee1eSDan Willemsen		}
98*1c12ee1eSDan Willemsen	}()
99*1c12ee1eSDan Willemsen
100*1c12ee1eSDan Willemsen	// Collect all entries in the map and sort them.
101*1c12ee1eSDan Willemsen	es.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
102*1c12ee1eSDan Willemsen		entries = append(entries, mapEntry{k, v})
103*1c12ee1eSDan Willemsen		return true
104*1c12ee1eSDan Willemsen	})
105*1c12ee1eSDan Willemsen	sort.Slice(entries, func(i, j int) bool {
106*1c12ee1eSDan Willemsen		return less(entries[i].k, entries[j].k)
107*1c12ee1eSDan Willemsen	})
108*1c12ee1eSDan Willemsen
109*1c12ee1eSDan Willemsen	// Visit the entries in the specified ordering.
110*1c12ee1eSDan Willemsen	for _, e := range entries {
111*1c12ee1eSDan Willemsen		if !fn(e.k, e.v) {
112*1c12ee1eSDan Willemsen			return
113*1c12ee1eSDan Willemsen		}
114*1c12ee1eSDan Willemsen	}
115*1c12ee1eSDan Willemsen}
116