From d740abf0c6e9ae18d8d4e5f54919e9fa8dd9480e Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 28 Feb 2023 18:10:21 +0000 Subject: [PATCH] model/labels: add Get and Range to Builder This lets relabelling work on a `Builder` rather than converting to and from `Labels` on every rule. Signed-off-by: Bryan Boreham --- model/labels/labels.go | 49 ++++++++++++++++++++++++++++------- model/labels/labels_string.go | 35 +++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/model/labels/labels.go b/model/labels/labels.go index 056bc6374..5e06e3b8d 100644 --- a/model/labels/labels.go +++ b/model/labels/labels.go @@ -530,6 +530,43 @@ func (b *Builder) Set(n, v string) *Builder { return b } +func (b *Builder) Get(n string) string { + for _, d := range b.del { + if d == n { + return "" + } + } + for _, a := range b.add { + if a.Name == n { + return a.Value + } + } + return b.base.Get(n) +} + +// Range calls f on each label in the Builder. +// If f calls Set or Del on b then this may affect what callbacks subsequently happen. +func (b *Builder) Range(f func(l Label)) { + origAdd, origDel := b.add, b.del + b.base.Range(func(l Label) { + if !slices.Contains(origDel, l.Name) && !contains(origAdd, l.Name) { + f(l) + } + }) + for _, a := range origAdd { + f(a) + } +} + +func contains(s []Label, n string) bool { + for _, a := range s { + if a.Name == n { + return true + } + } + return false +} + // Labels returns the labels from the builder, adding them to res if non-nil. // Argument res can be the same as b.base, if caller wants to overwrite that slice. // If no modifications were made, the original labels are returned. @@ -545,20 +582,12 @@ func (b *Builder) Labels(res Labels) Labels { } else { res = res[:0] } -Outer: // Justification that res can be the same slice as base: in this loop // we move forward through base, and either skip an element or assign // it to res at its current position or an earlier position. for _, l := range b.base { - for _, n := range b.del { - if l.Name == n { - continue Outer - } - } - for _, la := range b.add { - if l.Name == la.Name { - continue Outer - } + if slices.Contains(b.del, l.Name) || contains(b.add, l.Name) { + continue } res = append(res, l) } diff --git a/model/labels/labels_string.go b/model/labels/labels_string.go index 815e263ba..422fb37c0 100644 --- a/model/labels/labels_string.go +++ b/model/labels/labels_string.go @@ -587,6 +587,41 @@ func (b *Builder) Set(n, v string) *Builder { return b } +func (b *Builder) Get(n string) string { + if slices.Contains(b.del, n) { + return "" + } + for _, a := range b.add { + if a.Name == n { + return a.Value + } + } + return b.base.Get(n) +} + +// Range calls f on each label in the Builder. +// If f calls Set or Del on b then this may affect what callbacks subsequently happen. +func (b *Builder) Range(f func(l Label)) { + origAdd, origDel := b.add, b.del + b.base.Range(func(l Label) { + if !slices.Contains(origDel, l.Name) && !contains(origAdd, l.Name) { + f(l) + } + }) + for _, a := range origAdd { + f(a) + } +} + +func contains(s []Label, n string) bool { + for _, a := range s { + if a.Name == n { + return true + } + } + return false +} + // Labels returns the labels from the builder, adding them to res if non-nil. // Argument res can be the same as b.base, if caller wants to overwrite that slice. // If no modifications were made, the original labels are returned.