From f70628ee1c460b7438f75abe563678adb73e5b5f Mon Sep 17 00:00:00 2001 From: Pawel Foremski Date: Fri, 11 Sep 2020 14:35:09 +0200 Subject: [PATCH 01/19] add FindTagsAppend() --- template/tree_v4.go | 43 ++++++++++++++++++++++++----------- template/tree_v6_generated.go | 43 ++++++++++++++++++++++++----------- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/template/tree_v4.go b/template/tree_v4.go index 8a2a117..b10aa81 100644 --- a/template/tree_v4.go +++ b/template/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag GeneratedType, nodeIndex uint, matchFunc MatchesFunc } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []GeneratedType { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]GeneratedType, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []GeneratedType, nodeIndex uint) []GeneratedType { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]GeneratedType, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]GeneratedType, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]GeneratedType, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []GeneratedType, address patricia.IPv4Address) []GeneratedType { var matchCount uint root := &t.nodes[1] - ret := make([]GeneratedType, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]GeneratedType, error) for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/template/tree_v6_generated.go b/template/tree_v6_generated.go index 602e018..4d9726f 100644 --- a/template/tree_v6_generated.go +++ b/template/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag GeneratedType, nodeIndex uint, matchFunc MatchesFunc } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []GeneratedType { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]GeneratedType, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []GeneratedType, nodeIndex uint) []GeneratedType { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]GeneratedType, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]GeneratedType, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]GeneratedType, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []GeneratedType, address patricia.IPv6Address) []GeneratedType { var matchCount uint root := &t.nodes[1] - ret := make([]GeneratedType, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]GeneratedType, error) for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing From 2c3122643c86b89dfd6c08a4eaafb64d814bf187 Mon Sep 17 00:00:00 2001 From: Pawel Foremski Date: Fri, 11 Sep 2020 15:04:44 +0200 Subject: [PATCH 02/19] generate the type trees --- bool_tree/tree_v4.go | 43 +++++++++++++++++++--------- bool_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- byte_tree/tree_v4.go | 43 +++++++++++++++++++--------- byte_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- complex128_tree/tree_v4.go | 43 +++++++++++++++++++--------- complex128_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- complex64_tree/tree_v4.go | 43 +++++++++++++++++++--------- complex64_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- float32_tree/tree_v4.go | 43 +++++++++++++++++++--------- float32_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- float64_tree/tree_v4.go | 43 +++++++++++++++++++--------- float64_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- int16_tree/tree_v4.go | 43 +++++++++++++++++++--------- int16_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- int32_tree/tree_v4.go | 43 +++++++++++++++++++--------- int32_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- int64_tree/tree_v4.go | 43 +++++++++++++++++++--------- int64_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- int8_tree/tree_v4.go | 43 +++++++++++++++++++--------- int8_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- int_tree/tree_v4.go | 43 +++++++++++++++++++--------- int_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- rune_tree/tree_v4.go | 43 +++++++++++++++++++--------- rune_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- string_tree/tree_v4.go | 43 +++++++++++++++++++--------- string_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- uint16_tree/tree_v4.go | 43 +++++++++++++++++++--------- uint16_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- uint32_tree/tree_v4.go | 43 +++++++++++++++++++--------- uint32_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- uint64_tree/tree_v4.go | 43 +++++++++++++++++++--------- uint64_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- uint8_tree/tree_v4.go | 43 +++++++++++++++++++--------- uint8_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- uint_tree/tree_v4.go | 43 +++++++++++++++++++--------- uint_tree/tree_v6_generated.go | 43 +++++++++++++++++++--------- 36 files changed, 1080 insertions(+), 468 deletions(-) diff --git a/bool_tree/tree_v4.go b/bool_tree/tree_v4.go index a58f404..02ffc32 100644 --- a/bool_tree/tree_v4.go +++ b/bool_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag bool, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []bool { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]bool, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []bool, nodeIndex uint) []bool { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]bool, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]bool, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]bool, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []bool, address patricia.IPv4Address) []bool { var matchCount uint root := &t.nodes[1] - ret := make([]bool, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]bool, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/bool_tree/tree_v6_generated.go b/bool_tree/tree_v6_generated.go index 3fca655..0554a33 100644 --- a/bool_tree/tree_v6_generated.go +++ b/bool_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag bool, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []bool { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]bool, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []bool, nodeIndex uint) []bool { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]bool, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]bool, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]bool, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []bool, address patricia.IPv6Address) []bool { var matchCount uint root := &t.nodes[1] - ret := make([]bool, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]bool, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/byte_tree/tree_v4.go b/byte_tree/tree_v4.go index dabafb1..a303da0 100644 --- a/byte_tree/tree_v4.go +++ b/byte_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag byte, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []byte { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]byte, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []byte, nodeIndex uint) []byte { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]byte, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]byte, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]byte, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []byte, address patricia.IPv4Address) []byte { var matchCount uint root := &t.nodes[1] - ret := make([]byte, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]byte, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/byte_tree/tree_v6_generated.go b/byte_tree/tree_v6_generated.go index 4dcd120..3f3ba4a 100644 --- a/byte_tree/tree_v6_generated.go +++ b/byte_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag byte, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []byte { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]byte, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []byte, nodeIndex uint) []byte { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]byte, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]byte, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]byte, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []byte, address patricia.IPv6Address) []byte { var matchCount uint root := &t.nodes[1] - ret := make([]byte, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]byte, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/complex128_tree/tree_v4.go b/complex128_tree/tree_v4.go index faa38d3..389f6e0 100644 --- a/complex128_tree/tree_v4.go +++ b/complex128_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag complex128, nodeIndex uint, matchFunc MatchesFunc, r } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []complex128 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]complex128, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []complex128, nodeIndex uint) []complex128 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]complex128, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex128, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]complex128, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []complex128, address patricia.IPv4Address) []complex128 { var matchCount uint root := &t.nodes[1] - ret := make([]complex128, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex128, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/complex128_tree/tree_v6_generated.go b/complex128_tree/tree_v6_generated.go index a0eaa06..222b667 100644 --- a/complex128_tree/tree_v6_generated.go +++ b/complex128_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag complex128, nodeIndex uint, matchFunc MatchesFunc, r } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []complex128 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]complex128, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []complex128, nodeIndex uint) []complex128 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]complex128, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex128, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]complex128, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []complex128, address patricia.IPv6Address) []complex128 { var matchCount uint root := &t.nodes[1] - ret := make([]complex128, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex128, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/complex64_tree/tree_v4.go b/complex64_tree/tree_v4.go index 7b52e42..2888e50 100644 --- a/complex64_tree/tree_v4.go +++ b/complex64_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag complex64, nodeIndex uint, matchFunc MatchesFunc, re } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []complex64 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]complex64, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []complex64, nodeIndex uint) []complex64 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]complex64, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex64, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]complex64, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []complex64, address patricia.IPv4Address) []complex64 { var matchCount uint root := &t.nodes[1] - ret := make([]complex64, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/complex64_tree/tree_v6_generated.go b/complex64_tree/tree_v6_generated.go index 201c9af..42f57ff 100644 --- a/complex64_tree/tree_v6_generated.go +++ b/complex64_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag complex64, nodeIndex uint, matchFunc MatchesFunc, re } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []complex64 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]complex64, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []complex64, nodeIndex uint) []complex64 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]complex64, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex64, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]complex64, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []complex64, address patricia.IPv6Address) []complex64 { var matchCount uint root := &t.nodes[1] - ret := make([]complex64, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/float32_tree/tree_v4.go b/float32_tree/tree_v4.go index 17fb3ac..d250077 100644 --- a/float32_tree/tree_v4.go +++ b/float32_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag float32, nodeIndex uint, matchFunc MatchesFunc, repl } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []float32 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]float32, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []float32, nodeIndex uint) []float32 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]float32, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float32, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]float32, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []float32, address patricia.IPv4Address) []float32 { var matchCount uint root := &t.nodes[1] - ret := make([]float32, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/float32_tree/tree_v6_generated.go b/float32_tree/tree_v6_generated.go index a002105..f1c9bb3 100644 --- a/float32_tree/tree_v6_generated.go +++ b/float32_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag float32, nodeIndex uint, matchFunc MatchesFunc, repl } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []float32 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]float32, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []float32, nodeIndex uint) []float32 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]float32, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float32, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]float32, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []float32, address patricia.IPv6Address) []float32 { var matchCount uint root := &t.nodes[1] - ret := make([]float32, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/float64_tree/tree_v4.go b/float64_tree/tree_v4.go index 9a765c3..99ab65e 100644 --- a/float64_tree/tree_v4.go +++ b/float64_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag float64, nodeIndex uint, matchFunc MatchesFunc, repl } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []float64 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]float64, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []float64, nodeIndex uint) []float64 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]float64, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float64, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]float64, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []float64, address patricia.IPv4Address) []float64 { var matchCount uint root := &t.nodes[1] - ret := make([]float64, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/float64_tree/tree_v6_generated.go b/float64_tree/tree_v6_generated.go index b95c952..d4b84ec 100644 --- a/float64_tree/tree_v6_generated.go +++ b/float64_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag float64, nodeIndex uint, matchFunc MatchesFunc, repl } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []float64 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]float64, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []float64, nodeIndex uint) []float64 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]float64, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float64, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]float64, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []float64, address patricia.IPv6Address) []float64 { var matchCount uint root := &t.nodes[1] - ret := make([]float64, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int16_tree/tree_v4.go b/int16_tree/tree_v4.go index 445b1d1..d8bd72c 100644 --- a/int16_tree/tree_v4.go +++ b/int16_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag int16, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []int16 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int16, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []int16, nodeIndex uint) []int16 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int16, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int16, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int16, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int16, address patricia.IPv4Address) []int16 { var matchCount uint root := &t.nodes[1] - ret := make([]int16, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int16, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int16_tree/tree_v6_generated.go b/int16_tree/tree_v6_generated.go index c1ef07b..8e3bd43 100644 --- a/int16_tree/tree_v6_generated.go +++ b/int16_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag int16, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []int16 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int16, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []int16, nodeIndex uint) []int16 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int16, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int16, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int16, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int16, address patricia.IPv6Address) []int16 { var matchCount uint root := &t.nodes[1] - ret := make([]int16, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int16, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int32_tree/tree_v4.go b/int32_tree/tree_v4.go index f33f37d..73f853e 100644 --- a/int32_tree/tree_v4.go +++ b/int32_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag int32, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []int32 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int32, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []int32, nodeIndex uint) []int32 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int32, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int32, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int32, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int32, address patricia.IPv4Address) []int32 { var matchCount uint root := &t.nodes[1] - ret := make([]int32, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int32_tree/tree_v6_generated.go b/int32_tree/tree_v6_generated.go index 0512284..2ec9a84 100644 --- a/int32_tree/tree_v6_generated.go +++ b/int32_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag int32, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []int32 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int32, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []int32, nodeIndex uint) []int32 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int32, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int32, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int32, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int32, address patricia.IPv6Address) []int32 { var matchCount uint root := &t.nodes[1] - ret := make([]int32, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int64_tree/tree_v4.go b/int64_tree/tree_v4.go index 18358e6..b97364f 100644 --- a/int64_tree/tree_v4.go +++ b/int64_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag int64, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []int64 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int64, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []int64, nodeIndex uint) []int64 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int64, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int64, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int64, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int64, address patricia.IPv4Address) []int64 { var matchCount uint root := &t.nodes[1] - ret := make([]int64, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int64_tree/tree_v6_generated.go b/int64_tree/tree_v6_generated.go index 21ffa67..44b745b 100644 --- a/int64_tree/tree_v6_generated.go +++ b/int64_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag int64, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []int64 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int64, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []int64, nodeIndex uint) []int64 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int64, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int64, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int64, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int64, address patricia.IPv6Address) []int64 { var matchCount uint root := &t.nodes[1] - ret := make([]int64, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int8_tree/tree_v4.go b/int8_tree/tree_v4.go index 2f53e24..e70ad8a 100644 --- a/int8_tree/tree_v4.go +++ b/int8_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag int8, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []int8 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int8, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []int8, nodeIndex uint) []int8 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int8, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int8, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int8, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int8, address patricia.IPv4Address) []int8 { var matchCount uint root := &t.nodes[1] - ret := make([]int8, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int8, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int8_tree/tree_v6_generated.go b/int8_tree/tree_v6_generated.go index 681aafd..8c73832 100644 --- a/int8_tree/tree_v6_generated.go +++ b/int8_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag int8, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []int8 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int8, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []int8, nodeIndex uint) []int8 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int8, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int8, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int8, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int8, address patricia.IPv6Address) []int8 { var matchCount uint root := &t.nodes[1] - ret := make([]int8, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int8, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int_tree/tree_v4.go b/int_tree/tree_v4.go index cc4d96f..8730814 100644 --- a/int_tree/tree_v4.go +++ b/int_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag int, nodeIndex uint, matchFunc MatchesFunc, replaceF } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []int { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []int, nodeIndex uint) []int { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int, address patricia.IPv4Address) []int { var matchCount uint root := &t.nodes[1] - ret := make([]int, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/int_tree/tree_v6_generated.go b/int_tree/tree_v6_generated.go index 2ce9c46..0eba682 100644 --- a/int_tree/tree_v6_generated.go +++ b/int_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag int, nodeIndex uint, matchFunc MatchesFunc, replaceF } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []int { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]int, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []int, nodeIndex uint) []int { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]int, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]int, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int, address patricia.IPv6Address) []int { var matchCount uint root := &t.nodes[1] - ret := make([]int, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/rune_tree/tree_v4.go b/rune_tree/tree_v4.go index 4ee7ebf..55bbbf4 100644 --- a/rune_tree/tree_v4.go +++ b/rune_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag rune, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []rune { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]rune, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []rune, nodeIndex uint) []rune { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]rune, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]rune, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]rune, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []rune, address patricia.IPv4Address) []rune { var matchCount uint root := &t.nodes[1] - ret := make([]rune, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]rune, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/rune_tree/tree_v6_generated.go b/rune_tree/tree_v6_generated.go index 54d79c6..f9e9d5a 100644 --- a/rune_tree/tree_v6_generated.go +++ b/rune_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag rune, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []rune { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]rune, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []rune, nodeIndex uint) []rune { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]rune, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]rune, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]rune, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []rune, address patricia.IPv6Address) []rune { var matchCount uint root := &t.nodes[1] - ret := make([]rune, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]rune, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/string_tree/tree_v4.go b/string_tree/tree_v4.go index 8ae1eaa..b4d796a 100644 --- a/string_tree/tree_v4.go +++ b/string_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag string, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []string { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]string, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []string, nodeIndex uint) []string { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]string, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]string, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]string, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []string, address patricia.IPv4Address) []string { var matchCount uint root := &t.nodes[1] - ret := make([]string, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]string, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/string_tree/tree_v6_generated.go b/string_tree/tree_v6_generated.go index dd19a73..1de8875 100644 --- a/string_tree/tree_v6_generated.go +++ b/string_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag string, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []string { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]string, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []string, nodeIndex uint) []string { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]string, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]string, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]string, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []string, address patricia.IPv6Address) []string { var matchCount uint root := &t.nodes[1] - ret := make([]string, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]string, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v4.go b/uint16_tree/tree_v4.go index a60d4dc..cb2a28d 100644 --- a/uint16_tree/tree_v4.go +++ b/uint16_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag uint16, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []uint16 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint16, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []uint16, nodeIndex uint) []uint16 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint16, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint16, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint16, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint16, address patricia.IPv4Address) []uint16 { var matchCount uint root := &t.nodes[1] - ret := make([]uint16, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint16, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v6_generated.go b/uint16_tree/tree_v6_generated.go index db87aa8..bd899e2 100644 --- a/uint16_tree/tree_v6_generated.go +++ b/uint16_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag uint16, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []uint16 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint16, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []uint16, nodeIndex uint) []uint16 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint16, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint16, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint16, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint16, address patricia.IPv6Address) []uint16 { var matchCount uint root := &t.nodes[1] - ret := make([]uint16, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint16, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint32_tree/tree_v4.go b/uint32_tree/tree_v4.go index 3de8bf6..2bd4069 100644 --- a/uint32_tree/tree_v4.go +++ b/uint32_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag uint32, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []uint32 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint32, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []uint32, nodeIndex uint) []uint32 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint32, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint32, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint32, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint32, address patricia.IPv4Address) []uint32 { var matchCount uint root := &t.nodes[1] - ret := make([]uint32, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint32_tree/tree_v6_generated.go b/uint32_tree/tree_v6_generated.go index 871992e..b83fa31 100644 --- a/uint32_tree/tree_v6_generated.go +++ b/uint32_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag uint32, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []uint32 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint32, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []uint32, nodeIndex uint) []uint32 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint32, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint32, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint32, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint32, address patricia.IPv6Address) []uint32 { var matchCount uint root := &t.nodes[1] - ret := make([]uint32, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint64_tree/tree_v4.go b/uint64_tree/tree_v4.go index adf8639..f291719 100644 --- a/uint64_tree/tree_v4.go +++ b/uint64_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag uint64, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []uint64 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint64, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []uint64, nodeIndex uint) []uint64 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint64, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint64, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint64, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint64, address patricia.IPv4Address) []uint64 { var matchCount uint root := &t.nodes[1] - ret := make([]uint64, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint64_tree/tree_v6_generated.go b/uint64_tree/tree_v6_generated.go index 6192b1b..5e9ce15 100644 --- a/uint64_tree/tree_v6_generated.go +++ b/uint64_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag uint64, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []uint64 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint64, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []uint64, nodeIndex uint) []uint64 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint64, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint64, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint64, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint64, address patricia.IPv6Address) []uint64 { var matchCount uint root := &t.nodes[1] - ret := make([]uint64, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint8_tree/tree_v4.go b/uint8_tree/tree_v4.go index 73e5c30..ac2fe85 100644 --- a/uint8_tree/tree_v4.go +++ b/uint8_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag uint8, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []uint8 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint8, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []uint8, nodeIndex uint) []uint8 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint8, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint8, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint8, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint8, address patricia.IPv4Address) []uint8 { var matchCount uint root := &t.nodes[1] - ret := make([]uint8, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint8, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint8_tree/tree_v6_generated.go b/uint8_tree/tree_v6_generated.go index dc00f89..5e9bd23 100644 --- a/uint8_tree/tree_v6_generated.go +++ b/uint8_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag uint8, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []uint8 { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint8, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []uint8, nodeIndex uint) []uint8 { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint8, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint8, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint8, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint8, address patricia.IPv6Address) []uint8 { var matchCount uint root := &t.nodes[1] - ret := make([]uint8, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint8, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint_tree/tree_v4.go b/uint_tree/tree_v4.go index 27b30c2..146b452 100644 --- a/uint_tree/tree_v4.go +++ b/uint_tree/tree_v4.go @@ -78,19 +78,26 @@ func (t *TreeV4) addTag(tag uint, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV4) tagsForNode(nodeIndex uint) []uint { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint, 0) } +} + +func (t *TreeV4) tagsForNodeAppend(ret []uint, nodeIndex uint) []uint { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint, address patricia.IPv4Address) []uint { var matchCount uint root := &t.nodes[1] - ret := make([]uint, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing diff --git a/uint_tree/tree_v6_generated.go b/uint_tree/tree_v6_generated.go index f4c1222..d8f9cff 100644 --- a/uint_tree/tree_v6_generated.go +++ b/uint_tree/tree_v6_generated.go @@ -78,19 +78,26 @@ func (t *TreeV6) addTag(tag uint, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } - func (t *TreeV6) tagsForNode(nodeIndex uint) []uint { - if nodeIndex == 0 { - // useful for base cases where we haven't found anything + if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { + return ret + } else { + // NB: for compatibility with the old tagsForNode() + // old comment: useful for base cases where we haven't found anything return make([]uint, 0) } +} + +func (t *TreeV6) tagsForNodeAppend(ret []uint, nodeIndex uint) []uint { + if nodeIndex == 0 { + return ret + } // TODO: clean up the typing in here, between uint, uint64 tagCount := t.nodes[nodeIndex].TagCount - ret := make([]uint, tagCount) key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret[i] = t.tags[key+uint64(i)] + ret = append(ret, t.tags[key+uint64(i)]) } return ret } @@ -525,19 +532,29 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } } -// FindTags finds all matching tags that passes the filter function +// FindTags finds all matching tags for given address func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint, error) { + if ret := t.FindTagsAppend(nil, address); ret != nil { + // NB: the nil error is for compatibility with the old FindTags() + return ret, nil + } else { + // NB: the alloc is for compatibility with the old FindTags() + return make([]uint, 0), nil + } +} + +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint, address patricia.IPv6Address) []uint { var matchCount uint root := &t.nodes[1] - ret := make([]uint, 0) if root.TagCount > 0 { - ret = append(ret, t.tagsForNode(1)...) + ret = t.tagsForNodeAppend(ret, 1) } if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,24 +569,24 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = append(ret, t.tagsForNode(nodeIndex)...) + ret = t.tagsForNodeAppend(ret, nodeIndex) } if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing From 97e9497eb68b58f47cd36932f97b3829432db49a Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Mon, 30 Aug 2021 18:54:12 +0000 Subject: [PATCH 03/19] Removed unnecessary error return values These errors were always nil - keep things clean --- template/tree_v4.go | 78 ++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/template/tree_v4.go b/template/tree_v4.go index 8a2a117..cf6d58e 100644 --- a/template/tree_v4.go +++ b/template/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag GeneratedType, matchFunc Mat // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag GeneratedType) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag GeneratedType) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag GeneratedType, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag GeneratedType, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal GeneratedType) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal GeneratedType) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]GeneratedType, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []GeneratedType { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]GeneratedType, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []GeneratedType { var matchCount uint root := &t.nodes[1] ret := make([]GeneratedType, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]GeneratedType, error) if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]GeneratedType, error) for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]GeneratedType, error) if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]GeneratedType, error) // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, GeneratedType, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, GeneratedType) { root := &t.nodes[1] var found bool var ret GeneratedType @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, GeneratedTy if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, GeneratedTy // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, GeneratedTy if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, GeneratedTy // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []GeneratedType, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []GeneratedType) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []Generate if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []Generate // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []Generate if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing From bef95ac2ca6e15feb0c549ee89e77a9af5704170 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Mon, 30 Aug 2021 18:58:55 +0000 Subject: [PATCH 04/19] Updated tests for no error returns --- template/tree_v4_bulk_test.go | 9 +- template/tree_v4_test.go | 275 ++++++++++++---------------------- 2 files changed, 97 insertions(+), 187 deletions(-) diff --git a/template/tree_v4_bulk_test.go b/template/tree_v4_bulk_test.go index 6d7f273..88cad4a 100644 --- a/template/tree_v4_bulk_test.go +++ b/template/tree_v4_bulk_test.go @@ -83,21 +83,18 @@ func TestBulkLoad(t *testing.T) { panic(fmt.Sprintf("search: Could not parse IP '%s': %s", address, err)) } if v4 != nil { - foundTags, err := tree.FindTags(*v4) - assert.NoError(t, err) + foundTags := tree.FindTags(*v4) if assert.True(t, len(foundTags) > 0, "Couldn't find tags for "+address) { assert.True(t, tag == foundTags[len(foundTags)-1]) } - found, foundTag, err := tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, foundTag := tree.FindDeepestTag(*v4) assert.True(t, found, "Couldn't find deepest tag") assert.True(t, tag == foundTag) // delete the tags now //fmt.Printf("Deleting %s: %s\n", address, tag) - deleteCount, err := tree.Delete(*v4, func(a GeneratedType, b GeneratedType) bool { return a == b }, tag) - assert.NoError(t, err) + deleteCount := tree.Delete(*v4, func(a GeneratedType, b GeneratedType) bool { return a == b }, tag) assert.Equal(t, 1, deleteCount, "Tried deleting tag") //tree.print() } else if v6 == nil { diff --git a/template/tree_v4_test.go b/template/tree_v4_test.go index cd0d5bc..9d512fc 100644 --- a/template/tree_v4_test.go +++ b/template/tree_v4_test.go @@ -142,105 +142,89 @@ func TestTree2(t *testing.T) { // -------- // now assert they're all found v4, _, _ = patricia.ParseIPFromString("188.212.216.242") - found, tag, err := tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag := tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "a", tag) v4, _, _ = patricia.ParseIPFromString("171.233.143.228") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "b", tag) v4, _, _ = patricia.ParseIPFromString("186.244.183.12") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "c", tag) v4, _, _ = patricia.ParseIPFromString("171.233.143.222") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "d", tag) v4, _, _ = patricia.ParseIPFromString("190.207.189.24") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "e", tag) v4, _, _ = patricia.ParseIPFromString("188.212.216.240") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "f", tag) v4, _, _ = patricia.ParseIPFromString("185.76.10.148") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "g", tag) v4, _, _ = patricia.ParseIPFromString("14.208.248.50") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "h", tag) v4, _, _ = patricia.ParseIPFromString("59.60.75.52") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "i", tag) v4, _, _ = patricia.ParseIPFromString("185.76.10.146") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "j", tag) v4, _, _ = patricia.ParseIPFromString("185.76.10.146") - found, tags, err := tree.FindDeepestTags(*v4) - assert.NoError(t, err) + found, tags := tree.FindDeepestTags(*v4) assert.True(t, found) assert.Equal(t, "j", tags[0]) assert.Equal(t, "k", tags[1]) // test searching for addresses with no leaf nodes v4, _, _ = patricia.ParseIPFromString("1.2.3.4") - found, tags, err = tree.FindDeepestTags(*v4) - assert.NoError(t, err) + found, tags = tree.FindDeepestTags(*v4) assert.True(t, found) assert.Equal(t, "foo", tags[0]) assert.Equal(t, "bar", tags[1]) v4, _, _ = patricia.ParseIPFromString("1.2.3.5") - found, tags, err = tree.FindDeepestTags(*v4) - assert.NoError(t, err) + found, tags = tree.FindDeepestTags(*v4) assert.True(t, found) assert.Equal(t, "foo", tags[0]) assert.Equal(t, "bar", tags[1]) v4, _, _ = patricia.ParseIPFromString("1.2.3.4") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "foo", tag) // test searching for an address that has nothing v4, _, _ = patricia.ParseIPFromString("9.9.9.9") - found, tags, err = tree.FindDeepestTags(*v4) - assert.NoError(t, err) + found, tags = tree.FindDeepestTags(*v4) assert.False(t, found) assert.NotNil(t, tags) assert.Equal(t, 0, len(tags)) // test searching for an empty address v4, _, _ = patricia.ParseIPFromString("9.9.9.9/0") - found, tags, err = tree.FindDeepestTags(*v4) - assert.NoError(t, err) + found, tags = tree.FindDeepestTags(*v4) assert.False(t, found) assert.NotNil(t, tags) assert.Equal(t, 0, len(tags)) @@ -252,16 +236,14 @@ func TestTree2(t *testing.T) { tree.Add(*v4, "root_node", nil) v4, _, _ = patricia.ParseIPFromString("9.9.9.9/0") - found, tags, err = tree.FindDeepestTags(*v4) - assert.NoError(t, err) + found, tags = tree.FindDeepestTags(*v4) assert.True(t, found) assert.NotNil(t, tags) assert.Equal(t, 1, len(tags)) assert.Equal(t, "root_node", tags[0]) v4, _, _ = patricia.ParseIPFromString("9.9.9.9/0") - found, tag, err = tree.FindDeepestTag(*v4) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "root_node", tag) } @@ -282,30 +264,26 @@ func TestAddressReusable(t *testing.T) { assert.Nil(t, v6) tree.Add(*v4, "Hello", nil) - found, tag, err := tree.FindDeepestTag(*v4) + found, tag := tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "Hello", tag) - assert.NoError(t, err) // search again with same address - found, tag, err = tree.FindDeepestTag(*v4) + found, tag = tree.FindDeepestTag(*v4) assert.True(t, found) assert.Equal(t, "Hello", tag) - assert.NoError(t, err) // search again with same address - tags, err := tree.FindTags(*v4) + tags := tree.FindTags(*v4) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Hello", tags[0]) } - assert.NoError(t, err) // search again with same address - tags, err = tree.FindTags(*v4) + tags = tree.FindTags(*v4) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Hello", tags[0]) } - assert.NoError(t, err) } func TestSimpleTree1(t *testing.T) { @@ -319,18 +297,15 @@ func TestSimpleTree1(t *testing.T) { tree.Add(ipv4b, "tagB", nil) tree.Add(ipv4c, "tagC", nil) - found, tag, err := tree.FindDeepestTag(ipv4FromBytes([]byte{98, 139, 183, 24}, 32)) - assert.NoError(t, err) + found, tag := tree.FindDeepestTag(ipv4FromBytes([]byte{98, 139, 183, 24}, 32)) assert.True(t, found) assert.Equal(t, "tagA", tag) - found, tag, err = tree.FindDeepestTag(ipv4FromBytes([]byte{198, 186, 190, 179}, 32)) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(ipv4FromBytes([]byte{198, 186, 190, 179}, 32)) assert.True(t, found) assert.Equal(t, "tagB", tag) - found, tag, err = tree.FindDeepestTag(ipv4FromBytes([]byte{151, 101, 124, 84}, 32)) - assert.NoError(t, err) + found, tag = tree.FindDeepestTag(ipv4FromBytes([]byte{151, 101, 124, 84}, 32)) assert.True(t, found) assert.Equal(t, "tagC", tag) } @@ -350,30 +325,26 @@ func TestSimpleTree2(t *testing.T) { tree.Add(*ipD, "D", nil) // find the 4 addresses - found, _, _ := tree.FindDeepestTag(*ipA) + found, _ := tree.FindDeepestTag(*ipA) assert.True(t, found) - found, _, _ = tree.FindDeepestTag(*ipB) + found, _ = tree.FindDeepestTag(*ipB) assert.True(t, found) - found, _, _ = tree.FindDeepestTag(*ipC) + found, _ = tree.FindDeepestTag(*ipC) assert.True(t, found) - found, _, _ = tree.FindDeepestTag(*ipD) + found, _ = tree.FindDeepestTag(*ipD) assert.True(t, found) // delete each one matchFunc := func(a GeneratedType, b GeneratedType) bool { return a == b } - deleteCount, err := tree.Delete(*ipA, matchFunc, "A") - assert.NoError(t, err) + deleteCount := tree.Delete(*ipA, matchFunc, "A") assert.Equal(t, 1, deleteCount) - deleteCount, err = tree.Delete(*ipB, matchFunc, "B") - assert.NoError(t, err) + deleteCount = tree.Delete(*ipB, matchFunc, "B") assert.Equal(t, 1, deleteCount) - deleteCount, err = tree.Delete(*ipC, matchFunc, "C") - assert.NoError(t, err) + deleteCount = tree.Delete(*ipC, matchFunc, "C") assert.Equal(t, 1, deleteCount) - deleteCount, err = tree.Delete(*ipD, matchFunc, "D") - assert.NoError(t, err) + deleteCount = tree.Delete(*ipD, matchFunc, "D") assert.Equal(t, 1, deleteCount) // should have zero logical nodes except for root @@ -384,63 +355,57 @@ func TestSimpleTree(t *testing.T) { tree := NewTreeV4() for i := 32; i > 0; i-- { - countIncreased, count, err := tree.Add(ipv4FromBytes([]byte{127, 0, 0, 1}, i), fmt.Sprintf("Tag-%d", i), nil) - assert.NoError(t, err) + countIncreased, count := tree.Add(ipv4FromBytes([]byte{127, 0, 0, 1}, i), fmt.Sprintf("Tag-%d", i), nil) assert.True(t, countIncreased) assert.Equal(t, 1, count) } - tags, err := tree.FindTags(ipv4FromBytes([]byte{127, 0, 0, 1}, 32)) - assert.NoError(t, err) + tags := tree.FindTags(ipv4FromBytes([]byte{127, 0, 0, 1}, 32)) if assert.Equal(t, 32, len(tags)) { assert.Equal(t, "Tag-32", tags[31].(string)) assert.Equal(t, "Tag-31", tags[30].(string)) } - tags, err = tree.FindTags(ipv4FromBytes([]byte{63, 3, 0, 1}, 32)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{63, 3, 0, 1}, 32)) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Tag-1", tags[0].(string)) } // find deepest tag: match at lowest level - found, tag, err := tree.FindDeepestTag(ipv4FromBytes([]byte{127, 0, 0, 1}, 32)) + found, tag := tree.FindDeepestTag(ipv4FromBytes([]byte{127, 0, 0, 1}, 32)) assert.True(t, found) if assert.NotNil(t, tag) { assert.Equal(t, "Tag-32", tag.(string)) } // find deepest tag: match at top level - found, tag, err = tree.FindDeepestTag(ipv4FromBytes([]byte{63, 5, 4, 3}, 32)) + found, tag = tree.FindDeepestTag(ipv4FromBytes([]byte{63, 5, 4, 3}, 32)) assert.True(t, found) if assert.NotNil(t, tag) { assert.Equal(t, "Tag-1", tag.(string)) } // find deepest tag: match at mid level - found, tag, err = tree.FindDeepestTag(ipv4FromBytes([]byte{119, 5, 4, 3}, 32)) + found, tag = tree.FindDeepestTag(ipv4FromBytes([]byte{119, 5, 4, 3}, 32)) assert.True(t, found) if assert.NotNil(t, tag) { assert.Equal(t, "Tag-4", tag.(string)) } // find deepest tag: no match - found, tag, err = tree.FindDeepestTag(ipv4FromBytes([]byte{128, 4, 3, 2}, 32)) + found, tag = tree.FindDeepestTag(ipv4FromBytes([]byte{128, 4, 3, 2}, 32)) assert.False(t, found) assert.Nil(t, tag) // Add a couple root tags - countIncreased, count, err := tree.Add(ipv4FromBytes([]byte{127, 0, 0, 1}, 0), "root1", nil) - assert.NoError(t, err) + countIncreased, count := tree.Add(ipv4FromBytes([]byte{127, 0, 0, 1}, 0), "root1", nil) assert.True(t, countIncreased) assert.Equal(t, 1, count) - countIncreased, count, err = tree.Add(patricia.IPv4Address{}, "root2", nil) - assert.NoError(t, err) + countIncreased, count = tree.Add(patricia.IPv4Address{}, "root2", nil) assert.True(t, countIncreased) assert.Equal(t, 2, count) - tags, err = tree.FindTags(patricia.IPv4Address{}) - assert.NoError(t, err) + tags = tree.FindTags(patricia.IPv4Address{}) if assert.Equal(t, 2, len(tags)) { assert.Equal(t, "root1", tags[0].(string)) assert.Equal(t, "root2", tags[1].(string)) @@ -481,23 +446,19 @@ func TestTree1FindTags(t *testing.T) { tree.Add(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags, err := tree.FindTags(ipv4FromBytes([]byte{128, 142, 133, 1}, 32)) - assert.NoError(t, err) + tags := tree.FindTags(ipv4FromBytes([]byte{128, 142, 133, 1}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagZ})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags, err = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // three tags in a hierarchy - get just the first - tags, err = tree.FindTags(ipv4FromBytes([]byte{162, 1, 0, 5}, 30)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{162, 1, 0, 5}, 30)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagZ})) // three tags in hierarchy - get none - tags, err = tree.FindTags(ipv4FromBytes([]byte{1, 0, 0, 0}, 1)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{1, 0, 0, 0}, 1)) assert.True(t, tagArraysEqual(tags, []string{tagZ})) } @@ -518,23 +479,19 @@ func TestTree1FindTagsWithFilter(t *testing.T) { tree.Add(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags, err := tree.FindTagsWithFilter(ipv4FromBytes([]byte{128, 142, 133, 1}, 32), filterFunc) - assert.NoError(t, err) + tags := tree.FindTagsWithFilter(ipv4FromBytes([]byte{128, 142, 133, 1}, 32), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags, err = tree.FindTagsWithFilter(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), filterFunc) - assert.NoError(t, err) + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - get just the first - tags, err = tree.FindTagsWithFilter(ipv4FromBytes([]byte{162, 1, 0, 5}, 30), filterFunc) - assert.NoError(t, err) + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{162, 1, 0, 5}, 30), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagB})) // three tags in hierarchy - get none - tags, err = tree.FindTagsWithFilter(ipv4FromBytes([]byte{1, 0, 0, 0}, 1), filterFunc) - assert.NoError(t, err) + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{1, 0, 0, 0}, 1), filterFunc) assert.Zero(t, len(tags)) } @@ -553,31 +510,26 @@ func TestRootNode(t *testing.T) { tree.Add(patricia.IPv4Address{}, tagB, nil) // query the root node with no address - tags, err := tree.FindTags(patricia.IPv4Address{}) - assert.NoError(t, err) + tags := tree.FindTags(patricia.IPv4Address{}) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // query a node that doesn't exist - tags, err = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // create a new /16 node with C & D tree.Add(ipv4FromBytes([]byte{1, 2, 3, 4}, 16), tagC, nil) tree.Add(ipv4FromBytes([]byte{1, 2, 3, 4}, 16), tagD, nil) - tags, err = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 16)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 16)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) // create a node under the /16 node tree.Add(ipv4FromBytes([]byte{1, 2, 3, 4}, 32), tagZ, nil) - tags, err = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD, tagZ})) // check the /24 and make sure we still get the /16 and root - tags, err = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 24)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 24)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) } @@ -586,18 +538,15 @@ func TestAdd(t *testing.T) { address := ipv4FromBytes([]byte{1, 2, 3, 4}, 32) tree := NewTreeV4() - countIncreased, count, err := tree.Add(address, "hi", nil) - assert.NoError(t, err) + countIncreased, count := tree.Add(address, "hi", nil) assert.True(t, countIncreased) assert.Equal(t, 1, count) - countIncreased, count, err = tree.Add(address, "hi", nil) - assert.NoError(t, err) + countIncreased, count = tree.Add(address, "hi", nil) assert.True(t, countIncreased) assert.Equal(t, 2, count) - countIncreased, count, err = tree.Add(address, "hi", nil) - assert.NoError(t, err) + countIncreased, count = tree.Add(address, "hi", nil) assert.True(t, countIncreased) assert.Equal(t, 3, count) } @@ -609,56 +558,44 @@ func TestSet(t *testing.T) { tree := NewTreeV4() // add a parent node, just to mix things up - countIncreased, count, err := tree.Set(ipv4FromBytes([]byte{1, 2, 3, 0}, 24), "parent") - assert.NoError(t, err) - assert.True(t, countIncreased) + countIncreased, count := tree.Set(ipv4FromBytes([]byte{1, 2, 3, 0}, 24), "parent") assert.Equal(t, 1, count) - countIncreased, count, err = tree.Set(address, "tagA") - assert.NoError(t, err) + countIncreased, count = tree.Set(address, "tagA") assert.True(t, countIncreased) assert.Equal(t, 1, count) - found, tag, err := tree.FindDeepestTag(address) + found, tag := tree.FindDeepestTag(address) assert.True(t, found) - assert.NoError(t, err) assert.Equal(t, "tagA", tag) - countIncreased, count, err = tree.Set(address, "tagB") + countIncreased, count = tree.Set(address, "tagB") assert.Equal(t, 1, count) assert.False(t, countIncreased) - assert.NoError(t, err) - found, tag, err = tree.FindDeepestTag(address) + found, tag = tree.FindDeepestTag(address) assert.True(t, found) - assert.NoError(t, err) assert.Equal(t, "tagB", tag) - countIncreased, count, err = tree.Set(address, "tagC") + countIncreased, count = tree.Set(address, "tagC") assert.Equal(t, 1, count) assert.False(t, countIncreased) - assert.NoError(t, err) - found, tag, err = tree.FindDeepestTag(address) + found, tag = tree.FindDeepestTag(address) assert.True(t, found) - assert.NoError(t, err) assert.Equal(t, "tagC", tag) - countIncreased, count, err = tree.Set(address, "tagD") + countIncreased, count = tree.Set(address, "tagD") assert.Equal(t, 1, count) assert.False(t, countIncreased) - assert.NoError(t, err) - found, tag, err = tree.FindDeepestTag(address) + found, tag = tree.FindDeepestTag(address) assert.True(t, found) - assert.NoError(t, err) assert.Equal(t, "tagD", tag) // now delete the tag - delCount, err := tree.Delete(address, func(a GeneratedType, b GeneratedType) bool { return true }, "") + delCount := tree.Delete(address, func(a GeneratedType, b GeneratedType) bool { return true }, "") assert.Equal(t, 1, delCount) - assert.NoError(t, err) // verify it's gone - should get the parent - found, tag, err = tree.FindDeepestTag(address) + found, tag = tree.FindDeepestTag(address) assert.True(t, found) - assert.NoError(t, err) assert.Equal(t, "parent", tag) } @@ -699,51 +636,43 @@ func TestDelete1(t *testing.T) { assert.Equal(t, "tagC", tree.tagsForNode(4)[0]) // three tags in a hierarchy - ask for an exact match, receive all 3 and the root - tags, err := tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) - assert.NoError(t, err) + tags := tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // 1. delete a tag that doesn't exist count := 0 - count, err = tree.Delete(ipv4FromBytes([]byte{9, 9, 9, 9}, 32), matchFunc, "bad tag") - assert.NoError(t, err) + count = tree.Delete(ipv4FromBytes([]byte{9, 9, 9, 9}, 32), matchFunc, "bad tag") assert.Equal(t, 0, count) assert.Equal(t, 4, tree.countNodes(1)) assert.Equal(t, 4, tree.countTags(1)) // 2. delete a tag on an address that exists, but doesn't have the tag - count, err = tree.Delete(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "bad tag") + count = tree.Delete(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "bad tag") assert.Equal(t, 0, count) - assert.NoError(t, err) // verify - tags, err = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) assert.Equal(t, 4, tree.countNodes(1)) assert.Equal(t, 4, tree.countTags(1)) // 3. delete the default/root tag - count, err = tree.Delete(ipv4FromBytes([]byte{0, 0, 0, 0}, 0), matchFunc, "tagZ") - assert.NoError(t, err) + count = tree.Delete(ipv4FromBytes([]byte{0, 0, 0, 0}, 0), matchFunc, "tagZ") assert.Equal(t, 1, count) assert.Equal(t, 4, tree.countNodes(1)) // doesn't delete anything assert.Equal(t, 3, tree.countTags(1)) assert.Equal(t, 0, len(tree.availableIndexes)) // three tags in a hierarchy - ask for an exact match, receive all 3, not the root, which we deleted - tags, err = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC})) // 4. delete tagA - count, err = tree.Delete(ipv4FromBytes([]byte{128, 0, 0, 0}, 7), matchFunc, "tagA") - assert.NoError(t, err) + count = tree.Delete(ipv4FromBytes([]byte{128, 0, 0, 0}, 7), matchFunc, "tagA") assert.Equal(t, 1, count) // verify - tags, err = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagC})) assert.Equal(t, 3, tree.countNodes(1)) assert.Equal(t, 2, tree.countTags(1)) @@ -751,13 +680,11 @@ func TestDelete1(t *testing.T) { assert.Equal(t, uint(2), tree.availableIndexes[0]) // 5. delete tag B - count, err = tree.Delete(ipv4FromBytes([]byte{128, 0, 0, 0}, 2), matchFunc, "tagB") - assert.NoError(t, err) + count = tree.Delete(ipv4FromBytes([]byte{128, 0, 0, 0}, 2), matchFunc, "tagB") assert.Equal(t, 1, count) // verify - tags, err = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagC})) assert.Equal(t, 2, tree.countNodes(1)) assert.Equal(t, 1, tree.countTags(1)) @@ -776,13 +703,11 @@ func TestDelete1(t *testing.T) { assert.Equal(t, "tagE", tree.tagsForNode(3)[0]) // 6. delete tag C - count, err = tree.Delete(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "tagC") - assert.NoError(t, err) + count = tree.Delete(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "tagC") assert.Equal(t, 1, count) // verify - tags, err = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) - assert.NoError(t, err) + tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{})) assert.Equal(t, 2, tree.countNodes(1)) assert.Equal(t, 2, tree.countTags(1)) @@ -838,27 +763,23 @@ func TestDuplicateTagsWithNoMatchFunc(t *testing.T) { tree := NewTreeV4() - wasAdded, count, err := tree.Add(patricia.IPv4Address{}, "FOO", matchFunc) // default + wasAdded, count := tree.Add(patricia.IPv4Address{}, "FOO", matchFunc) // default assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) - wasAdded, count, err = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) // add another at previous node - wasAdded, count, err = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "FOOBAR", matchFunc) + wasAdded, count = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "FOOBAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 2, count) - assert.NoError(t, err) // add a dupe to the previous node - will be fine since match is nil - wasAdded, count, err = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 3, count) - assert.NoError(t, err) } // test duplicate tags with match func that always returns false @@ -869,27 +790,23 @@ func TestDuplicateTagsWithFalseMatchFunc(t *testing.T) { tree := NewTreeV4() - wasAdded, count, err := tree.Add(patricia.IPv4Address{}, "FOO", matchFunc) // default + wasAdded, count := tree.Add(patricia.IPv4Address{}, "FOO", matchFunc) // default assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) - wasAdded, count, err = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) // add another at previous node - wasAdded, count, err = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "FOOBAR", matchFunc) + wasAdded, count = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "FOOBAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 2, count) - assert.NoError(t, err) // add a dupe to the previous node - will be fine since match is nil - wasAdded, count, err = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 3, count) - assert.NoError(t, err) } // test duplicate tags with match func that does something @@ -900,27 +817,23 @@ func TestDuplicateTagsWithMatchFunc(t *testing.T) { tree := NewTreeV4() - wasAdded, count, err := tree.Add(patricia.IPv4Address{}, "FOO", matchFunc) // default + wasAdded, count := tree.Add(patricia.IPv4Address{}, "FOO", matchFunc) // default assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) - wasAdded, count, err = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) // add another at previous node - wasAdded, count, err = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "FOOBAR", matchFunc) + wasAdded, count = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "FOOBAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 2, count) - assert.NoError(t, err) // add a dupe to the previous node - will be fine since match is nil - wasAdded, count, err = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), "BAR", matchFunc) assert.False(t, wasAdded) assert.Equal(t, 2, count) - assert.NoError(t, err) } func payloadToByteArrays(tags []GeneratedType) [][]byte { From 9c3118adfde0cde636201be1dc6a64f9e5cb1da3 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Mon, 30 Aug 2021 19:00:12 +0000 Subject: [PATCH 05/19] Code gen --- bool_tree/tree_v4.go | 78 ++++++++++++++-------------- bool_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- byte_tree/tree_v4.go | 78 ++++++++++++++-------------- byte_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- complex128_tree/tree_v4.go | 78 ++++++++++++++-------------- complex128_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- complex64_tree/tree_v4.go | 78 ++++++++++++++-------------- complex64_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- float32_tree/tree_v4.go | 78 ++++++++++++++-------------- float32_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- float64_tree/tree_v4.go | 78 ++++++++++++++-------------- float64_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- int16_tree/tree_v4.go | 78 ++++++++++++++-------------- int16_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- int32_tree/tree_v4.go | 78 ++++++++++++++-------------- int32_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- int64_tree/tree_v4.go | 78 ++++++++++++++-------------- int64_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- int8_tree/tree_v4.go | 78 ++++++++++++++-------------- int8_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- int_tree/tree_v4.go | 78 ++++++++++++++-------------- int_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- rune_tree/tree_v4.go | 78 ++++++++++++++-------------- rune_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- string_tree/tree_v4.go | 78 ++++++++++++++-------------- string_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- template/tree_v6_generated.go | 78 ++++++++++++++-------------- uint16_tree/tree_v4.go | 78 ++++++++++++++-------------- uint16_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- uint32_tree/tree_v4.go | 78 ++++++++++++++-------------- uint32_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- uint64_tree/tree_v4.go | 78 ++++++++++++++-------------- uint64_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- uint8_tree/tree_v4.go | 78 ++++++++++++++-------------- uint8_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- uint_tree/tree_v4.go | 78 ++++++++++++++-------------- uint_tree/tree_v6_generated.go | 78 ++++++++++++++-------------- 37 files changed, 1443 insertions(+), 1443 deletions(-) diff --git a/bool_tree/tree_v4.go b/bool_tree/tree_v4.go index a58f404..59db323 100644 --- a/bool_tree/tree_v4.go +++ b/bool_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag bool, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag bool) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag bool) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag bool, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag bool, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal bool) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal bool) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]bool, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []bool { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]bool, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []bool { var matchCount uint root := &t.nodes[1] ret := make([]bool, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]bool, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]bool, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]bool, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]bool, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, bool, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, bool) { root := &t.nodes[1] var found bool var ret bool @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, bool, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, bool, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, bool, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, bool, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/bool_tree/tree_v6_generated.go b/bool_tree/tree_v6_generated.go index 3fca655..ad26812 100644 --- a/bool_tree/tree_v6_generated.go +++ b/bool_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag bool, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag bool) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag bool) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag bool, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag bool, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal bool) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal bool) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]bool, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []bool { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]bool, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []bool { var matchCount uint root := &t.nodes[1] ret := make([]bool, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]bool, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]bool, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]bool, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]bool, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, bool, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, bool) { root := &t.nodes[1] var found bool var ret bool @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, bool, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, bool, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, bool, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, bool, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/byte_tree/tree_v4.go b/byte_tree/tree_v4.go index dabafb1..f28be9c 100644 --- a/byte_tree/tree_v4.go +++ b/byte_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag byte, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag byte) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag byte) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag byte, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag byte, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal byte) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal byte) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]byte, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []byte { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]byte, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []byte { var matchCount uint root := &t.nodes[1] ret := make([]byte, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]byte, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]byte, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]byte, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]byte, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, byte, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, byte) { root := &t.nodes[1] var found bool var ret byte @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, byte, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, byte, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, byte, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, byte, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/byte_tree/tree_v6_generated.go b/byte_tree/tree_v6_generated.go index 4dcd120..0a0ae4a 100644 --- a/byte_tree/tree_v6_generated.go +++ b/byte_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag byte, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag byte) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag byte) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag byte, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag byte, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal byte) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal byte) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]byte, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []byte { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]byte, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []byte { var matchCount uint root := &t.nodes[1] ret := make([]byte, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]byte, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]byte, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]byte, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]byte, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, byte, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, byte) { root := &t.nodes[1] var found bool var ret byte @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, byte, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, byte, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, byte, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, byte, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/complex128_tree/tree_v4.go b/complex128_tree/tree_v4.go index faa38d3..7952ab2 100644 --- a/complex128_tree/tree_v4.go +++ b/complex128_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag complex128, matchFunc Matche // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag complex128) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag complex128) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag complex128, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag complex128, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex128) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex128) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]complex128, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []complex128 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex128, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []complex128 { var matchCount uint root := &t.nodes[1] ret := make([]complex128, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex128, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex128, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex128, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex128, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex128, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex128) { root := &t.nodes[1] var found bool var ret complex128 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex128, if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex128, // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex128, if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex128, // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex128, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex128) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex1 if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex1 // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex1 if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/complex128_tree/tree_v6_generated.go b/complex128_tree/tree_v6_generated.go index a0eaa06..4ade956 100644 --- a/complex128_tree/tree_v6_generated.go +++ b/complex128_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag complex128, matchFunc Matche // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag complex128) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag complex128) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag complex128, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag complex128, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex128) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex128) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]complex128, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []complex128 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex128, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []complex128 { var matchCount uint root := &t.nodes[1] ret := make([]complex128, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex128, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex128, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex128, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex128, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex128, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex128) { root := &t.nodes[1] var found bool var ret complex128 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex128, if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex128, // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex128, if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex128, // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex128, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex128) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex1 if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex1 // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex1 if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/complex64_tree/tree_v4.go b/complex64_tree/tree_v4.go index 7b52e42..63fcfad 100644 --- a/complex64_tree/tree_v4.go +++ b/complex64_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag complex64, matchFunc Matches // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag complex64) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag complex64) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag complex64, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag complex64, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex64) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]complex64, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []complex64 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex64, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []complex64 { var matchCount uint root := &t.nodes[1] ret := make([]complex64, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex64, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex64, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]complex64, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex64, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex64) { root := &t.nodes[1] var found bool var ret complex64 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex64, if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex64, // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex64, if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex64, // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex64, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex64) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex6 if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex6 // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex6 if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/complex64_tree/tree_v6_generated.go b/complex64_tree/tree_v6_generated.go index 201c9af..071145e 100644 --- a/complex64_tree/tree_v6_generated.go +++ b/complex64_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag complex64, matchFunc Matches // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag complex64) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag complex64) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag complex64, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag complex64, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex64) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]complex64, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []complex64 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex64, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []complex64 { var matchCount uint root := &t.nodes[1] ret := make([]complex64, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex64, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex64, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]complex64, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex64, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex64) { root := &t.nodes[1] var found bool var ret complex64 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex64, if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex64, // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex64, if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex64, // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex64, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex64) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex6 if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex6 // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex6 if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/float32_tree/tree_v4.go b/float32_tree/tree_v4.go index 17fb3ac..db50284 100644 --- a/float32_tree/tree_v4.go +++ b/float32_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag float32, matchFunc MatchesFu // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag float32) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag float32) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag float32, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag float32, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float32) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]float32, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []float32 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float32, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []float32 { var matchCount uint root := &t.nodes[1] ret := make([]float32, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float32, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float32, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float32, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float32, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float32) { root := &t.nodes[1] var found bool var ret float32 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float32, er if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float32, er // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float32, er if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float32, er // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/float32_tree/tree_v6_generated.go b/float32_tree/tree_v6_generated.go index a002105..7457b3e 100644 --- a/float32_tree/tree_v6_generated.go +++ b/float32_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag float32, matchFunc MatchesFu // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag float32) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag float32) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag float32, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag float32, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float32) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]float32, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []float32 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float32, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []float32 { var matchCount uint root := &t.nodes[1] ret := make([]float32, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float32, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float32, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float32, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float32, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float32) { root := &t.nodes[1] var found bool var ret float32 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float32, er if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float32, er // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float32, er if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float32, er // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/float64_tree/tree_v4.go b/float64_tree/tree_v4.go index 9a765c3..643d93b 100644 --- a/float64_tree/tree_v4.go +++ b/float64_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag float64, matchFunc MatchesFu // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag float64) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag float64) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag float64, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag float64, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float64) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]float64, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []float64 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float64, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []float64 { var matchCount uint root := &t.nodes[1] ret := make([]float64, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float64, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float64, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]float64, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float64, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float64) { root := &t.nodes[1] var found bool var ret float64 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float64, er if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float64, er // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float64, er if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float64, er // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/float64_tree/tree_v6_generated.go b/float64_tree/tree_v6_generated.go index b95c952..872300e 100644 --- a/float64_tree/tree_v6_generated.go +++ b/float64_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag float64, matchFunc MatchesFu // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag float64) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag float64) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag float64, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag float64, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float64) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]float64, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []float64 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float64, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []float64 { var matchCount uint root := &t.nodes[1] ret := make([]float64, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float64, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float64, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]float64, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float64, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float64) { root := &t.nodes[1] var found bool var ret float64 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float64, er if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float64, er // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float64, er if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float64, er // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int16_tree/tree_v4.go b/int16_tree/tree_v4.go index 445b1d1..1336f78 100644 --- a/int16_tree/tree_v4.go +++ b/int16_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int16, matchFunc MatchesFunc // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag int16) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag int16) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag int16, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag int16, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int16) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]int16, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int16 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int16, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int16 { var matchCount uint root := &t.nodes[1] ret := make([]int16, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int16, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int16, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int16, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int16, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int16, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int16) { root := &t.nodes[1] var found bool var ret int16 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int16, erro if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int16, erro // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int16, erro if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int16, erro // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16, e if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16, e // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16, e if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int16_tree/tree_v6_generated.go b/int16_tree/tree_v6_generated.go index c1ef07b..c195f44 100644 --- a/int16_tree/tree_v6_generated.go +++ b/int16_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int16, matchFunc MatchesFunc // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag int16) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag int16) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag int16, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag int16, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int16) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]int16, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int16 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int16, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int16 { var matchCount uint root := &t.nodes[1] ret := make([]int16, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int16, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int16, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int16, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int16, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int16, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int16) { root := &t.nodes[1] var found bool var ret int16 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int16, erro if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int16, erro // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int16, erro if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int16, erro // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16, e if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16, e // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16, e if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int32_tree/tree_v4.go b/int32_tree/tree_v4.go index f33f37d..670ac97 100644 --- a/int32_tree/tree_v4.go +++ b/int32_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int32, matchFunc MatchesFunc // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag int32) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag int32) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag int32, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag int32, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int32) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]int32, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int32 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int32, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int32 { var matchCount uint root := &t.nodes[1] ret := make([]int32, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int32, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int32, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int32, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int32, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int32) { root := &t.nodes[1] var found bool var ret int32 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int32, erro if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int32, erro // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int32, erro if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int32, erro // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32, e if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32, e // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32, e if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int32_tree/tree_v6_generated.go b/int32_tree/tree_v6_generated.go index 0512284..20a6db4 100644 --- a/int32_tree/tree_v6_generated.go +++ b/int32_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int32, matchFunc MatchesFunc // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag int32) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag int32) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag int32, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag int32, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int32) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]int32, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int32 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int32, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int32 { var matchCount uint root := &t.nodes[1] ret := make([]int32, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int32, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int32, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int32, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int32, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int32) { root := &t.nodes[1] var found bool var ret int32 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int32, erro if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int32, erro // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int32, erro if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int32, erro // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32, e if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32, e // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32, e if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int64_tree/tree_v4.go b/int64_tree/tree_v4.go index 18358e6..ca70515 100644 --- a/int64_tree/tree_v4.go +++ b/int64_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int64, matchFunc MatchesFunc // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag int64) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag int64) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag int64, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag int64, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int64) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]int64, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int64 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int64, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int64 { var matchCount uint root := &t.nodes[1] ret := make([]int64, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int64, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int64, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int64, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int64, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int64) { root := &t.nodes[1] var found bool var ret int64 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int64, erro if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int64, erro // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int64, erro if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int64, erro // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64, e if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64, e // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64, e if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int64_tree/tree_v6_generated.go b/int64_tree/tree_v6_generated.go index 21ffa67..162739d 100644 --- a/int64_tree/tree_v6_generated.go +++ b/int64_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int64, matchFunc MatchesFunc // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag int64) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag int64) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag int64, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag int64, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int64) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]int64, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int64 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int64, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int64 { var matchCount uint root := &t.nodes[1] ret := make([]int64, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int64, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int64, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int64, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int64, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int64) { root := &t.nodes[1] var found bool var ret int64 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int64, erro if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int64, erro // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int64, erro if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int64, erro // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64, e if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64, e // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64, e if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int8_tree/tree_v4.go b/int8_tree/tree_v4.go index 2f53e24..35710f3 100644 --- a/int8_tree/tree_v4.go +++ b/int8_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int8, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag int8) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag int8) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag int8, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag int8, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int8) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]int8, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int8 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int8, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int8 { var matchCount uint root := &t.nodes[1] ret := make([]int8, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int8, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int8, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int8, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int8, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int8, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int8) { root := &t.nodes[1] var found bool var ret int8 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int8, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int8, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int8, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int8, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int8_tree/tree_v6_generated.go b/int8_tree/tree_v6_generated.go index 681aafd..49ed95e 100644 --- a/int8_tree/tree_v6_generated.go +++ b/int8_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int8, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag int8) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag int8) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag int8, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag int8, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int8) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]int8, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int8 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int8, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int8 { var matchCount uint root := &t.nodes[1] ret := make([]int8, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int8, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int8, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int8, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int8, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int8, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int8) { root := &t.nodes[1] var found bool var ret int8 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int8, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int8, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int8, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int8, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int_tree/tree_v4.go b/int_tree/tree_v4.go index cc4d96f..8c5e338 100644 --- a/int_tree/tree_v4.go +++ b/int_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag int) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag int) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag int, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag int, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]int, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int { var matchCount uint root := &t.nodes[1] ret := make([]int, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]int, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int) { root := &t.nodes[1] var found bool var ret int @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int, error) if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int, error) // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int, error) if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int, error) // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int, err if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int, err // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int, err if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/int_tree/tree_v6_generated.go b/int_tree/tree_v6_generated.go index 2ce9c46..51c0ca3 100644 --- a/int_tree/tree_v6_generated.go +++ b/int_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag int) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag int) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag int, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag int, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]int, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int { var matchCount uint root := &t.nodes[1] ret := make([]int, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]int, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int) { root := &t.nodes[1] var found bool var ret int @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int, error) if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int, error) // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int, error) if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int, error) // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int, err if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int, err // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int, err if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/rune_tree/tree_v4.go b/rune_tree/tree_v4.go index 4ee7ebf..cef64f1 100644 --- a/rune_tree/tree_v4.go +++ b/rune_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag rune, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag rune) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag rune) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag rune, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag rune, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal rune) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal rune) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]rune, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []rune { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]rune, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []rune { var matchCount uint root := &t.nodes[1] ret := make([]rune, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]rune, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]rune, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]rune, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]rune, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, rune, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, rune) { root := &t.nodes[1] var found bool var ret rune @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, rune, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, rune, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, rune, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, rune, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/rune_tree/tree_v6_generated.go b/rune_tree/tree_v6_generated.go index 54d79c6..accf43e 100644 --- a/rune_tree/tree_v6_generated.go +++ b/rune_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag rune, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag rune) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag rune) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag rune, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag rune, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal rune) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal rune) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]rune, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []rune { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]rune, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []rune { var matchCount uint root := &t.nodes[1] ret := make([]rune, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]rune, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]rune, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]rune, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]rune, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, rune, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, rune) { root := &t.nodes[1] var found bool var ret rune @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, rune, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, rune, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, rune, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, rune, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/string_tree/tree_v4.go b/string_tree/tree_v4.go index 8ae1eaa..6f4fe9b 100644 --- a/string_tree/tree_v4.go +++ b/string_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag string, matchFunc MatchesFun // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag string) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag string) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag string, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag string, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal string) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal string) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]string, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []string { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]string, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []string { var matchCount uint root := &t.nodes[1] ret := make([]string, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]string, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]string, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]string, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]string, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, string, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, string) { root := &t.nodes[1] var found bool var ret string @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, string, err if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, string, err // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, string, err if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, string, err // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/string_tree/tree_v6_generated.go b/string_tree/tree_v6_generated.go index dd19a73..1edc5af 100644 --- a/string_tree/tree_v6_generated.go +++ b/string_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag string, matchFunc MatchesFun // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag string) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag string) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag string, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag string, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal string) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal string) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]string, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []string { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]string, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []string { var matchCount uint root := &t.nodes[1] ret := make([]string, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]string, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]string, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]string, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]string, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, string, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, string) { root := &t.nodes[1] var found bool var ret string @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, string, err if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, string, err // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, string, err if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, string, err // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/template/tree_v6_generated.go b/template/tree_v6_generated.go index 602e018..917751e 100644 --- a/template/tree_v6_generated.go +++ b/template/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag GeneratedType, matchFunc Mat // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag GeneratedType) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag GeneratedType) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag GeneratedType, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag GeneratedType, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal GeneratedType) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal GeneratedType) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]GeneratedType, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []GeneratedType { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]GeneratedType, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []GeneratedType { var matchCount uint root := &t.nodes[1] ret := make([]GeneratedType, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]GeneratedType, error) if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]GeneratedType, error) for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]GeneratedType, error) if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]GeneratedType, error) // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, GeneratedType, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, GeneratedType) { root := &t.nodes[1] var found bool var ret GeneratedType @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, GeneratedTy if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, GeneratedTy // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, GeneratedTy if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, GeneratedTy // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []GeneratedType, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []GeneratedType) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []Generate if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []Generate // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []Generate if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v4.go b/uint16_tree/tree_v4.go index a60d4dc..88de0e1 100644 --- a/uint16_tree/tree_v4.go +++ b/uint16_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint16, matchFunc MatchesFun // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag uint16) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag uint16) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag uint16, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag uint16, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint16) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]uint16, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint16 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint16, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint16 { var matchCount uint root := &t.nodes[1] ret := make([]uint16, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint16, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint16, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint16, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint16, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint16, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint16) { root := &t.nodes[1] var found bool var ret uint16 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint16, err if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint16, err // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint16, err if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint16, err // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v6_generated.go b/uint16_tree/tree_v6_generated.go index db87aa8..efc35e3 100644 --- a/uint16_tree/tree_v6_generated.go +++ b/uint16_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint16, matchFunc MatchesFun // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag uint16) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag uint16) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag uint16, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag uint16, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint16) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]uint16, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint16 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint16, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint16 { var matchCount uint root := &t.nodes[1] ret := make([]uint16, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint16, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint16, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint16, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint16, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint16, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint16) { root := &t.nodes[1] var found bool var ret uint16 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint16, err if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint16, err // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint16, err if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint16, err // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint32_tree/tree_v4.go b/uint32_tree/tree_v4.go index 3de8bf6..debbeb0 100644 --- a/uint32_tree/tree_v4.go +++ b/uint32_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint32, matchFunc MatchesFun // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag uint32) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag uint32) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag uint32, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag uint32, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint32) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]uint32, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint32 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint32, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint32 { var matchCount uint root := &t.nodes[1] ret := make([]uint32, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint32, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint32, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint32, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint32, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint32) { root := &t.nodes[1] var found bool var ret uint32 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint32, err if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint32, err // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint32, err if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint32, err // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint32_tree/tree_v6_generated.go b/uint32_tree/tree_v6_generated.go index 871992e..3940394 100644 --- a/uint32_tree/tree_v6_generated.go +++ b/uint32_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint32, matchFunc MatchesFun // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag uint32) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag uint32) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag uint32, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag uint32, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint32) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]uint32, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint32 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint32, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint32 { var matchCount uint root := &t.nodes[1] ret := make([]uint32, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint32, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint32, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint32, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint32, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint32, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint32) { root := &t.nodes[1] var found bool var ret uint32 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint32, err if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint32, err // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint32, err if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint32, err // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint64_tree/tree_v4.go b/uint64_tree/tree_v4.go index adf8639..1f4f15b 100644 --- a/uint64_tree/tree_v4.go +++ b/uint64_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint64, matchFunc MatchesFun // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag uint64) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag uint64) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag uint64, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag uint64, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint64) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]uint64, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint64 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint64, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint64 { var matchCount uint root := &t.nodes[1] ret := make([]uint64, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint64, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint64, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint64, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint64, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint64) { root := &t.nodes[1] var found bool var ret uint64 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint64, err if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint64, err // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint64, err if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint64, err // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint64_tree/tree_v6_generated.go b/uint64_tree/tree_v6_generated.go index 6192b1b..0a59dfa 100644 --- a/uint64_tree/tree_v6_generated.go +++ b/uint64_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint64, matchFunc MatchesFun // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag uint64) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag uint64) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag uint64, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag uint64, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint64) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]uint64, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint64 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint64, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint64 { var matchCount uint root := &t.nodes[1] ret := make([]uint64, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint64, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint64, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint64, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint64, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint64, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint64) { root := &t.nodes[1] var found bool var ret uint64 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint64, err if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint64, err // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint64, err if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint64, err // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64, if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64, // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64, if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint8_tree/tree_v4.go b/uint8_tree/tree_v4.go index 73e5c30..0f1312c 100644 --- a/uint8_tree/tree_v4.go +++ b/uint8_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint8, matchFunc MatchesFunc // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag uint8) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag uint8) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag uint8, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag uint8, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint8) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]uint8, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint8 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint8, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint8 { var matchCount uint root := &t.nodes[1] ret := make([]uint8, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint8, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint8, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint8, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint8, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint8, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint8) { root := &t.nodes[1] var found bool var ret uint8 @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint8, erro if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint8, erro // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint8, erro if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint8, erro // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8, e if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8, e // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8, e if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint8_tree/tree_v6_generated.go b/uint8_tree/tree_v6_generated.go index dc00f89..282e048 100644 --- a/uint8_tree/tree_v6_generated.go +++ b/uint8_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint8, matchFunc MatchesFunc // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag uint8) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag uint8) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag uint8, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag uint8, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint8) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]uint8, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint8 { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint8, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint8 { var matchCount uint root := &t.nodes[1] ret := make([]uint8, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint8, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint8, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint8, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint8, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint8, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint8) { root := &t.nodes[1] var found bool var ret uint8 @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint8, erro if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint8, erro // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint8, erro if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint8, erro // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8, e if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8, e // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8, e if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint_tree/tree_v4.go b/uint_tree/tree_v4.go index 27b30c2..0cf1fdc 100644 --- a/uint_tree/tree_v4.go +++ b/uint_tree/tree_v4.go @@ -141,21 +141,21 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Set(address patricia.IPv4Address, tag uint) (bool, int, error) { +func (t *TreeV4) Set(address patricia.IPv4Address, tag uint) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV4) Add(address patricia.IPv4Address, tag uint, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV4) Add(address patricia.IPv4Address, tag uint, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV4, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint) (int, error) { +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) ([]uint, error) { +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint, error) { +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint { var matchCount uint root := &t.nodes[1] ret := make([]uint, 0) @@ -537,7 +537,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) ([]uint, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint, error) { +func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint) { root := &t.nodes[1] var found bool var ret uint @@ -596,7 +596,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint, error) { +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing diff --git a/uint_tree/tree_v6_generated.go b/uint_tree/tree_v6_generated.go index f4c1222..e43fea8 100644 --- a/uint_tree/tree_v6_generated.go +++ b/uint_tree/tree_v6_generated.go @@ -141,21 +141,21 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint, matchFunc MatchesFunc) // Set the single value for a node - overwrites what's there // Returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Set(address patricia.IPv6Address, tag uint) (bool, int, error) { +func (t *TreeV6) Set(address patricia.IPv6Address, tag uint) (bool, int) { return t.add(address, tag, nil, true) } // Add adds a tag to the tree // - if matchFunc is non-nil, it will be used to ensure uniqueness at this node // - returns whether the tag count at this address was increased, and how many tags at this address -func (t *TreeV6) Add(address patricia.IPv6Address, tag uint, matchFunc MatchesFunc) (bool, int, error) { +func (t *TreeV6) Add(address patricia.IPv6Address, tag uint, matchFunc MatchesFunc) (bool, int) { return t.add(address, tag, matchFunc, false) } // add a tag to the tree, optionally as the single value // - overwrites the first value in the list if 'replaceFirst' is true // - returns whether the tag count was increased, and the number of tags at this address -func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFunc, replaceFirst bool) (bool, int, error) { +func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFunc, replaceFirst bool) (bool, int) { // make sure we have more than enough capacity before we start adding to the tree, which invalidates pointers into the array if (len(t.availableIndexes) + cap(t.nodes)) < (len(t.nodes) + 10) { temp := make([]treeNodeV6, len(t.nodes), (cap(t.nodes)+1)*2) @@ -168,7 +168,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu // handle root tags if address.Length == 0 { countIncreased := t.addTag(tag, 1, matchFunc, replaceFirst) - return countIncreased, t.nodes[1].TagCount, nil + return countIncreased, t.nodes[1].TagCount } // root node doesn't have any prefix, so find the starting point @@ -179,7 +179,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Left } else { @@ -187,7 +187,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) root.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } nodeIndex = root.Right } @@ -212,7 +212,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu if matchCount == node.prefixLength { // the whole prefix matched - we're done! countIncreased := t.addTag(tag, nodeIndex, matchFunc, replaceFirst) - return countIncreased, t.nodes[nodeIndex].TagCount, nil + return countIncreased, t.nodes[nodeIndex].TagCount } // the input address is shorter than the match found - need to create a new, intermediate parent @@ -240,7 +240,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu } parent.Right = newNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } if matchCount == node.prefixLength { @@ -255,7 +255,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Left = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the left - traverse it @@ -270,7 +270,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu newNodeIndex := t.newNode(address, address.Length) countIncreased := t.addTag(tag, newNodeIndex, matchFunc, replaceFirst) node.Right = newNodeIndex - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } // there's a node to the right - traverse it @@ -308,12 +308,12 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu } parent.Right = newCommonParentNodeIndex } - return countIncreased, t.nodes[newNodeIndex].TagCount, nil + return countIncreased, t.nodes[newNodeIndex].TagCount } } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint) (int, error) { +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -339,14 +339,14 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat // traverse the tree for { if nodeIndex == 0 { - return 0, nil + return 0 } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return 0, nil + return 0 } if matchCount == address.Length { @@ -370,25 +370,25 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat if targetNode == nil || targetNode.TagCount == 0 { // no tags found - return 0, nil + return 0 } // delete matching tags deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it - return deleteCount, nil + return deleteCount } if targetNodeIndex == 1 { // can't delete the root node - return deleteCount, nil + return deleteCount } // compact the tree, if possible if targetNode.Left != 0 && targetNode.Right != 0 { // target has two children - nothing we can do - not deleting the node - return deleteCount, nil + return deleteCount } else if targetNode.Left != 0 { // target node only has only left child if parent.Left == targetNodeIndex { @@ -453,11 +453,11 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat targetNode.Left = 0 targetNode.Right = 0 t.availableIndexes = append(t.availableIndexes, targetNodeIndex) - return deleteCount, nil + return deleteCount } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) ([]uint, error) { +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint { root := &t.nodes[1] if filterFunc == nil { return t.FindTags(address) @@ -476,7 +476,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -491,14 +491,14 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -512,7 +512,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -526,7 +526,7 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil } // FindTags finds all matching tags that passes the filter function -func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint, error) { +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint { var matchCount uint root := &t.nodes[1] ret := make([]uint, 0) @@ -537,7 +537,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint, error) { if address.Length == 0 { // caller just looking for root tags - return ret, nil + return ret } var nodeIndex uint @@ -552,14 +552,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint, error) { for { count++ if nodeIndex == 0 { - return ret, nil + return ret } node := &t.nodes[nodeIndex] matchCount = node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return ret, nil + return ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -569,7 +569,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint, error) { if matchCount == address.Length { // exact match - we're done - return ret, nil + return ret } // there's still more address - keep traversing @@ -584,7 +584,7 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) ([]uint, error) { // FindDeepestTag finds a tag at the deepest level in the tree, representing the closest match. // - if that target node has multiple tags, the first in the list is returned -func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint, error) { +func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint) { root := &t.nodes[1] var found bool var ret uint @@ -596,7 +596,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint, error if address.Length == 0 { // caller just looking for root tags - return found, ret, nil + return found, ret } var nodeIndex uint @@ -609,14 +609,14 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint, error // traverse the tree for { if nodeIndex == 0 { - return found, ret, nil + return found, ret } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, ret, nil + return found, ret } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -627,7 +627,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint, error if matchCount == address.Length { // exact match - we're done - return found, ret, nil + return found, ret } // there's still more address - keep traversing @@ -642,7 +642,7 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint, error // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match // - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint, error) { +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint) { root := &t.nodes[1] var found bool var retTagIndex uint @@ -654,7 +654,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint, er if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } var nodeIndex uint @@ -667,14 +667,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint, er // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -685,7 +685,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint, er if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex), nil + return found, t.tagsForNode(retTagIndex) } // there's still more address - keep traversing From e2dbd6ac075e5746c17ba165433df2f92c485dd1 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Mon, 30 Aug 2021 19:00:20 +0000 Subject: [PATCH 06/19] Updated unit tests to handle no error returns --- template/tree_v6_test.go | 153 ++++++++++++++------------------------- 1 file changed, 53 insertions(+), 100 deletions(-) diff --git a/template/tree_v6_test.go b/template/tree_v6_test.go index 49cd151..b0bceae 100644 --- a/template/tree_v6_test.go +++ b/template/tree_v6_test.go @@ -58,73 +58,67 @@ func TestSimpleTreeV6(t *testing.T) { tree := NewTreeV6() for i := 128; i > 0; i-- { - countIncreased, count, err := tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", i), fmt.Sprintf("Tag-%d", i), nil) - assert.NoError(t, err) + countIncreased, count := tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", i), fmt.Sprintf("Tag-%d", i), nil) assert.True(t, countIncreased) assert.Equal(t, 1, count) } - tags, err := tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags := tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) if assert.Equal(t, 128, len(tags)) { assert.Equal(t, "Tag-128", tags[127].(string)) assert.Equal(t, "Tag-32", tags[31].(string)) } - tags, err = tree.FindTags(ipv6FromString("4001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("4001:db8:0:0:0:0:2:1/128", 128)) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Tag-1", tags[0]) } // find deepest tag: match at lowest level - found, tag, err := tree.FindDeepestTag(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + found, tag := tree.FindDeepestTag(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, found) if assert.NotNil(t, tag) { assert.Equal(t, "Tag-128", tag) } // find deepest tag: match at top level - found, tag, err = tree.FindDeepestTag(ipv6FromString("7001:db8:0:0:0:0:2:1/128", 128)) + found, tag = tree.FindDeepestTag(ipv6FromString("7001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, found) if assert.NotNil(t, tag) { assert.Equal(t, "Tag-1", tag.(string)) } - found, tag, err = tree.FindDeepestTag(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 1)) + found, tag = tree.FindDeepestTag(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 1)) assert.True(t, found) if assert.NotNil(t, tag) { assert.Equal(t, "Tag-1", tag.(string)) } // find deepest tag: match at mid level - found, tag, err = tree.FindDeepestTag(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 32)) + found, tag = tree.FindDeepestTag(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 32)) assert.True(t, found) if assert.NotNil(t, tag) { assert.Equal(t, "Tag-32", tag.(string)) } - found, tag, err = tree.FindDeepestTag(ipv6FromString("2001:db8:FFFF:0:0:0:2:1/128", 128)) + found, tag = tree.FindDeepestTag(ipv6FromString("2001:db8:FFFF:0:0:0:2:1/128", 128)) assert.True(t, found) if assert.NotNil(t, tag) { assert.Equal(t, "Tag-32", tag.(string)) } // find deepest tag: no match - found, tag, err = tree.FindDeepestTag(ipv6FromString("F001:db8:1:0:0:0:2:1/128", 32)) + found, tag = tree.FindDeepestTag(ipv6FromString("F001:db8:1:0:0:0:2:1/128", 32)) assert.False(t, found) assert.Nil(t, tag) // Add a couple root tags - countIncreased, count, err := tree.Add(ipv6FromString("2001:db8:1:0:0:0:2:1/128", 0), "root1", nil) - assert.NoError(t, err) + countIncreased, count := tree.Add(ipv6FromString("2001:db8:1:0:0:0:2:1/128", 0), "root1", nil) assert.True(t, countIncreased) assert.Equal(t, 1, count) - countIncreased, count, err = tree.Add(patricia.IPv6Address{}, "root2", nil) - assert.NoError(t, err) + countIncreased, count = tree.Add(patricia.IPv6Address{}, "root2", nil) assert.True(t, countIncreased) assert.Equal(t, 2, count) - tags, err = tree.FindTags(patricia.IPv6Address{}) - assert.NoError(t, err) + tags = tree.FindTags(patricia.IPv6Address{}) if assert.Equal(t, 2, len(tags)) { assert.Equal(t, "root1", tags[0].(string)) assert.Equal(t, "root2", tags[1].(string)) @@ -145,29 +139,23 @@ func TestTree1V6(t *testing.T) { tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags, err := tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128)) - assert.NoError(t, err) + tags := tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagZ})) - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagZ})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // three tags in a hierarchy - get just the first - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagZ})) // three tags in hierarchy - get none - tags, err = tree.FindTags(ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagZ})) - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66)) assert.True(t, tagArraysEqual(tags, []string{tagZ})) } @@ -188,29 +176,23 @@ func TestTree1V6WithFilter(t *testing.T) { tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags, err := tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128), filterFunc) - assert.NoError(t, err) + tags := tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) - tags, err = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127), filterFunc) - assert.NoError(t, err) + tags = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags, err = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), filterFunc) - assert.NoError(t, err) + tags = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - get just the first - tags, err = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128), filterFunc) - assert.NoError(t, err) + tags = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagB})) // three tags in hierarchy - get none - tags, err = tree.FindTagsWithFilter(ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128), filterFunc) - assert.NoError(t, err) + tags = tree.FindTagsWithFilter(ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128), filterFunc) assert.Zero(t, len(tags)) - tags, err = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66), filterFunc) - assert.NoError(t, err) + tags = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66), filterFunc) assert.Zero(t, len(tags)) } @@ -229,31 +211,26 @@ func TestRootNodeV6(t *testing.T) { tree.Add(patricia.IPv6Address{}, tagB, nil) // query the root node with no address - tags, err := tree.FindTags(patricia.IPv6Address{}) - assert.NoError(t, err) + tags := tree.FindTags(patricia.IPv6Address{}) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // query a node that doesn't exist - tags, err = tree.FindTags(ipv6FromString("FFFF:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("FFFF:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // create a new /65 node with C & D tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 65), tagC, nil) tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 65), tagD, nil) - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) // create a node under the /65 node tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), tagZ, nil) - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD, tagZ})) // check the /77 and make sure we still get the /65 and root - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 77)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 77)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) } @@ -279,74 +256,62 @@ func TestDelete1V6(t *testing.T) { assert.Equal(t, 4, tree.countNodes(1)) // three tags in a hierarchy - ask for an exact match, receive all 3 and the root - tags, err := tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags := tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // 1. delete a tag that doesn't exist count := 0 - count, err = tree.Delete(ipv6FromString("F001:db8:0:0:0:0:2:1/128", 128), matchFunc, "bad tag") - assert.NoError(t, err) + count = tree.Delete(ipv6FromString("F001:db8:0:0:0:0:2:1/128", 128), matchFunc, "bad tag") assert.Equal(t, 0, count) assert.Equal(t, 4, tree.countTags(1)) assert.Equal(t, 4, tree.countNodes(1)) // 2. delete a tag on an address that exists, but doesn't have the tag - count, err = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "bad tag") + count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "bad tag") assert.Equal(t, 0, count) - assert.NoError(t, err) // verify - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) assert.Equal(t, 4, tree.countNodes(1)) assert.Equal(t, 4, tree.countTags(1)) // 3. delete the default/root tag - count, err = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 0), matchFunc, "tagZ") - assert.NoError(t, err) + count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 0), matchFunc, "tagZ") assert.Equal(t, 1, count) assert.Equal(t, 4, tree.countNodes(1)) // doesn't delete anything assert.Equal(t, 3, tree.countTags(1)) // three tags in a hierarchy - ask for an exact match, receive all 3, not the root, which we deleted - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC})) // 4. delete tagA - count, err = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "tagA") - assert.NoError(t, err) + count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "tagA") assert.Equal(t, 1, count) // verify - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagC})) assert.Equal(t, 3, tree.countNodes(1)) assert.Equal(t, 2, tree.countTags(1)) // 5. delete tag B - count, err = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 2), matchFunc, "tagB") - assert.NoError(t, err) + count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 2), matchFunc, "tagB") assert.Equal(t, 1, count) // verify - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagC})) assert.Equal(t, 2, tree.countNodes(1)) assert.Equal(t, 1, tree.countTags(1)) // 6. delete tag C - count, err = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), matchFunc, "tagC") - assert.NoError(t, err) + count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), matchFunc, "tagC") assert.Equal(t, 1, count) // verify - tags, err = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.NoError(t, err) + tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{})) assert.Equal(t, 1, tree.countNodes(1)) assert.Equal(t, 0, tree.countTags(1)) @@ -358,27 +323,23 @@ func TestDuplicateTagsWithNoMatchFuncV6(t *testing.T) { tree := NewTreeV6() - wasAdded, count, err := tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), "FOO", matchFunc) + wasAdded, count := tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), "FOO", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) - wasAdded, count, err = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) // add another at previous node - wasAdded, count, err = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "FOOBAR", matchFunc) + wasAdded, count = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "FOOBAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 2, count) - assert.NoError(t, err) // add a dupe to the previous node - will be fine since match is nil - wasAdded, count, err = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 3, count) - assert.NoError(t, err) } // test duplicate tags with match func that always returns false @@ -389,27 +350,23 @@ func TestDuplicateTagsWithFalseMatchFuncV6(t *testing.T) { tree := NewTreeV6() - wasAdded, count, err := tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), "FOO", matchFunc) + wasAdded, count := tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), "FOO", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) - wasAdded, count, err = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) // add another at previous node - wasAdded, count, err = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "FOOBAR", matchFunc) + wasAdded, count = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "FOOBAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 2, count) - assert.NoError(t, err) // add a dupe to the previous node - will be fine since match is nil - wasAdded, count, err = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 3, count) - assert.NoError(t, err) } // test duplicate tags with match func that does something @@ -420,25 +377,21 @@ func TestDuplicateTagsWithMatchFuncV6(t *testing.T) { tree := NewTreeV6() - wasAdded, count, err := tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), "FOO", matchFunc) + wasAdded, count := tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), "FOO", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) - wasAdded, count, err = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 1, count) - assert.NoError(t, err) // add another at previous node - wasAdded, count, err = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "FOOBAR", matchFunc) + wasAdded, count = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "FOOBAR", matchFunc) assert.True(t, wasAdded) assert.Equal(t, 2, count) - assert.NoError(t, err) // add a dupe to the previous node - will be fine since match is nil - wasAdded, count, err = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) + wasAdded, count = tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:2/128", 128), "BAR", matchFunc) assert.False(t, wasAdded) assert.Equal(t, 2, count) - assert.NoError(t, err) } From 0e456c67c4f2239089abeafea950a6b9129743fc Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Tue, 31 Aug 2021 03:17:45 +0000 Subject: [PATCH 07/19] Changed method signatures to reduce allocations The `Find` methods now accept a slice to put results into. `Delete` now accepts a slice to use as a buffer. --- template/tree_v4.go | 138 ++++++++++--------------------- template/tree_v4_bulk_test.go | 5 +- template/tree_v4_manual.go | 4 +- template/tree_v4_test.go | 148 +++++++++++++++++++++------------- template/tree_v6_manual.go | 4 +- template/tree_v6_test.go | 90 +++++++++++++-------- 6 files changed, 199 insertions(+), 190 deletions(-) diff --git a/template/tree_v4.go b/template/tree_v4.go index 598faf7..03cb5a6 100644 --- a/template/tree_v4.go +++ b/template/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag GeneratedType, nodeIndex uint, matchFunc MatchesFunc } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []GeneratedType { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]GeneratedType, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []GeneratedType, nodeIndex uint) []GeneratedType { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []GeneratedType, nodeIndex uint) []GeneratedType { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) GeneratedType { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag GeneratedType, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []GeneratedType, nodeIndex uint, matchTag GeneratedType, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag GeneratedType, matchFunc Mat // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal GeneratedType) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []GeneratedType, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal GeneratedType) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []GeneratedType { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []GeneratedType, address patricia.IPv4Address, filterFunc FilterFunc) []GeneratedType { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]GeneratedType, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []GeneratedType { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]GeneratedType, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []GeneratedType, address patricia.IPv4Address) []GeneratedType { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []GeneratedType, address patricia.IPv4Address) []GeneratedType { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []GeneratedType, address patricia.IPv4Addres // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, GeneratedTy } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []GeneratedType) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []GeneratedType, address patricia.IPv4Address) (bool, []GeneratedType) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []Generate if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []Generate // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []Generate if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/template/tree_v4_bulk_test.go b/template/tree_v4_bulk_test.go index 88cad4a..2a377b4 100644 --- a/template/tree_v4_bulk_test.go +++ b/template/tree_v4_bulk_test.go @@ -73,6 +73,7 @@ func TestBulkLoad(t *testing.T) { assert.Equal(t, recordsLoaded, tree.CountTags()) } + buf := make([]GeneratedType, 0) evaluate := func() { fmt.Printf("# of nodes: %d\n", len(tree.nodes)) // query all tags from each address, query specific tag from each address, delete the tag @@ -83,7 +84,7 @@ func TestBulkLoad(t *testing.T) { panic(fmt.Sprintf("search: Could not parse IP '%s': %s", address, err)) } if v4 != nil { - foundTags := tree.FindTags(*v4) + foundTags := tree.FindTags(buf, *v4) if assert.True(t, len(foundTags) > 0, "Couldn't find tags for "+address) { assert.True(t, tag == foundTags[len(foundTags)-1]) } @@ -94,7 +95,7 @@ func TestBulkLoad(t *testing.T) { // delete the tags now //fmt.Printf("Deleting %s: %s\n", address, tag) - deleteCount := tree.Delete(*v4, func(a GeneratedType, b GeneratedType) bool { return a == b }, tag) + deleteCount := tree.Delete(buf, *v4, func(a GeneratedType, b GeneratedType) bool { return a == b }, tag) assert.Equal(t, 1, deleteCount, "Tried deleting tag") //tree.print() } else if v6 == nil { diff --git a/template/tree_v4_manual.go b/template/tree_v4_manual.go index 104b8df..0d18b52 100644 --- a/template/tree_v4_manual.go +++ b/template/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]GeneratedType, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/template/tree_v4_test.go b/template/tree_v4_test.go index 9d512fc..20275c2 100644 --- a/template/tree_v4_test.go +++ b/template/tree_v4_test.go @@ -25,6 +25,7 @@ func BenchmarkFindTags(b *testing.B) { tree := NewTreeV4() + buf := make([]GeneratedType, 0) tree.Add(patricia.IPv4Address{}, tagZ, nil) // default tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), tagA, nil) tree.Add(ipv4FromBytes([]byte{160, 0, 0, 0}, 2), tagB, nil) // 160 -> 128 @@ -33,7 +34,7 @@ func BenchmarkFindTags(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { address := patricia.NewIPv4Address(uint32(2156823809), 32) - tree.FindTags(address) + tree.FindTags(buf, address) } } @@ -79,8 +80,10 @@ func BenchmarkBuildTreeAndFindDeepestTag(b *testing.B) { } func TestTree2(t *testing.T) { - tree := NewTreeV4() + tags := make([]GeneratedType, 0) + found := false + tree := NewTreeV4() // insert a bunch of tags v4, _, err := patricia.ParseIPFromString("1.2.3.0/24") assert.NoError(t, err) @@ -192,20 +195,20 @@ func TestTree2(t *testing.T) { assert.Equal(t, "j", tag) v4, _, _ = patricia.ParseIPFromString("185.76.10.146") - found, tags := tree.FindDeepestTags(*v4) + found, tags = tree.FindDeepestTags(tags, *v4) assert.True(t, found) assert.Equal(t, "j", tags[0]) assert.Equal(t, "k", tags[1]) // test searching for addresses with no leaf nodes v4, _, _ = patricia.ParseIPFromString("1.2.3.4") - found, tags = tree.FindDeepestTags(*v4) + found, tags = tree.FindDeepestTags(tags, *v4) assert.True(t, found) assert.Equal(t, "foo", tags[0]) assert.Equal(t, "bar", tags[1]) v4, _, _ = patricia.ParseIPFromString("1.2.3.5") - found, tags = tree.FindDeepestTags(*v4) + found, tags = tree.FindDeepestTags(tags, *v4) assert.True(t, found) assert.Equal(t, "foo", tags[0]) assert.Equal(t, "bar", tags[1]) @@ -217,14 +220,14 @@ func TestTree2(t *testing.T) { // test searching for an address that has nothing v4, _, _ = patricia.ParseIPFromString("9.9.9.9") - found, tags = tree.FindDeepestTags(*v4) + found, tags = tree.FindDeepestTags(tags, *v4) assert.False(t, found) assert.NotNil(t, tags) assert.Equal(t, 0, len(tags)) // test searching for an empty address v4, _, _ = patricia.ParseIPFromString("9.9.9.9/0") - found, tags = tree.FindDeepestTags(*v4) + found, tags = tree.FindDeepestTags(tags, *v4) assert.False(t, found) assert.NotNil(t, tags) assert.Equal(t, 0, len(tags)) @@ -236,7 +239,7 @@ func TestTree2(t *testing.T) { tree.Add(*v4, "root_node", nil) v4, _, _ = patricia.ParseIPFromString("9.9.9.9/0") - found, tags = tree.FindDeepestTags(*v4) + found, tags = tree.FindDeepestTags(tags, *v4) assert.True(t, found) assert.NotNil(t, tags) assert.Equal(t, 1, len(tags)) @@ -250,6 +253,8 @@ func TestTree2(t *testing.T) { // test that the find functions don't destroy an address - too brittle and confusing for caller for what gains? func TestAddressReusable(t *testing.T) { + tags := make([]GeneratedType, 0) + tree := NewTreeV4() pv4, pv6, err := patricia.ParseIPFromString("59.60.75.53") // needs to share same second-level node with the address we're going to work with @@ -274,13 +279,13 @@ func TestAddressReusable(t *testing.T) { assert.Equal(t, "Hello", tag) // search again with same address - tags := tree.FindTags(*v4) + tags = tree.FindTags(tags, *v4) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Hello", tags[0]) } // search again with same address - tags = tree.FindTags(*v4) + tags = tree.FindTags(tags, *v4) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Hello", tags[0]) } @@ -312,6 +317,8 @@ func TestSimpleTree1(t *testing.T) { // Test having a couple of inner nodes func TestSimpleTree2(t *testing.T) { + buf := make([]GeneratedType, 0) + ipA, _, _ := patricia.ParseIPFromString("203.143.220.0/23") ipB, _, _ := patricia.ParseIPFromString("203.143.220.198/32") ipC, _, _ := patricia.ParseIPFromString("203.143.0.0/16") @@ -338,13 +345,13 @@ func TestSimpleTree2(t *testing.T) { matchFunc := func(a GeneratedType, b GeneratedType) bool { return a == b } - deleteCount := tree.Delete(*ipA, matchFunc, "A") + deleteCount := tree.Delete(buf, *ipA, matchFunc, "A") assert.Equal(t, 1, deleteCount) - deleteCount = tree.Delete(*ipB, matchFunc, "B") + deleteCount = tree.Delete(buf, *ipB, matchFunc, "B") assert.Equal(t, 1, deleteCount) - deleteCount = tree.Delete(*ipC, matchFunc, "C") + deleteCount = tree.Delete(buf, *ipC, matchFunc, "C") assert.Equal(t, 1, deleteCount) - deleteCount = tree.Delete(*ipD, matchFunc, "D") + deleteCount = tree.Delete(buf, *ipD, matchFunc, "D") assert.Equal(t, 1, deleteCount) // should have zero logical nodes except for root @@ -352,6 +359,8 @@ func TestSimpleTree2(t *testing.T) { } func TestSimpleTree(t *testing.T) { + tags := make([]GeneratedType, 0) + tree := NewTreeV4() for i := 32; i > 0; i-- { @@ -360,13 +369,13 @@ func TestSimpleTree(t *testing.T) { assert.Equal(t, 1, count) } - tags := tree.FindTags(ipv4FromBytes([]byte{127, 0, 0, 1}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{127, 0, 0, 1}, 32)) if assert.Equal(t, 32, len(tags)) { assert.Equal(t, "Tag-32", tags[31].(string)) assert.Equal(t, "Tag-31", tags[30].(string)) } - tags = tree.FindTags(ipv4FromBytes([]byte{63, 3, 0, 1}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{63, 3, 0, 1}, 32)) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Tag-1", tags[0].(string)) } @@ -405,7 +414,7 @@ func TestSimpleTree(t *testing.T) { assert.True(t, countIncreased) assert.Equal(t, 2, count) - tags = tree.FindTags(patricia.IPv4Address{}) + tags = tree.FindTags(tags, patricia.IPv4Address{}) if assert.Equal(t, 2, len(tags)) { assert.Equal(t, "root1", tags[0].(string)) assert.Equal(t, "root2", tags[1].(string)) @@ -434,6 +443,8 @@ func tagArraysEqual(a []GeneratedType, b []string) bool { } func TestTree1FindTags(t *testing.T) { + tags := make([]GeneratedType, 0) + tagA := "tagA" tagB := "tagB" tagC := "tagC" @@ -446,23 +457,25 @@ func TestTree1FindTags(t *testing.T) { tree.Add(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags := tree.FindTags(ipv4FromBytes([]byte{128, 142, 133, 1}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 142, 133, 1}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagZ})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // three tags in a hierarchy - get just the first - tags = tree.FindTags(ipv4FromBytes([]byte{162, 1, 0, 5}, 30)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{162, 1, 0, 5}, 30)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagZ})) // three tags in hierarchy - get none - tags = tree.FindTags(ipv4FromBytes([]byte{1, 0, 0, 0}, 1)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 0, 0, 0}, 1)) assert.True(t, tagArraysEqual(tags, []string{tagZ})) } func TestTree1FindTagsWithFilter(t *testing.T) { + tags := make([]GeneratedType, 0) + tagA := "tagA" tagB := "tagB" tagC := "tagC" @@ -479,24 +492,26 @@ func TestTree1FindTagsWithFilter(t *testing.T) { tree.Add(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags := tree.FindTagsWithFilter(ipv4FromBytes([]byte{128, 142, 133, 1}, 32), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv4FromBytes([]byte{128, 142, 133, 1}, 32), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - get just the first - tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{162, 1, 0, 5}, 30), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv4FromBytes([]byte{162, 1, 0, 5}, 30), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagB})) // three tags in hierarchy - get none - tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{1, 0, 0, 0}, 1), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv4FromBytes([]byte{1, 0, 0, 0}, 1), filterFunc) assert.Zero(t, len(tags)) } // Test that all queries get the root nodes func TestRootNode(t *testing.T) { + tags := make([]GeneratedType, 0) + tagA := "tagA" tagB := "tagB" tagC := "tagC" @@ -510,26 +525,26 @@ func TestRootNode(t *testing.T) { tree.Add(patricia.IPv4Address{}, tagB, nil) // query the root node with no address - tags := tree.FindTags(patricia.IPv4Address{}) + tags = tree.FindTags(tags, patricia.IPv4Address{}) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // query a node that doesn't exist - tags = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // create a new /16 node with C & D tree.Add(ipv4FromBytes([]byte{1, 2, 3, 4}, 16), tagC, nil) tree.Add(ipv4FromBytes([]byte{1, 2, 3, 4}, 16), tagD, nil) - tags = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 16)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 16)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) // create a node under the /16 node tree.Add(ipv4FromBytes([]byte{1, 2, 3, 4}, 32), tagZ, nil) - tags = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD, tagZ})) // check the /24 and make sure we still get the /16 and root - tags = tree.FindTags(ipv4FromBytes([]byte{1, 2, 3, 4}, 24)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 24)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) } @@ -553,6 +568,8 @@ func TestAdd(t *testing.T) { // Test setting a value to a node, rather than adding to a list func TestSet(t *testing.T) { + buf := make([]GeneratedType, 0) + address := ipv4FromBytes([]byte{1, 2, 3, 4}, 32) tree := NewTreeV4() @@ -590,7 +607,7 @@ func TestSet(t *testing.T) { assert.Equal(t, "tagD", tag) // now delete the tag - delCount := tree.Delete(address, func(a GeneratedType, b GeneratedType) bool { return true }, "") + delCount := tree.Delete(buf, address, func(a GeneratedType, b GeneratedType) bool { return true }, "") assert.Equal(t, 1, delCount) // verify it's gone - should get the parent @@ -600,6 +617,8 @@ func TestSet(t *testing.T) { } func TestDelete1(t *testing.T) { + tags := make([]GeneratedType, 0) + matchFunc := func(tagData GeneratedType, val GeneratedType) bool { return tagData.(string) == val.(string) } @@ -630,49 +649,53 @@ func TestDelete1(t *testing.T) { // verify status of internal nodes collections assert.Zero(t, len(tree.availableIndexes)) - assert.Equal(t, "tagZ", tree.tagsForNode(1)[0]) - assert.Equal(t, "tagA", tree.tagsForNode(2)[0]) - assert.Equal(t, "tagB", tree.tagsForNode(3)[0]) - assert.Equal(t, "tagC", tree.tagsForNode(4)[0]) + assert.Equal(t, "tagZ", tree.tagsForNode(tags, 1)[0]) + tags = tags[:0] + assert.Equal(t, "tagA", tree.tagsForNode(tags, 2)[0]) + tags = tags[:0] + assert.Equal(t, "tagB", tree.tagsForNode(tags, 3)[0]) + tags = tags[:0] + assert.Equal(t, "tagC", tree.tagsForNode(tags, 4)[0]) + tags = tags[:0] // three tags in a hierarchy - ask for an exact match, receive all 3 and the root - tags := tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // 1. delete a tag that doesn't exist count := 0 - count = tree.Delete(ipv4FromBytes([]byte{9, 9, 9, 9}, 32), matchFunc, "bad tag") + count = tree.Delete(tags, ipv4FromBytes([]byte{9, 9, 9, 9}, 32), matchFunc, "bad tag") assert.Equal(t, 0, count) assert.Equal(t, 4, tree.countNodes(1)) assert.Equal(t, 4, tree.countTags(1)) // 2. delete a tag on an address that exists, but doesn't have the tag - count = tree.Delete(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "bad tag") + count = tree.Delete(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "bad tag") assert.Equal(t, 0, count) // verify - tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) assert.Equal(t, 4, tree.countNodes(1)) assert.Equal(t, 4, tree.countTags(1)) // 3. delete the default/root tag - count = tree.Delete(ipv4FromBytes([]byte{0, 0, 0, 0}, 0), matchFunc, "tagZ") + count = tree.Delete(tags, ipv4FromBytes([]byte{0, 0, 0, 0}, 0), matchFunc, "tagZ") assert.Equal(t, 1, count) assert.Equal(t, 4, tree.countNodes(1)) // doesn't delete anything assert.Equal(t, 3, tree.countTags(1)) assert.Equal(t, 0, len(tree.availableIndexes)) // three tags in a hierarchy - ask for an exact match, receive all 3, not the root, which we deleted - tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC})) // 4. delete tagA - count = tree.Delete(ipv4FromBytes([]byte{128, 0, 0, 0}, 7), matchFunc, "tagA") + count = tree.Delete(tags, ipv4FromBytes([]byte{128, 0, 0, 0}, 7), matchFunc, "tagA") assert.Equal(t, 1, count) // verify - tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagC})) assert.Equal(t, 3, tree.countNodes(1)) assert.Equal(t, 2, tree.countTags(1)) @@ -680,11 +703,11 @@ func TestDelete1(t *testing.T) { assert.Equal(t, uint(2), tree.availableIndexes[0]) // 5. delete tag B - count = tree.Delete(ipv4FromBytes([]byte{128, 0, 0, 0}, 2), matchFunc, "tagB") + count = tree.Delete(tags, ipv4FromBytes([]byte{128, 0, 0, 0}, 2), matchFunc, "tagB") assert.Equal(t, 1, count) // verify - tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagC})) assert.Equal(t, 2, tree.countNodes(1)) assert.Equal(t, 1, tree.countTags(1)) @@ -700,14 +723,16 @@ func TestDelete1(t *testing.T) { // this should be recycling tagB assert.Equal(t, 1, len(tree.availableIndexes)) assert.Equal(t, uint(2), tree.availableIndexes[0]) - assert.Equal(t, "tagE", tree.tagsForNode(3)[0]) + + tags = tags[:0] + assert.Equal(t, "tagE", tree.tagsForNode(tags, 3)[0]) // 6. delete tag C - count = tree.Delete(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "tagC") + count = tree.Delete(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "tagC") assert.Equal(t, 1, count) // verify - tags = tree.FindTags(ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{})) assert.Equal(t, 2, tree.countNodes(1)) assert.Equal(t, 2, tree.countTags(1)) @@ -727,6 +752,8 @@ func TestTryToBreak(t *testing.T) { } func TestTagsMap(t *testing.T) { + tags := make([]GeneratedType, 0) + tree := NewTreeV4() // insert tags @@ -738,23 +765,34 @@ func TestTagsMap(t *testing.T) { // verify assert.Equal(t, 3, tree.nodes[1].TagCount) assert.Equal(t, "tagA", tree.firstTagForNode(1)) - assert.Equal(t, 3, len(tree.tagsForNode(1))) - assert.Equal(t, "tagA", tree.tagsForNode(1)[0]) - assert.Equal(t, "tagB", tree.tagsForNode(1)[1]) - assert.Equal(t, "tagC", tree.tagsForNode(1)[2]) + assert.Equal(t, 3, len(tree.tagsForNode(tags, 1))) + tags = tags[:0] + + assert.Equal(t, "tagA", tree.tagsForNode(tags, 1)[0]) + tags = tags[:0] + + assert.Equal(t, "tagB", tree.tagsForNode(tags, 1)[1]) + tags = tags[:0] + + assert.Equal(t, "tagC", tree.tagsForNode(tags, 1)[2]) + tags = tags[:0] // delete tagB matchesFunc := func(payload GeneratedType, val GeneratedType) bool { return payload == val } - deleted, kept := tree.deleteTag(1, "tagB", matchesFunc) + deleted, kept := tree.deleteTag(tags, 1, "tagB", matchesFunc) + assert.Equal(t, 0, len(tags)) // verify assert.Equal(t, 1, deleted) assert.Equal(t, 2, kept) assert.Equal(t, 2, tree.nodes[1].TagCount) - assert.Equal(t, "tagA", tree.tagsForNode(1)[0]) - assert.Equal(t, "tagC", tree.tagsForNode(1)[1]) + assert.Equal(t, "tagA", tree.tagsForNode(tags, 1)[0]) + tags = tags[:0] + + assert.Equal(t, "tagC", tree.tagsForNode(tags, 1)[1]) + tags = tags[:0] } // test duplicate tags with no match func diff --git a/template/tree_v6_manual.go b/template/tree_v6_manual.go index bc1d627..6f36820 100644 --- a/template/tree_v6_manual.go +++ b/template/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]GeneratedType, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/template/tree_v6_test.go b/template/tree_v6_test.go index b0bceae..472cb20 100644 --- a/template/tree_v6_test.go +++ b/template/tree_v6_test.go @@ -35,10 +35,12 @@ func BenchmarkFindTagsV6(b *testing.B) { tree.Add(ipv6FromString("2001:db8:0:0:0:5:2:1/128", 16), tagB, nil) // 160 -> 128 tree.Add(ipv6FromString("2001:db7:0:0:0:0:2:1/128", 77), tagC, nil) + buf := make([]GeneratedType, 0) address := ipv6FromString("2001:db7:0:0:0:0:2:1/128", 32) b.ResetTimer() for n := 0; n < b.N; n++ { - tree.FindTags(address) + tree.FindTags(buf, address) + buf = buf[:0] } } @@ -55,6 +57,8 @@ func BenchmarkFindDeepestTagV6(b *testing.B) { } func TestSimpleTreeV6(t *testing.T) { + tags := make([]GeneratedType, 0) + tree := NewTreeV6() for i := 128; i > 0; i-- { @@ -63,13 +67,13 @@ func TestSimpleTreeV6(t *testing.T) { assert.Equal(t, 1, count) } - tags := tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) if assert.Equal(t, 128, len(tags)) { assert.Equal(t, "Tag-128", tags[127].(string)) assert.Equal(t, "Tag-32", tags[31].(string)) } - tags = tree.FindTags(ipv6FromString("4001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("4001:db8:0:0:0:0:2:1/128", 128)) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Tag-1", tags[0]) } @@ -118,15 +122,16 @@ func TestSimpleTreeV6(t *testing.T) { assert.True(t, countIncreased) assert.Equal(t, 2, count) - tags = tree.FindTags(patricia.IPv6Address{}) + tags = tree.FindTags(tags, patricia.IPv6Address{}) if assert.Equal(t, 2, len(tags)) { assert.Equal(t, "root1", tags[0].(string)) assert.Equal(t, "root2", tags[1].(string)) } - } func TestTree1V6(t *testing.T) { + tags := make([]GeneratedType, 0) + tagA := "tagA" tagB := "tagB" tagC := "tagC" @@ -139,27 +144,29 @@ func TestTree1V6(t *testing.T) { tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags := tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagZ})) - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagZ})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // three tags in a hierarchy - get just the first - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagZ})) // three tags in hierarchy - get none - tags = tree.FindTags(ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagZ})) - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66)) assert.True(t, tagArraysEqual(tags, []string{tagZ})) } func TestTree1V6WithFilter(t *testing.T) { + tags := make([]GeneratedType, 0) + tagA := "tagA" tagB := "tagB" tagC := "tagC" @@ -176,28 +183,30 @@ func TestTree1V6WithFilter(t *testing.T) { tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags := tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) - tags = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - get just the first - tags = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagB})) // three tags in hierarchy - get none - tags = tree.FindTagsWithFilter(ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128), filterFunc) assert.Zero(t, len(tags)) - tags = tree.FindTagsWithFilter(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66), filterFunc) + tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66), filterFunc) assert.Zero(t, len(tags)) } // Test that all queries get the root nodes func TestRootNodeV6(t *testing.T) { + tags := make([]GeneratedType, 0) + tagA := "tagA" tagB := "tagB" tagC := "tagC" @@ -211,30 +220,32 @@ func TestRootNodeV6(t *testing.T) { tree.Add(patricia.IPv6Address{}, tagB, nil) // query the root node with no address - tags := tree.FindTags(patricia.IPv6Address{}) + tags = tree.FindTags(tags, patricia.IPv6Address{}) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // query a node that doesn't exist - tags = tree.FindTags(ipv6FromString("FFFF:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("FFFF:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // create a new /65 node with C & D tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 65), tagC, nil) tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 65), tagD, nil) - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) // create a node under the /65 node tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), tagZ, nil) - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD, tagZ})) // check the /77 and make sure we still get the /65 and root - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 77)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 77)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) } func TestDelete1V6(t *testing.T) { + tags := make([]GeneratedType, 0) + matchFunc := func(tagData GeneratedType, val GeneratedType) bool { return tagData.(string) == val.(string) } @@ -256,62 +267,73 @@ func TestDelete1V6(t *testing.T) { assert.Equal(t, 4, tree.countNodes(1)) // three tags in a hierarchy - ask for an exact match, receive all 3 and the root - tags := tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) + tags = tags[:0] // 1. delete a tag that doesn't exist count := 0 - count = tree.Delete(ipv6FromString("F001:db8:0:0:0:0:2:1/128", 128), matchFunc, "bad tag") + count = tree.Delete(tags, ipv6FromString("F001:db8:0:0:0:0:2:1/128", 128), matchFunc, "bad tag") assert.Equal(t, 0, count) assert.Equal(t, 4, tree.countTags(1)) assert.Equal(t, 4, tree.countNodes(1)) + assert.Equal(t, 0, len(tags)) // 2. delete a tag on an address that exists, but doesn't have the tag - count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "bad tag") + count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "bad tag") assert.Equal(t, 0, count) + assert.Equal(t, 0, len(tags)) // verify - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) assert.Equal(t, 4, tree.countNodes(1)) assert.Equal(t, 4, tree.countTags(1)) + tags = tags[:0] // 3. delete the default/root tag - count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 0), matchFunc, "tagZ") + count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 0), matchFunc, "tagZ") assert.Equal(t, 1, count) assert.Equal(t, 4, tree.countNodes(1)) // doesn't delete anything assert.Equal(t, 3, tree.countTags(1)) + assert.Equal(t, 0, len(tags)) // three tags in a hierarchy - ask for an exact match, receive all 3, not the root, which we deleted - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC})) + tags = tags[:0] // 4. delete tagA - count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "tagA") + count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "tagA") assert.Equal(t, 1, count) + assert.Equal(t, 0, len(tags)) // verify - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagC})) assert.Equal(t, 3, tree.countNodes(1)) assert.Equal(t, 2, tree.countTags(1)) + tags = tags[:0] // 5. delete tag B - count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 2), matchFunc, "tagB") + count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 2), matchFunc, "tagB") assert.Equal(t, 1, count) + assert.Equal(t, 0, len(tags)) // verify - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagC})) assert.Equal(t, 2, tree.countNodes(1)) assert.Equal(t, 1, tree.countTags(1)) + tags = tags[:0] // 6. delete tag C - count = tree.Delete(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), matchFunc, "tagC") + count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), matchFunc, "tagC") assert.Equal(t, 1, count) + assert.Equal(t, 0, len(tags)) // verify - tags = tree.FindTags(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{})) assert.Equal(t, 1, tree.countNodes(1)) assert.Equal(t, 0, tree.countTags(1)) From fc6e47278d9fc0325dc923386f59ad3b81b0f260 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Tue, 31 Aug 2021 03:20:35 +0000 Subject: [PATCH 08/19] Code gen --- bool_tree/tree_v4.go | 138 ++++++++------------------- bool_tree/tree_v4_manual.go | 4 +- bool_tree/tree_v6_generated.go | 138 ++++++++------------------- bool_tree/tree_v6_manual.go | 4 +- byte_tree/tree_v4.go | 138 ++++++++------------------- byte_tree/tree_v4_manual.go | 4 +- byte_tree/tree_v6_generated.go | 138 ++++++++------------------- byte_tree/tree_v6_manual.go | 4 +- complex128_tree/tree_v4.go | 138 ++++++++------------------- complex128_tree/tree_v4_manual.go | 4 +- complex128_tree/tree_v6_generated.go | 138 ++++++++------------------- complex128_tree/tree_v6_manual.go | 4 +- complex64_tree/tree_v4.go | 138 ++++++++------------------- complex64_tree/tree_v4_manual.go | 4 +- complex64_tree/tree_v6_generated.go | 138 ++++++++------------------- complex64_tree/tree_v6_manual.go | 4 +- float32_tree/tree_v4.go | 138 ++++++++------------------- float32_tree/tree_v4_manual.go | 4 +- float32_tree/tree_v6_generated.go | 138 ++++++++------------------- float32_tree/tree_v6_manual.go | 4 +- float64_tree/tree_v4.go | 138 ++++++++------------------- float64_tree/tree_v4_manual.go | 4 +- float64_tree/tree_v6_generated.go | 138 ++++++++------------------- float64_tree/tree_v6_manual.go | 4 +- int16_tree/tree_v4.go | 138 ++++++++------------------- int16_tree/tree_v4_manual.go | 4 +- int16_tree/tree_v6_generated.go | 138 ++++++++------------------- int16_tree/tree_v6_manual.go | 4 +- int32_tree/tree_v4.go | 138 ++++++++------------------- int32_tree/tree_v4_manual.go | 4 +- int32_tree/tree_v6_generated.go | 138 ++++++++------------------- int32_tree/tree_v6_manual.go | 4 +- int64_tree/tree_v4.go | 138 ++++++++------------------- int64_tree/tree_v4_manual.go | 4 +- int64_tree/tree_v6_generated.go | 138 ++++++++------------------- int64_tree/tree_v6_manual.go | 4 +- int8_tree/tree_v4.go | 138 ++++++++------------------- int8_tree/tree_v4_manual.go | 4 +- int8_tree/tree_v6_generated.go | 138 ++++++++------------------- int8_tree/tree_v6_manual.go | 4 +- int_tree/tree_v4.go | 138 ++++++++------------------- int_tree/tree_v4_manual.go | 4 +- int_tree/tree_v6_generated.go | 138 ++++++++------------------- int_tree/tree_v6_manual.go | 4 +- rune_tree/tree_v4.go | 138 ++++++++------------------- rune_tree/tree_v4_manual.go | 4 +- rune_tree/tree_v6_generated.go | 138 ++++++++------------------- rune_tree/tree_v6_manual.go | 4 +- string_tree/tree_v4.go | 138 ++++++++------------------- string_tree/tree_v4_manual.go | 4 +- string_tree/tree_v6_generated.go | 138 ++++++++------------------- string_tree/tree_v6_manual.go | 4 +- template/tree_v6_generated.go | 138 ++++++++------------------- uint16_tree/tree_v4.go | 138 ++++++++------------------- uint16_tree/tree_v4_manual.go | 4 +- uint16_tree/tree_v6_generated.go | 138 ++++++++------------------- uint16_tree/tree_v6_manual.go | 4 +- uint32_tree/tree_v4.go | 138 ++++++++------------------- uint32_tree/tree_v4_manual.go | 4 +- uint32_tree/tree_v6_generated.go | 138 ++++++++------------------- uint32_tree/tree_v6_manual.go | 4 +- uint64_tree/tree_v4.go | 138 ++++++++------------------- uint64_tree/tree_v4_manual.go | 4 +- uint64_tree/tree_v6_generated.go | 138 ++++++++------------------- uint64_tree/tree_v6_manual.go | 4 +- uint8_tree/tree_v4.go | 138 ++++++++------------------- uint8_tree/tree_v4_manual.go | 4 +- uint8_tree/tree_v6_generated.go | 138 ++++++++------------------- uint8_tree/tree_v6_manual.go | 4 +- uint_tree/tree_v4.go | 138 ++++++++------------------- uint_tree/tree_v4_manual.go | 4 +- uint_tree/tree_v6_generated.go | 138 ++++++++------------------- uint_tree/tree_v6_manual.go | 4 +- 73 files changed, 1625 insertions(+), 3625 deletions(-) diff --git a/bool_tree/tree_v4.go b/bool_tree/tree_v4.go index 16fc645..72bf53a 100644 --- a/bool_tree/tree_v4.go +++ b/bool_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag bool, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []bool { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]bool, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []bool, nodeIndex uint) []bool { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []bool, nodeIndex uint) []bool { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) bool { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag bool, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []bool, nodeIndex uint, matchTag bool, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag bool, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal bool) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []bool, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal bool) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []bool { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []bool, address patricia.IPv4Address, filterFunc FilterFunc) []bool { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]bool, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []bool { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]bool, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []bool, address patricia.IPv4Address) []bool { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []bool, address patricia.IPv4Address) []bool { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []bool, address patricia.IPv4Address) []bool // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, bool) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []bool, address patricia.IPv4Address) (bool, []bool) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/bool_tree/tree_v4_manual.go b/bool_tree/tree_v4_manual.go index 6444071..68d0e43 100644 --- a/bool_tree/tree_v4_manual.go +++ b/bool_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]bool, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/bool_tree/tree_v6_generated.go b/bool_tree/tree_v6_generated.go index 3e47dbb..b4fc560 100644 --- a/bool_tree/tree_v6_generated.go +++ b/bool_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag bool, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []bool { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]bool, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []bool, nodeIndex uint) []bool { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []bool, nodeIndex uint) []bool { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) bool { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag bool, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []bool, nodeIndex uint, matchTag bool, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag bool, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal bool) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []bool, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal bool) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []bool { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []bool, address patricia.IPv6Address, filterFunc FilterFunc) []bool { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]bool, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []bool { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]bool, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []bool, address patricia.IPv6Address) []bool { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []bool, address patricia.IPv6Address) []bool { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []bool, address patricia.IPv6Address) []bool // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, bool) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []bool, address patricia.IPv6Address) (bool, []bool) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/bool_tree/tree_v6_manual.go b/bool_tree/tree_v6_manual.go index fe878a8..6d8e2f0 100644 --- a/bool_tree/tree_v6_manual.go +++ b/bool_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]bool, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/byte_tree/tree_v4.go b/byte_tree/tree_v4.go index fe54700..422772b 100644 --- a/byte_tree/tree_v4.go +++ b/byte_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag byte, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []byte { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]byte, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []byte, nodeIndex uint) []byte { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []byte, nodeIndex uint) []byte { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) byte { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag byte, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []byte, nodeIndex uint, matchTag byte, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag byte, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal byte) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []byte, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal byte) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []byte { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []byte, address patricia.IPv4Address, filterFunc FilterFunc) []byte { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]byte, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []byte { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]byte, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []byte, address patricia.IPv4Address) []byte { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []byte, address patricia.IPv4Address) []byte { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []byte, address patricia.IPv4Address) []byte // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, byte) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []byte, address patricia.IPv4Address) (bool, []byte) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/byte_tree/tree_v4_manual.go b/byte_tree/tree_v4_manual.go index fd0c62e..addbc75 100644 --- a/byte_tree/tree_v4_manual.go +++ b/byte_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]byte, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/byte_tree/tree_v6_generated.go b/byte_tree/tree_v6_generated.go index f4d5228..bbae6a6 100644 --- a/byte_tree/tree_v6_generated.go +++ b/byte_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag byte, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []byte { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]byte, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []byte, nodeIndex uint) []byte { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []byte, nodeIndex uint) []byte { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) byte { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag byte, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []byte, nodeIndex uint, matchTag byte, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag byte, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal byte) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []byte, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal byte) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []byte { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []byte, address patricia.IPv6Address, filterFunc FilterFunc) []byte { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]byte, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []byte { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]byte, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []byte, address patricia.IPv6Address) []byte { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []byte, address patricia.IPv6Address) []byte { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []byte, address patricia.IPv6Address) []byte // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, byte) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []byte, address patricia.IPv6Address) (bool, []byte) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/byte_tree/tree_v6_manual.go b/byte_tree/tree_v6_manual.go index db042be..201342f 100644 --- a/byte_tree/tree_v6_manual.go +++ b/byte_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]byte, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/complex128_tree/tree_v4.go b/complex128_tree/tree_v4.go index add0cf5..daf3ef4 100644 --- a/complex128_tree/tree_v4.go +++ b/complex128_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag complex128, nodeIndex uint, matchFunc MatchesFunc, r } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []complex128 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]complex128, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []complex128, nodeIndex uint) []complex128 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []complex128, nodeIndex uint) []complex128 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) complex128 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag complex128, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []complex128, nodeIndex uint, matchTag complex128, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag complex128, matchFunc Matche // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex128) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []complex128, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex128) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []complex128 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []complex128, address patricia.IPv4Address, filterFunc FilterFunc) []complex128 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]complex128, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []complex128 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]complex128, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []complex128, address patricia.IPv4Address) []complex128 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []complex128, address patricia.IPv4Address) []complex128 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []complex128, address patricia.IPv4Address) // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex128) } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex128) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []complex128, address patricia.IPv4Address) (bool, []complex128) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex1 if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex1 // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex1 if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/complex128_tree/tree_v4_manual.go b/complex128_tree/tree_v4_manual.go index 8f8a0d0..2e43f23 100644 --- a/complex128_tree/tree_v4_manual.go +++ b/complex128_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]complex128, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/complex128_tree/tree_v6_generated.go b/complex128_tree/tree_v6_generated.go index 42e0170..91129a6 100644 --- a/complex128_tree/tree_v6_generated.go +++ b/complex128_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag complex128, nodeIndex uint, matchFunc MatchesFunc, r } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []complex128 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]complex128, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []complex128, nodeIndex uint) []complex128 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []complex128, nodeIndex uint) []complex128 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) complex128 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag complex128, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []complex128, nodeIndex uint, matchTag complex128, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag complex128, matchFunc Matche // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex128) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []complex128, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex128) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []complex128 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []complex128, address patricia.IPv6Address, filterFunc FilterFunc) []complex128 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]complex128, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []complex128 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]complex128, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []complex128, address patricia.IPv6Address) []complex128 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []complex128, address patricia.IPv6Address) []complex128 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []complex128, address patricia.IPv6Address) // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex128) } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex128) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []complex128, address patricia.IPv6Address) (bool, []complex128) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex1 if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex1 // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex1 if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/complex128_tree/tree_v6_manual.go b/complex128_tree/tree_v6_manual.go index 188129e..ced60da 100644 --- a/complex128_tree/tree_v6_manual.go +++ b/complex128_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]complex128, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/complex64_tree/tree_v4.go b/complex64_tree/tree_v4.go index 4e017bc..c9ae9c9 100644 --- a/complex64_tree/tree_v4.go +++ b/complex64_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag complex64, nodeIndex uint, matchFunc MatchesFunc, re } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []complex64 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]complex64, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []complex64, nodeIndex uint) []complex64 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []complex64, nodeIndex uint) []complex64 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) complex64 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag complex64, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []complex64, nodeIndex uint, matchTag complex64, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag complex64, matchFunc Matches // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex64) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []complex64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []complex64 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []complex64, address patricia.IPv4Address, filterFunc FilterFunc) []complex64 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]complex64, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []complex64 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]complex64, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []complex64, address patricia.IPv4Address) []complex64 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []complex64, address patricia.IPv4Address) []complex64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []complex64, address patricia.IPv4Address) [ // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex64) } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex64) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []complex64, address patricia.IPv4Address) (bool, []complex64) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex6 if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex6 // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex6 if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/complex64_tree/tree_v4_manual.go b/complex64_tree/tree_v4_manual.go index cc4a0ac..224167c 100644 --- a/complex64_tree/tree_v4_manual.go +++ b/complex64_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]complex64, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/complex64_tree/tree_v6_generated.go b/complex64_tree/tree_v6_generated.go index 364f17b..5254a1b 100644 --- a/complex64_tree/tree_v6_generated.go +++ b/complex64_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag complex64, nodeIndex uint, matchFunc MatchesFunc, re } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []complex64 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]complex64, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []complex64, nodeIndex uint) []complex64 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []complex64, nodeIndex uint) []complex64 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) complex64 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag complex64, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []complex64, nodeIndex uint, matchTag complex64, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag complex64, matchFunc Matches // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex64) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []complex64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []complex64 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []complex64, address patricia.IPv6Address, filterFunc FilterFunc) []complex64 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]complex64, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []complex64 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]complex64, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []complex64, address patricia.IPv6Address) []complex64 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []complex64, address patricia.IPv6Address) []complex64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []complex64, address patricia.IPv6Address) [ // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex64) } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex64) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []complex64, address patricia.IPv6Address) (bool, []complex64) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex6 if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex6 // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex6 if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/complex64_tree/tree_v6_manual.go b/complex64_tree/tree_v6_manual.go index d139c37..c4ea91f 100644 --- a/complex64_tree/tree_v6_manual.go +++ b/complex64_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]complex64, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/float32_tree/tree_v4.go b/float32_tree/tree_v4.go index 6a19894..1fc1a19 100644 --- a/float32_tree/tree_v4.go +++ b/float32_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag float32, nodeIndex uint, matchFunc MatchesFunc, repl } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []float32 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]float32, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []float32, nodeIndex uint) []float32 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []float32, nodeIndex uint) []float32 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) float32 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag float32, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []float32, nodeIndex uint, matchTag float32, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag float32, matchFunc MatchesFu // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float32) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []float32, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []float32 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []float32, address patricia.IPv4Address, filterFunc FilterFunc) []float32 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]float32, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []float32 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]float32, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []float32, address patricia.IPv4Address) []float32 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []float32, address patricia.IPv4Address) []float32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []float32, address patricia.IPv4Address) []f // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []float32, address patricia.IPv4Address) (bool, []float32) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/float32_tree/tree_v4_manual.go b/float32_tree/tree_v4_manual.go index b2cf555..61455df 100644 --- a/float32_tree/tree_v4_manual.go +++ b/float32_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]float32, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/float32_tree/tree_v6_generated.go b/float32_tree/tree_v6_generated.go index eaa0b29..2055cbf 100644 --- a/float32_tree/tree_v6_generated.go +++ b/float32_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag float32, nodeIndex uint, matchFunc MatchesFunc, repl } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []float32 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]float32, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []float32, nodeIndex uint) []float32 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []float32, nodeIndex uint) []float32 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) float32 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag float32, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []float32, nodeIndex uint, matchTag float32, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag float32, matchFunc MatchesFu // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float32) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []float32, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []float32 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []float32, address patricia.IPv6Address, filterFunc FilterFunc) []float32 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]float32, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []float32 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]float32, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []float32, address patricia.IPv6Address) []float32 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []float32, address patricia.IPv6Address) []float32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []float32, address patricia.IPv6Address) []f // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []float32, address patricia.IPv6Address) (bool, []float32) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/float32_tree/tree_v6_manual.go b/float32_tree/tree_v6_manual.go index d9cf06b..063dc21 100644 --- a/float32_tree/tree_v6_manual.go +++ b/float32_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]float32, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/float64_tree/tree_v4.go b/float64_tree/tree_v4.go index 121731d..82ae019 100644 --- a/float64_tree/tree_v4.go +++ b/float64_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag float64, nodeIndex uint, matchFunc MatchesFunc, repl } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []float64 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]float64, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []float64, nodeIndex uint) []float64 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []float64, nodeIndex uint) []float64 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) float64 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag float64, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []float64, nodeIndex uint, matchTag float64, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag float64, matchFunc MatchesFu // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float64) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []float64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []float64 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []float64, address patricia.IPv4Address, filterFunc FilterFunc) []float64 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]float64, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []float64 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]float64, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []float64, address patricia.IPv4Address) []float64 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []float64, address patricia.IPv4Address) []float64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []float64, address patricia.IPv4Address) []f // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []float64, address patricia.IPv4Address) (bool, []float64) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/float64_tree/tree_v4_manual.go b/float64_tree/tree_v4_manual.go index 8470d04..0f069db 100644 --- a/float64_tree/tree_v4_manual.go +++ b/float64_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]float64, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/float64_tree/tree_v6_generated.go b/float64_tree/tree_v6_generated.go index c686c12..35d80f0 100644 --- a/float64_tree/tree_v6_generated.go +++ b/float64_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag float64, nodeIndex uint, matchFunc MatchesFunc, repl } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []float64 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]float64, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []float64, nodeIndex uint) []float64 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []float64, nodeIndex uint) []float64 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) float64 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag float64, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []float64, nodeIndex uint, matchTag float64, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag float64, matchFunc MatchesFu // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float64) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []float64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []float64 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []float64, address patricia.IPv6Address, filterFunc FilterFunc) []float64 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]float64, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []float64 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]float64, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []float64, address patricia.IPv6Address) []float64 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []float64, address patricia.IPv6Address) []float64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []float64, address patricia.IPv6Address) []f // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []float64, address patricia.IPv6Address) (bool, []float64) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/float64_tree/tree_v6_manual.go b/float64_tree/tree_v6_manual.go index 8a46502..b5c4086 100644 --- a/float64_tree/tree_v6_manual.go +++ b/float64_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]float64, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int16_tree/tree_v4.go b/int16_tree/tree_v4.go index 453f413..cd0edf1 100644 --- a/int16_tree/tree_v4.go +++ b/int16_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag int16, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []int16 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int16, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []int16, nodeIndex uint) []int16 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []int16, nodeIndex uint) []int16 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int16 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int16, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []int16, nodeIndex uint, matchTag int16, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int16, matchFunc MatchesFunc // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int16) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []int16, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int16 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []int16, address patricia.IPv4Address, filterFunc FilterFunc) []int16 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int16, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []int16 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int16, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []int16, address patricia.IPv4Address) []int16 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int16, address patricia.IPv4Address) []int16 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []int16, address patricia.IPv4Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int16) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []int16, address patricia.IPv4Address) (bool, []int16) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int16_tree/tree_v4_manual.go b/int16_tree/tree_v4_manual.go index 9203aee..3221573 100644 --- a/int16_tree/tree_v4_manual.go +++ b/int16_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]int16, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int16_tree/tree_v6_generated.go b/int16_tree/tree_v6_generated.go index 1de227e..7f3fe09 100644 --- a/int16_tree/tree_v6_generated.go +++ b/int16_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag int16, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []int16 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int16, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []int16, nodeIndex uint) []int16 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []int16, nodeIndex uint) []int16 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int16 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int16, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []int16, nodeIndex uint, matchTag int16, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int16, matchFunc MatchesFunc // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int16) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []int16, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int16 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []int16, address patricia.IPv6Address, filterFunc FilterFunc) []int16 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int16, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []int16 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int16, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []int16, address patricia.IPv6Address) []int16 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int16, address patricia.IPv6Address) []int16 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []int16, address patricia.IPv6Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int16) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []int16, address patricia.IPv6Address) (bool, []int16) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int16_tree/tree_v6_manual.go b/int16_tree/tree_v6_manual.go index 6330e12..3d16e81 100644 --- a/int16_tree/tree_v6_manual.go +++ b/int16_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]int16, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int32_tree/tree_v4.go b/int32_tree/tree_v4.go index 94e9cea..0f70a5d 100644 --- a/int32_tree/tree_v4.go +++ b/int32_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag int32, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []int32 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int32, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []int32, nodeIndex uint) []int32 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []int32, nodeIndex uint) []int32 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int32 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int32, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []int32, nodeIndex uint, matchTag int32, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int32, matchFunc MatchesFunc // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int32) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []int32, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int32 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []int32, address patricia.IPv4Address, filterFunc FilterFunc) []int32 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int32, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []int32 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int32, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []int32, address patricia.IPv4Address) []int32 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int32, address patricia.IPv4Address) []int32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []int32, address patricia.IPv4Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []int32, address patricia.IPv4Address) (bool, []int32) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int32_tree/tree_v4_manual.go b/int32_tree/tree_v4_manual.go index 10dad35..1450a01 100644 --- a/int32_tree/tree_v4_manual.go +++ b/int32_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]int32, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int32_tree/tree_v6_generated.go b/int32_tree/tree_v6_generated.go index 1bfe879..73ddb66 100644 --- a/int32_tree/tree_v6_generated.go +++ b/int32_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag int32, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []int32 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int32, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []int32, nodeIndex uint) []int32 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []int32, nodeIndex uint) []int32 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int32 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int32, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []int32, nodeIndex uint, matchTag int32, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int32, matchFunc MatchesFunc // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int32) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []int32, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int32 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []int32, address patricia.IPv6Address, filterFunc FilterFunc) []int32 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int32, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []int32 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int32, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []int32, address patricia.IPv6Address) []int32 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int32, address patricia.IPv6Address) []int32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []int32, address patricia.IPv6Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []int32, address patricia.IPv6Address) (bool, []int32) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int32_tree/tree_v6_manual.go b/int32_tree/tree_v6_manual.go index c3d1768..572615d 100644 --- a/int32_tree/tree_v6_manual.go +++ b/int32_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]int32, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int64_tree/tree_v4.go b/int64_tree/tree_v4.go index a3278a2..20abcfc 100644 --- a/int64_tree/tree_v4.go +++ b/int64_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag int64, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []int64 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int64, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []int64, nodeIndex uint) []int64 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []int64, nodeIndex uint) []int64 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int64 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int64, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []int64, nodeIndex uint, matchTag int64, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int64, matchFunc MatchesFunc // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int64) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []int64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int64 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []int64, address patricia.IPv4Address, filterFunc FilterFunc) []int64 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int64, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []int64 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int64, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []int64, address patricia.IPv4Address) []int64 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int64, address patricia.IPv4Address) []int64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []int64, address patricia.IPv4Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []int64, address patricia.IPv4Address) (bool, []int64) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int64_tree/tree_v4_manual.go b/int64_tree/tree_v4_manual.go index 2c3bb08..11f70e2 100644 --- a/int64_tree/tree_v4_manual.go +++ b/int64_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]int64, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int64_tree/tree_v6_generated.go b/int64_tree/tree_v6_generated.go index ee13232..370f055 100644 --- a/int64_tree/tree_v6_generated.go +++ b/int64_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag int64, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []int64 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int64, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []int64, nodeIndex uint) []int64 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []int64, nodeIndex uint) []int64 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int64 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int64, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []int64, nodeIndex uint, matchTag int64, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int64, matchFunc MatchesFunc // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int64) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []int64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int64 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []int64, address patricia.IPv6Address, filterFunc FilterFunc) []int64 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int64, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []int64 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int64, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []int64, address patricia.IPv6Address) []int64 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int64, address patricia.IPv6Address) []int64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []int64, address patricia.IPv6Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []int64, address patricia.IPv6Address) (bool, []int64) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int64_tree/tree_v6_manual.go b/int64_tree/tree_v6_manual.go index 7e5b355..d49a930 100644 --- a/int64_tree/tree_v6_manual.go +++ b/int64_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]int64, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int8_tree/tree_v4.go b/int8_tree/tree_v4.go index 52b5b53..f775599 100644 --- a/int8_tree/tree_v4.go +++ b/int8_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag int8, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []int8 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int8, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []int8, nodeIndex uint) []int8 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []int8, nodeIndex uint) []int8 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int8 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int8, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []int8, nodeIndex uint, matchTag int8, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int8, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int8) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []int8, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int8 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []int8, address patricia.IPv4Address, filterFunc FilterFunc) []int8 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int8, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []int8 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int8, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []int8, address patricia.IPv4Address) []int8 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int8, address patricia.IPv4Address) []int8 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []int8, address patricia.IPv4Address) []int8 // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int8) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []int8, address patricia.IPv4Address) (bool, []int8) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int8_tree/tree_v4_manual.go b/int8_tree/tree_v4_manual.go index a6798f7..5f0aff9 100644 --- a/int8_tree/tree_v4_manual.go +++ b/int8_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]int8, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int8_tree/tree_v6_generated.go b/int8_tree/tree_v6_generated.go index 82a6c9c..04e6071 100644 --- a/int8_tree/tree_v6_generated.go +++ b/int8_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag int8, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []int8 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int8, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []int8, nodeIndex uint) []int8 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []int8, nodeIndex uint) []int8 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int8 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int8, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []int8, nodeIndex uint, matchTag int8, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int8, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int8) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []int8, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int8 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []int8, address patricia.IPv6Address, filterFunc FilterFunc) []int8 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int8, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []int8 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int8, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []int8, address patricia.IPv6Address) []int8 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int8, address patricia.IPv6Address) []int8 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []int8, address patricia.IPv6Address) []int8 // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int8) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []int8, address patricia.IPv6Address) (bool, []int8) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int8_tree/tree_v6_manual.go b/int8_tree/tree_v6_manual.go index 44850c3..e128d23 100644 --- a/int8_tree/tree_v6_manual.go +++ b/int8_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]int8, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int_tree/tree_v4.go b/int_tree/tree_v4.go index 2663142..a7f28d8 100644 --- a/int_tree/tree_v4.go +++ b/int_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag int, nodeIndex uint, matchFunc MatchesFunc, replaceF } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []int { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []int, nodeIndex uint) []int { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []int, nodeIndex uint) []int { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []int, nodeIndex uint, matchTag int, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag int, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []int, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []int, address patricia.IPv4Address, filterFunc FilterFunc) []int { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []int { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []int, address patricia.IPv4Address) []int { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int, address patricia.IPv4Address) []int { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []int, address patricia.IPv4Address) []int { // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []int, address patricia.IPv4Address) (bool, []int) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int_tree/tree_v4_manual.go b/int_tree/tree_v4_manual.go index eec9596..bde6a36 100644 --- a/int_tree/tree_v4_manual.go +++ b/int_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]int, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/int_tree/tree_v6_generated.go b/int_tree/tree_v6_generated.go index 62613cc..f4b16de 100644 --- a/int_tree/tree_v6_generated.go +++ b/int_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag int, nodeIndex uint, matchFunc MatchesFunc, replaceF } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []int { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]int, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []int, nodeIndex uint) []int { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []int, nodeIndex uint) []int { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []int, nodeIndex uint, matchTag int, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag int, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []int, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []int, address patricia.IPv6Address, filterFunc FilterFunc) []int { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]int, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []int { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]int, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []int, address patricia.IPv6Address) []int { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int, address patricia.IPv6Address) []int { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []int, address patricia.IPv6Address) []int { // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []int, address patricia.IPv6Address) (bool, []int) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/int_tree/tree_v6_manual.go b/int_tree/tree_v6_manual.go index b237ebd..d35ec8b 100644 --- a/int_tree/tree_v6_manual.go +++ b/int_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]int, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/rune_tree/tree_v4.go b/rune_tree/tree_v4.go index a199663..c0fcd7f 100644 --- a/rune_tree/tree_v4.go +++ b/rune_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag rune, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []rune { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]rune, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []rune, nodeIndex uint) []rune { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []rune, nodeIndex uint) []rune { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) rune { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag rune, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []rune, nodeIndex uint, matchTag rune, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag rune, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal rune) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []rune, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal rune) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []rune { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []rune, address patricia.IPv4Address, filterFunc FilterFunc) []rune { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]rune, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []rune { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]rune, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []rune, address patricia.IPv4Address) []rune { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []rune, address patricia.IPv4Address) []rune { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []rune, address patricia.IPv4Address) []rune // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, rune) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []rune, address patricia.IPv4Address) (bool, []rune) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/rune_tree/tree_v4_manual.go b/rune_tree/tree_v4_manual.go index 89dd3eb..b2fb65f 100644 --- a/rune_tree/tree_v4_manual.go +++ b/rune_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]rune, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/rune_tree/tree_v6_generated.go b/rune_tree/tree_v6_generated.go index 85d45b1..ec30078 100644 --- a/rune_tree/tree_v6_generated.go +++ b/rune_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag rune, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []rune { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]rune, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []rune, nodeIndex uint) []rune { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []rune, nodeIndex uint) []rune { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) rune { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag rune, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []rune, nodeIndex uint, matchTag rune, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag rune, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal rune) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []rune, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal rune) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []rune { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []rune, address patricia.IPv6Address, filterFunc FilterFunc) []rune { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]rune, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []rune { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]rune, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []rune, address patricia.IPv6Address) []rune { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []rune, address patricia.IPv6Address) []rune { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []rune, address patricia.IPv6Address) []rune // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, rune) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []rune, address patricia.IPv6Address) (bool, []rune) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/rune_tree/tree_v6_manual.go b/rune_tree/tree_v6_manual.go index f18debd..4235695 100644 --- a/rune_tree/tree_v6_manual.go +++ b/rune_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]rune, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/string_tree/tree_v4.go b/string_tree/tree_v4.go index ea618bd..b3fb336 100644 --- a/string_tree/tree_v4.go +++ b/string_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag string, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []string { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]string, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []string, nodeIndex uint) []string { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []string, nodeIndex uint) []string { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) string { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag string, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []string, nodeIndex uint, matchTag string, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag string, matchFunc MatchesFun // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal string) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []string, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal string) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []string { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []string, address patricia.IPv4Address, filterFunc FilterFunc) []string { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]string, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []string { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]string, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []string, address patricia.IPv4Address) []string { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []string, address patricia.IPv4Address) []string { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []string, address patricia.IPv4Address) []st // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, string) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []string, address patricia.IPv4Address) (bool, []string) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/string_tree/tree_v4_manual.go b/string_tree/tree_v4_manual.go index ed7fd55..ce1444c 100644 --- a/string_tree/tree_v4_manual.go +++ b/string_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]string, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/string_tree/tree_v6_generated.go b/string_tree/tree_v6_generated.go index 5be1c69..f04de5d 100644 --- a/string_tree/tree_v6_generated.go +++ b/string_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag string, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []string { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]string, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []string, nodeIndex uint) []string { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []string, nodeIndex uint) []string { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) string { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag string, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []string, nodeIndex uint, matchTag string, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag string, matchFunc MatchesFun // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal string) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []string, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal string) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []string { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []string, address patricia.IPv6Address, filterFunc FilterFunc) []string { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]string, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []string { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]string, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []string, address patricia.IPv6Address) []string { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []string, address patricia.IPv6Address) []string { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []string, address patricia.IPv6Address) []st // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, string) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []string, address patricia.IPv6Address) (bool, []string) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/string_tree/tree_v6_manual.go b/string_tree/tree_v6_manual.go index 2b21c78..ecbc077 100644 --- a/string_tree/tree_v6_manual.go +++ b/string_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]string, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/template/tree_v6_generated.go b/template/tree_v6_generated.go index 90711fb..a33695b 100644 --- a/template/tree_v6_generated.go +++ b/template/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag GeneratedType, nodeIndex uint, matchFunc MatchesFunc } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []GeneratedType { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]GeneratedType, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []GeneratedType, nodeIndex uint) []GeneratedType { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []GeneratedType, nodeIndex uint) []GeneratedType { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) GeneratedType { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag GeneratedType, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []GeneratedType, nodeIndex uint, matchTag GeneratedType, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag GeneratedType, matchFunc Mat // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal GeneratedType) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []GeneratedType, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal GeneratedType) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []GeneratedType { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []GeneratedType, address patricia.IPv6Address, filterFunc FilterFunc) []GeneratedType { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]GeneratedType, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []GeneratedType { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]GeneratedType, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []GeneratedType, address patricia.IPv6Address) []GeneratedType { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []GeneratedType, address patricia.IPv6Address) []GeneratedType { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []GeneratedType, address patricia.IPv6Addres // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, GeneratedTy } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []GeneratedType) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []GeneratedType, address patricia.IPv6Address) (bool, []GeneratedType) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []Generate if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []Generate // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []Generate if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v4.go b/uint16_tree/tree_v4.go index fa701e3..85ec32a 100644 --- a/uint16_tree/tree_v4.go +++ b/uint16_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag uint16, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []uint16 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint16, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []uint16, nodeIndex uint) []uint16 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []uint16, nodeIndex uint) []uint16 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint16 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint16, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []uint16, nodeIndex uint, matchTag uint16, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint16, matchFunc MatchesFun // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint16) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []uint16, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint16 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []uint16, address patricia.IPv4Address, filterFunc FilterFunc) []uint16 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint16, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint16 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint16, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []uint16, address patricia.IPv4Address) []uint16 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint16, address patricia.IPv4Address) []uint16 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint16, address patricia.IPv4Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint16) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []uint16, address patricia.IPv4Address) (bool, []uint16) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v4_manual.go b/uint16_tree/tree_v4_manual.go index 1d8927a..9796aab 100644 --- a/uint16_tree/tree_v4_manual.go +++ b/uint16_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]uint16, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/uint16_tree/tree_v6_generated.go b/uint16_tree/tree_v6_generated.go index 3e6a5e9..084947d 100644 --- a/uint16_tree/tree_v6_generated.go +++ b/uint16_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag uint16, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []uint16 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint16, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []uint16, nodeIndex uint) []uint16 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []uint16, nodeIndex uint) []uint16 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint16 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint16, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []uint16, nodeIndex uint, matchTag uint16, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint16, matchFunc MatchesFun // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint16) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []uint16, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint16 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []uint16, address patricia.IPv6Address, filterFunc FilterFunc) []uint16 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint16, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint16 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint16, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []uint16, address patricia.IPv6Address) []uint16 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint16, address patricia.IPv6Address) []uint16 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint16, address patricia.IPv6Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint16) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []uint16, address patricia.IPv6Address) (bool, []uint16) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v6_manual.go b/uint16_tree/tree_v6_manual.go index 8dc9a66..3a11bb8 100644 --- a/uint16_tree/tree_v6_manual.go +++ b/uint16_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]uint16, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/uint32_tree/tree_v4.go b/uint32_tree/tree_v4.go index 22d8a2f..ae202f9 100644 --- a/uint32_tree/tree_v4.go +++ b/uint32_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag uint32, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []uint32 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint32, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []uint32, nodeIndex uint) []uint32 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []uint32, nodeIndex uint) []uint32 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint32 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint32, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []uint32, nodeIndex uint, matchTag uint32, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint32, matchFunc MatchesFun // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint32) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []uint32, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint32 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []uint32, address patricia.IPv4Address, filterFunc FilterFunc) []uint32 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint32, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint32 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint32, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []uint32, address patricia.IPv4Address) []uint32 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint32, address patricia.IPv4Address) []uint32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint32, address patricia.IPv4Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []uint32, address patricia.IPv4Address) (bool, []uint32) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint32_tree/tree_v4_manual.go b/uint32_tree/tree_v4_manual.go index 1d78f1d..02e3146 100644 --- a/uint32_tree/tree_v4_manual.go +++ b/uint32_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]uint32, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/uint32_tree/tree_v6_generated.go b/uint32_tree/tree_v6_generated.go index e1334e4..22ff55a 100644 --- a/uint32_tree/tree_v6_generated.go +++ b/uint32_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag uint32, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []uint32 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint32, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []uint32, nodeIndex uint) []uint32 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []uint32, nodeIndex uint) []uint32 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint32 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint32, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []uint32, nodeIndex uint, matchTag uint32, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint32, matchFunc MatchesFun // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint32) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []uint32, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint32 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []uint32, address patricia.IPv6Address, filterFunc FilterFunc) []uint32 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint32, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint32 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint32, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []uint32, address patricia.IPv6Address) []uint32 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint32, address patricia.IPv6Address) []uint32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint32, address patricia.IPv6Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []uint32, address patricia.IPv6Address) (bool, []uint32) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint32_tree/tree_v6_manual.go b/uint32_tree/tree_v6_manual.go index df2ca7f..339638a 100644 --- a/uint32_tree/tree_v6_manual.go +++ b/uint32_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]uint32, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/uint64_tree/tree_v4.go b/uint64_tree/tree_v4.go index 11072be..a442044 100644 --- a/uint64_tree/tree_v4.go +++ b/uint64_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag uint64, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []uint64 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint64, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []uint64, nodeIndex uint) []uint64 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []uint64, nodeIndex uint) []uint64 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint64 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint64, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []uint64, nodeIndex uint, matchTag uint64, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint64, matchFunc MatchesFun // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint64) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []uint64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint64 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []uint64, address patricia.IPv4Address, filterFunc FilterFunc) []uint64 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint64, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint64 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint64, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []uint64, address patricia.IPv4Address) []uint64 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint64, address patricia.IPv4Address) []uint64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint64, address patricia.IPv4Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []uint64, address patricia.IPv4Address) (bool, []uint64) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint64_tree/tree_v4_manual.go b/uint64_tree/tree_v4_manual.go index e3b4a74..45b1ec0 100644 --- a/uint64_tree/tree_v4_manual.go +++ b/uint64_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]uint64, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/uint64_tree/tree_v6_generated.go b/uint64_tree/tree_v6_generated.go index bb0b14f..3378db6 100644 --- a/uint64_tree/tree_v6_generated.go +++ b/uint64_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag uint64, nodeIndex uint, matchFunc MatchesFunc, repla } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []uint64 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint64, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []uint64, nodeIndex uint) []uint64 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []uint64, nodeIndex uint) []uint64 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint64 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint64, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []uint64, nodeIndex uint, matchTag uint64, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint64, matchFunc MatchesFun // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint64) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []uint64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint64 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []uint64, address patricia.IPv6Address, filterFunc FilterFunc) []uint64 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint64, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint64 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint64, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []uint64, address patricia.IPv6Address) []uint64 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint64, address patricia.IPv6Address) []uint64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint64, address patricia.IPv6Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []uint64, address patricia.IPv6Address) (bool, []uint64) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint64_tree/tree_v6_manual.go b/uint64_tree/tree_v6_manual.go index a8b29af..d88b6c9 100644 --- a/uint64_tree/tree_v6_manual.go +++ b/uint64_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]uint64, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/uint8_tree/tree_v4.go b/uint8_tree/tree_v4.go index fe7f51f..37a3f25 100644 --- a/uint8_tree/tree_v4.go +++ b/uint8_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag uint8, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []uint8 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint8, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []uint8, nodeIndex uint) []uint8 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []uint8, nodeIndex uint) []uint8 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint8 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint8, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []uint8, nodeIndex uint, matchTag uint8, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint8, matchFunc MatchesFunc // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint8) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []uint8, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint8 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []uint8, address patricia.IPv4Address, filterFunc FilterFunc) []uint8 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint8, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint8 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint8, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []uint8, address patricia.IPv4Address) []uint8 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint8, address patricia.IPv4Address) []uint8 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint8, address patricia.IPv4Address) []uin // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint8) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []uint8, address patricia.IPv4Address) (bool, []uint8) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint8_tree/tree_v4_manual.go b/uint8_tree/tree_v4_manual.go index 9dcc911..dfb4e14 100644 --- a/uint8_tree/tree_v4_manual.go +++ b/uint8_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]uint8, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/uint8_tree/tree_v6_generated.go b/uint8_tree/tree_v6_generated.go index 2e647a6..301dc2e 100644 --- a/uint8_tree/tree_v6_generated.go +++ b/uint8_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag uint8, nodeIndex uint, matchFunc MatchesFunc, replac } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []uint8 { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint8, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []uint8, nodeIndex uint) []uint8 { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []uint8, nodeIndex uint) []uint8 { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint8 { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint8, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []uint8, nodeIndex uint, matchTag uint8, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint8, matchFunc MatchesFunc // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint8) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []uint8, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint8 { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []uint8, address patricia.IPv6Address, filterFunc FilterFunc) []uint8 { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint8, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint8 { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint8, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []uint8, address patricia.IPv6Address) []uint8 { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint8, address patricia.IPv6Address) []uint8 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint8, address patricia.IPv6Address) []uin // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint8) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []uint8, address patricia.IPv6Address) (bool, []uint8) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint8_tree/tree_v6_manual.go b/uint8_tree/tree_v6_manual.go index e228cbb..5aa79a6 100644 --- a/uint8_tree/tree_v6_manual.go +++ b/uint8_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]uint8, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/uint_tree/tree_v4.go b/uint_tree/tree_v4.go index 9320e3b..fab806a 100644 --- a/uint_tree/tree_v4.go +++ b/uint_tree/tree_v4.go @@ -78,18 +78,13 @@ func (t *TreeV4) addTag(tag uint, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV4) tagsForNode(nodeIndex uint) []uint { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint, 0) - } -} -func (t *TreeV4) tagsForNodeAppend(ret []uint, nodeIndex uint) []uint { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV4) tagsForNode(ret []uint, nodeIndex uint) []uint { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV4) deleteTag(buf []uint, nodeIndex uint, matchTag uint, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV4) deleteTag(nodeIndex uint, matchTag uint, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint) int { +// - uses input slice to reduce allocations +func (t *TreeV4) Delete(buf []uint, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV4) FindTagsWithFilter(ret []uint, address patricia.IPv4Address, filterFunc FilterFunc) []uint { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV4) FindTags(ret []uint, address patricia.IPv4Address) []uint { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint, address patricia.IPv4Address) []uint { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint, address patricia.IPv4Address) []uint // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint) { +// - may return nil if nothing found +func (t *TreeV4) FindDeepestTags(ret []uint, address patricia.IPv4Address) (bool, []uint) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint_tree/tree_v4_manual.go b/uint_tree/tree_v4_manual.go index 182c301..efc8580 100644 --- a/uint_tree/tree_v4_manual.go +++ b/uint_tree/tree_v4_manual.go @@ -23,7 +23,9 @@ func (t *TreeV4) newNode(address patricia.IPv4Address, prefixLength uint) uint { } func (t *TreeV4) print() { + buf := make([]uint, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } diff --git a/uint_tree/tree_v6_generated.go b/uint_tree/tree_v6_generated.go index 8bd24de..2f975e2 100644 --- a/uint_tree/tree_v6_generated.go +++ b/uint_tree/tree_v6_generated.go @@ -78,18 +78,13 @@ func (t *TreeV6) addTag(tag uint, nodeIndex uint, matchFunc MatchesFunc, replace } return ret } -func (t *TreeV6) tagsForNode(nodeIndex uint) []uint { - if ret := t.tagsForNodeAppend(nil, nodeIndex); ret != nil { - return ret - } else { - // NB: for compatibility with the old tagsForNode() - // old comment: useful for base cases where we haven't found anything - return make([]uint, 0) - } -} -func (t *TreeV6) tagsForNodeAppend(ret []uint, nodeIndex uint) []uint { +// return the tags at the input node index - appending to the input slice +// - nil if none found +// - ret is only appended to +func (t *TreeV6) tagsForNode(ret []uint, nodeIndex uint) []uint { if nodeIndex == 0 { + // useful for base cases where we haven't found anything return ret } @@ -119,13 +114,17 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint { } // delete tags at the input node, returning how many were deleted, and how many are left -func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint, matchFunc MatchesFunc) (int, int) { - // TODO: this could be done much more efficiently - +// - uses input slice to reduce allocations +func (t *TreeV6) deleteTag(buf []uint, nodeIndex uint, matchTag uint, matchFunc MatchesFunc) (int, int) { // get tags - tags := t.tagsForNode(nodeIndex) + buf = buf[:0] + buf = t.tagsForNode(buf, nodeIndex) + if len(buf) == 0 { + return 0, 0 + } // delete tags + // TODO: this could be done smarter - delete in place? for i := 0; i < t.nodes[nodeIndex].TagCount; i++ { delete(t.tags, (uint64(nodeIndex)<<32)+uint64(i)) } @@ -134,7 +133,7 @@ func (t *TreeV6) deleteTag(nodeIndex uint, matchTag uint, matchFunc MatchesFunc) // put them back deleteCount := 0 keepCount := 0 - for _, tag := range tags { + for _, tag := range buf { if matchFunc(tag, matchTag) { deleteCount++ } else { @@ -320,7 +319,8 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed -func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint) int { +// - uses input slice to reduce allocations +func (t *TreeV6) Delete(buf []uint, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -381,7 +381,7 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // delete matching tags - deleteCount, remainingTagCount := t.deleteTag(targetNodeIndex, matchVal, matchFunc) + deleteCount, remainingTagCount := t.deleteTag(buf, targetNodeIndex, matchVal, matchFunc) if remainingTagCount > 0 { // target node still has tags - we're not deleting it return deleteCount @@ -464,92 +464,34 @@ func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, mat } // FindTagsWithFilter finds all matching tags that passes the filter function -func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint { - root := &t.nodes[1] - if filterFunc == nil { - return t.FindTags(address) - } +// - input slice is used to reduce allocations - will be reset before it's used +func (t *TreeV6) FindTagsWithFilter(ret []uint, address patricia.IPv6Address, filterFunc FilterFunc) []uint { + ret = t.FindTags(ret, address) - var matchCount uint - ret := make([]uint, 0) - - if root.TagCount > 0 { - for _, tag := range t.tagsForNode(1) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if address.Length == 0 { - // caller just looking for root tags + if len(ret) == 0 || filterFunc == nil { return ret } - var nodeIndex uint - if !address.IsLeftBitSet() { - nodeIndex = root.Left - } else { - nodeIndex = root.Right - } - - // traverse the tree - count := 0 - for { - count++ - if nodeIndex == 0 { - return ret - } - node := &t.nodes[nodeIndex] - - matchCount = node.MatchCount(address) - if matchCount < node.prefixLength { - // didn't match the entire node - we're done - return ret - } - - // matched the full node - get its tags, then chop off the bits we've already matched and continue - if node.TagCount > 0 { - for _, tag := range t.tagsForNode(nodeIndex) { - if filterFunc(tag) { - ret = append(ret, tag) - } - } - } - - if matchCount == address.Length { - // exact match - we're done - return ret - } - - // there's still more address - keep traversing - address.ShiftLeft(matchCount) - if !address.IsLeftBitSet() { - nodeIndex = node.Left - } else { - nodeIndex = node.Right + retPos := 0 + for _, val := range ret { + if filterFunc(val) { + ret[retPos] = val + retPos++ } } + return ret[:retPos] } -// FindTags finds all matching tags for given address -func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint { - if ret := t.FindTagsAppend(nil, address); ret != nil { - // NB: the nil error is for compatibility with the old FindTags() - return ret - } else { - // NB: the alloc is for compatibility with the old FindTags() - return make([]uint, 0) - } -} +// FindTags finds all matching tags for given address and appends them to ret +// - may return nil if none found +func (t *TreeV6) FindTags(ret []uint, address patricia.IPv6Address) []uint { + ret = ret[:0] -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint, address patricia.IPv6Address) []uint { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, 1) + ret = t.tagsForNode(ret, 1) } if address.Length == 0 { @@ -581,7 +523,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint, address patricia.IPv6Address) []uint // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNodeAppend(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex) } if matchCount == address.Length { @@ -658,8 +600,10 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - returns empty array if nothing found -func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint) { +// - may return nil if nothing found +func (t *TreeV6) FindDeepestTags(ret []uint, address patricia.IPv6Address) (bool, []uint) { + ret = ret[:0] + root := &t.nodes[1] var found bool var retTagIndex uint @@ -671,7 +615,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint) { if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } var nodeIndex uint @@ -684,14 +628,14 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint) { // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -702,7 +646,7 @@ func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint) { if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(retTagIndex) + return found, t.tagsForNode(ret, retTagIndex) } // there's still more address - keep traversing diff --git a/uint_tree/tree_v6_manual.go b/uint_tree/tree_v6_manual.go index 04596fd..d34c30d 100644 --- a/uint_tree/tree_v6_manual.go +++ b/uint_tree/tree_v6_manual.go @@ -23,7 +23,9 @@ func (t *TreeV6) newNode(address patricia.IPv6Address, prefixLength uint) uint { } func (t *TreeV6) print() { + buf := make([]uint, 0) for i := range t.nodes { - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(uint(i))) + buf = buf[:0] + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) } } From 057bd24994bb430e1a38d4b95546d2341f90df65 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Tue, 31 Aug 2021 03:42:31 +0000 Subject: [PATCH 09/19] Updated BenchmarkFindTags to use the buffer properly Benchmark results: cpu: Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz OLD: BenchmarkFindTags-5 3721257 294.3 ns/op 160 B/op 6 allocs/op NEW: BenchmarkFindTags-5 41273214 28.12 ns/op 0 B/op 0 allocs/op --- template/tree_v4_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/tree_v4_test.go b/template/tree_v4_test.go index 20275c2..0ff45e0 100644 --- a/template/tree_v4_test.go +++ b/template/tree_v4_test.go @@ -34,7 +34,7 @@ func BenchmarkFindTags(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { address := patricia.NewIPv4Address(uint32(2156823809), 32) - tree.FindTags(buf, address) + buf = tree.FindTags(buf, address) } } From 7242eff69658e64d51a618b7d5648daaf6fe5e1c Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Tue, 31 Aug 2021 16:48:33 +0000 Subject: [PATCH 10/19] Renamed newer methods with "Append" suffix, added non-suffixed helpers renamed the following to better describe their function: - FindTags -> FindTagsAppend - FindDeepestTags -> FindDeepestTagsAppend - Delete -> DeleteWithBuffer Created new methods with the original names, that allocate slices and pass them into the *Append/*WithBuffer methods. This provides easier migration to new code, and simplifies use cases that can't reuse buffers. --- template/tree_v4.go | 53 +++++++++++---- template/tree_v4_bulk_test.go | 4 +- template/tree_v4_test.go | 121 +++++++++++++++++++++------------- template/tree_v6_test.go | 104 ++++++++++++++++------------- 4 files changed, 177 insertions(+), 105 deletions(-) diff --git a/template/tree_v4.go b/template/tree_v4.go index 03cb5a6..8b0c577 100644 --- a/template/tree_v4.go +++ b/template/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal GeneratedType) int { + return t.DeleteWithBuffer(make([]GeneratedType, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []GeneratedType, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal GeneratedType) int { +func (t *TreeV4) DeleteWithBuffer(buf []GeneratedType, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal GeneratedType) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []GeneratedType, address patricia.IPv4Address, match } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []GeneratedType, address patricia.IPv4Address, filterFunc FilterFunc) []GeneratedType { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []GeneratedType { + ret := make([]GeneratedType, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []GeneratedType, address patricia.IPv4Address, filterFunc FilterFunc) []GeneratedType { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []GeneratedType, address patricia.IPv4Ad return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []GeneratedType, address patricia.IPv4Address) []GeneratedType { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []GeneratedType { + ret := make([]GeneratedType, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []GeneratedType, address patricia.IPv4Address) []GeneratedType { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, GeneratedTy } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []GeneratedType, address patricia.IPv4Address) (bool, []GeneratedType) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []GeneratedType) { + ret := make([]GeneratedType, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []GeneratedType, address patricia.IPv4Address) (bool, []GeneratedType) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/template/tree_v4_bulk_test.go b/template/tree_v4_bulk_test.go index 2a377b4..8b1d584 100644 --- a/template/tree_v4_bulk_test.go +++ b/template/tree_v4_bulk_test.go @@ -84,7 +84,7 @@ func TestBulkLoad(t *testing.T) { panic(fmt.Sprintf("search: Could not parse IP '%s': %s", address, err)) } if v4 != nil { - foundTags := tree.FindTags(buf, *v4) + foundTags := tree.FindTagsAppend(buf, *v4) if assert.True(t, len(foundTags) > 0, "Couldn't find tags for "+address) { assert.True(t, tag == foundTags[len(foundTags)-1]) } @@ -95,7 +95,7 @@ func TestBulkLoad(t *testing.T) { // delete the tags now //fmt.Printf("Deleting %s: %s\n", address, tag) - deleteCount := tree.Delete(buf, *v4, func(a GeneratedType, b GeneratedType) bool { return a == b }, tag) + deleteCount := tree.DeleteWithBuffer(buf, *v4, func(a GeneratedType, b GeneratedType) bool { return a == b }, tag) assert.Equal(t, 1, deleteCount, "Tried deleting tag") //tree.print() } else if v6 == nil { diff --git a/template/tree_v4_test.go b/template/tree_v4_test.go index 0ff45e0..54d06a5 100644 --- a/template/tree_v4_test.go +++ b/template/tree_v4_test.go @@ -17,7 +17,7 @@ func ipv4FromBytes(bytes []byte, length int) patricia.IPv4Address { } } -func BenchmarkFindTags(b *testing.B) { +func BenchmarkFindTagsAppend(b *testing.B) { tagA := "tagA" tagB := "tagB" tagC := "tagC" @@ -34,7 +34,8 @@ func BenchmarkFindTags(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { address := patricia.NewIPv4Address(uint32(2156823809), 32) - buf = tree.FindTags(buf, address) + buf = buf[:0] + buf = tree.FindTagsAppend(buf, address) } } @@ -194,21 +195,24 @@ func TestTree2(t *testing.T) { assert.True(t, found) assert.Equal(t, "j", tag) + tags = tags[:0] v4, _, _ = patricia.ParseIPFromString("185.76.10.146") - found, tags = tree.FindDeepestTags(tags, *v4) + found, tags = tree.FindDeepestTagsAppend(tags, *v4) assert.True(t, found) assert.Equal(t, "j", tags[0]) assert.Equal(t, "k", tags[1]) // test searching for addresses with no leaf nodes + tags = tags[:0] v4, _, _ = patricia.ParseIPFromString("1.2.3.4") - found, tags = tree.FindDeepestTags(tags, *v4) + found, tags = tree.FindDeepestTagsAppend(tags, *v4) assert.True(t, found) assert.Equal(t, "foo", tags[0]) assert.Equal(t, "bar", tags[1]) + tags = tags[:0] v4, _, _ = patricia.ParseIPFromString("1.2.3.5") - found, tags = tree.FindDeepestTags(tags, *v4) + found, tags = tree.FindDeepestTagsAppend(tags, *v4) assert.True(t, found) assert.Equal(t, "foo", tags[0]) assert.Equal(t, "bar", tags[1]) @@ -219,15 +223,17 @@ func TestTree2(t *testing.T) { assert.Equal(t, "foo", tag) // test searching for an address that has nothing + tags = tags[:0] v4, _, _ = patricia.ParseIPFromString("9.9.9.9") - found, tags = tree.FindDeepestTags(tags, *v4) + found, tags = tree.FindDeepestTagsAppend(tags, *v4) assert.False(t, found) assert.NotNil(t, tags) assert.Equal(t, 0, len(tags)) // test searching for an empty address + tags = tags[:0] v4, _, _ = patricia.ParseIPFromString("9.9.9.9/0") - found, tags = tree.FindDeepestTags(tags, *v4) + found, tags = tree.FindDeepestTagsAppend(tags, *v4) assert.False(t, found) assert.NotNil(t, tags) assert.Equal(t, 0, len(tags)) @@ -239,7 +245,8 @@ func TestTree2(t *testing.T) { tree.Add(*v4, "root_node", nil) v4, _, _ = patricia.ParseIPFromString("9.9.9.9/0") - found, tags = tree.FindDeepestTags(tags, *v4) + tags = tags[:0] + found, tags = tree.FindDeepestTagsAppend(tags, *v4) assert.True(t, found) assert.NotNil(t, tags) assert.Equal(t, 1, len(tags)) @@ -279,13 +286,15 @@ func TestAddressReusable(t *testing.T) { assert.Equal(t, "Hello", tag) // search again with same address - tags = tree.FindTags(tags, *v4) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, *v4) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Hello", tags[0]) } // search again with same address - tags = tree.FindTags(tags, *v4) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, *v4) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Hello", tags[0]) } @@ -345,13 +354,13 @@ func TestSimpleTree2(t *testing.T) { matchFunc := func(a GeneratedType, b GeneratedType) bool { return a == b } - deleteCount := tree.Delete(buf, *ipA, matchFunc, "A") + deleteCount := tree.DeleteWithBuffer(buf, *ipA, matchFunc, "A") assert.Equal(t, 1, deleteCount) - deleteCount = tree.Delete(buf, *ipB, matchFunc, "B") + deleteCount = tree.DeleteWithBuffer(buf, *ipB, matchFunc, "B") assert.Equal(t, 1, deleteCount) - deleteCount = tree.Delete(buf, *ipC, matchFunc, "C") + deleteCount = tree.DeleteWithBuffer(buf, *ipC, matchFunc, "C") assert.Equal(t, 1, deleteCount) - deleteCount = tree.Delete(buf, *ipD, matchFunc, "D") + deleteCount = tree.DeleteWithBuffer(buf, *ipD, matchFunc, "D") assert.Equal(t, 1, deleteCount) // should have zero logical nodes except for root @@ -369,13 +378,15 @@ func TestSimpleTree(t *testing.T) { assert.Equal(t, 1, count) } - tags = tree.FindTags(tags, ipv4FromBytes([]byte{127, 0, 0, 1}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{127, 0, 0, 1}, 32)) if assert.Equal(t, 32, len(tags)) { assert.Equal(t, "Tag-32", tags[31].(string)) assert.Equal(t, "Tag-31", tags[30].(string)) } - tags = tree.FindTags(tags, ipv4FromBytes([]byte{63, 3, 0, 1}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{63, 3, 0, 1}, 32)) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Tag-1", tags[0].(string)) } @@ -414,7 +425,8 @@ func TestSimpleTree(t *testing.T) { assert.True(t, countIncreased) assert.Equal(t, 2, count) - tags = tree.FindTags(tags, patricia.IPv4Address{}) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, patricia.IPv4Address{}) if assert.Equal(t, 2, len(tags)) { assert.Equal(t, "root1", tags[0].(string)) assert.Equal(t, "root2", tags[1].(string)) @@ -442,7 +454,7 @@ func tagArraysEqual(a []GeneratedType, b []string) bool { return true } -func TestTree1FindTags(t *testing.T) { +func TestTree1FindTagsAppend(t *testing.T) { tags := make([]GeneratedType, 0) tagA := "tagA" @@ -457,23 +469,27 @@ func TestTree1FindTags(t *testing.T) { tree.Add(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 142, 133, 1}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{128, 142, 133, 1}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagZ})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // three tags in a hierarchy - get just the first - tags = tree.FindTags(tags, ipv4FromBytes([]byte{162, 1, 0, 5}, 30)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{162, 1, 0, 5}, 30)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagZ})) // three tags in hierarchy - get none - tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 0, 0, 0}, 1)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{1, 0, 0, 0}, 1)) assert.True(t, tagArraysEqual(tags, []string{tagZ})) } -func TestTree1FindTagsWithFilter(t *testing.T) { +func TestTree1FindTagsWithFilterAppend(t *testing.T) { tags := make([]GeneratedType, 0) tagA := "tagA" @@ -492,19 +508,23 @@ func TestTree1FindTagsWithFilter(t *testing.T) { tree.Add(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags = tree.FindTagsWithFilter(tags, ipv4FromBytes([]byte{128, 142, 133, 1}, 32), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{128, 142, 133, 1}, 32), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags = tree.FindTagsWithFilter(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - get just the first - tags = tree.FindTagsWithFilter(tags, ipv4FromBytes([]byte{162, 1, 0, 5}, 30), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{162, 1, 0, 5}, 30), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagB})) // three tags in hierarchy - get none - tags = tree.FindTagsWithFilter(tags, ipv4FromBytes([]byte{1, 0, 0, 0}, 1), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{1, 0, 0, 0}, 1), filterFunc) assert.Zero(t, len(tags)) } @@ -525,26 +545,31 @@ func TestRootNode(t *testing.T) { tree.Add(patricia.IPv4Address{}, tagB, nil) // query the root node with no address - tags = tree.FindTags(tags, patricia.IPv4Address{}) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, patricia.IPv4Address{}) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // query a node that doesn't exist - tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // create a new /16 node with C & D tree.Add(ipv4FromBytes([]byte{1, 2, 3, 4}, 16), tagC, nil) tree.Add(ipv4FromBytes([]byte{1, 2, 3, 4}, 16), tagD, nil) - tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 16)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 16)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) // create a node under the /16 node tree.Add(ipv4FromBytes([]byte{1, 2, 3, 4}, 32), tagZ, nil) - tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD, tagZ})) // check the /24 and make sure we still get the /16 and root - tags = tree.FindTags(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 24)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{1, 2, 3, 4}, 24)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) } @@ -607,7 +632,7 @@ func TestSet(t *testing.T) { assert.Equal(t, "tagD", tag) // now delete the tag - delCount := tree.Delete(buf, address, func(a GeneratedType, b GeneratedType) bool { return true }, "") + delCount := tree.DeleteWithBuffer(buf, address, func(a GeneratedType, b GeneratedType) bool { return true }, "") assert.Equal(t, 1, delCount) // verify it's gone - should get the parent @@ -659,43 +684,47 @@ func TestDelete1(t *testing.T) { tags = tags[:0] // three tags in a hierarchy - ask for an exact match, receive all 3 and the root - tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // 1. delete a tag that doesn't exist count := 0 - count = tree.Delete(tags, ipv4FromBytes([]byte{9, 9, 9, 9}, 32), matchFunc, "bad tag") + count = tree.DeleteWithBuffer(tags, ipv4FromBytes([]byte{9, 9, 9, 9}, 32), matchFunc, "bad tag") assert.Equal(t, 0, count) assert.Equal(t, 4, tree.countNodes(1)) assert.Equal(t, 4, tree.countTags(1)) // 2. delete a tag on an address that exists, but doesn't have the tag - count = tree.Delete(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "bad tag") + count = tree.DeleteWithBuffer(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "bad tag") assert.Equal(t, 0, count) // verify - tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) assert.Equal(t, 4, tree.countNodes(1)) assert.Equal(t, 4, tree.countTags(1)) // 3. delete the default/root tag - count = tree.Delete(tags, ipv4FromBytes([]byte{0, 0, 0, 0}, 0), matchFunc, "tagZ") + count = tree.DeleteWithBuffer(tags, ipv4FromBytes([]byte{0, 0, 0, 0}, 0), matchFunc, "tagZ") assert.Equal(t, 1, count) assert.Equal(t, 4, tree.countNodes(1)) // doesn't delete anything assert.Equal(t, 3, tree.countTags(1)) assert.Equal(t, 0, len(tree.availableIndexes)) // three tags in a hierarchy - ask for an exact match, receive all 3, not the root, which we deleted - tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC})) // 4. delete tagA - count = tree.Delete(tags, ipv4FromBytes([]byte{128, 0, 0, 0}, 7), matchFunc, "tagA") + count = tree.DeleteWithBuffer(tags, ipv4FromBytes([]byte{128, 0, 0, 0}, 7), matchFunc, "tagA") assert.Equal(t, 1, count) // verify - tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagC})) assert.Equal(t, 3, tree.countNodes(1)) assert.Equal(t, 2, tree.countTags(1)) @@ -703,11 +732,12 @@ func TestDelete1(t *testing.T) { assert.Equal(t, uint(2), tree.availableIndexes[0]) // 5. delete tag B - count = tree.Delete(tags, ipv4FromBytes([]byte{128, 0, 0, 0}, 2), matchFunc, "tagB") + count = tree.DeleteWithBuffer(tags, ipv4FromBytes([]byte{128, 0, 0, 0}, 2), matchFunc, "tagB") assert.Equal(t, 1, count) // verify - tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{tagC})) assert.Equal(t, 2, tree.countNodes(1)) assert.Equal(t, 1, tree.countTags(1)) @@ -728,11 +758,12 @@ func TestDelete1(t *testing.T) { assert.Equal(t, "tagE", tree.tagsForNode(tags, 3)[0]) // 6. delete tag C - count = tree.Delete(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "tagC") + count = tree.DeleteWithBuffer(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "tagC") assert.Equal(t, 1, count) // verify - tags = tree.FindTags(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32)) assert.True(t, tagArraysEqual(tags, []string{})) assert.Equal(t, 2, tree.countNodes(1)) assert.Equal(t, 2, tree.countTags(1)) diff --git a/template/tree_v6_test.go b/template/tree_v6_test.go index 472cb20..2458855 100644 --- a/template/tree_v6_test.go +++ b/template/tree_v6_test.go @@ -39,7 +39,7 @@ func BenchmarkFindTagsV6(b *testing.B) { address := ipv6FromString("2001:db7:0:0:0:0:2:1/128", 32) b.ResetTimer() for n := 0; n < b.N; n++ { - tree.FindTags(buf, address) + tree.FindTagsAppend(buf, address) buf = buf[:0] } } @@ -67,13 +67,15 @@ func TestSimpleTreeV6(t *testing.T) { assert.Equal(t, 1, count) } - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) if assert.Equal(t, 128, len(tags)) { assert.Equal(t, "Tag-128", tags[127].(string)) assert.Equal(t, "Tag-32", tags[31].(string)) } - tags = tree.FindTags(tags, ipv6FromString("4001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("4001:db8:0:0:0:0:2:1/128", 128)) if assert.Equal(t, 1, len(tags)) { assert.Equal(t, "Tag-1", tags[0]) } @@ -122,7 +124,8 @@ func TestSimpleTreeV6(t *testing.T) { assert.True(t, countIncreased) assert.Equal(t, 2, count) - tags = tree.FindTags(tags, patricia.IPv6Address{}) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, patricia.IPv6Address{}) if assert.Equal(t, 2, len(tags)) { assert.Equal(t, "root1", tags[0].(string)) assert.Equal(t, "root2", tags[1].(string)) @@ -144,23 +147,29 @@ func TestTree1V6(t *testing.T) { tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagZ})) - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagZ})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // three tags in a hierarchy - get just the first - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagZ})) // three tags in hierarchy - get none - tags = tree.FindTags(tags, ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagZ})) - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66)) assert.True(t, tagArraysEqual(tags, []string{tagZ})) } @@ -183,23 +192,29 @@ func TestTree1V6WithFilter(t *testing.T) { tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), tagC, nil) // three tags in a hierarchy - ask for all but the most specific - tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:0/128", 128), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) - tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 127), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - ask for an exact match, receive all 3 - tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // three tags in a hierarchy - get just the first - tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv6FromString("2001:db8:0:0:0:1:2:1/128", 128), filterFunc) assert.True(t, tagArraysEqual(tags, []string{tagB})) // three tags in hierarchy - get none - tags = tree.FindTagsWithFilter(tags, ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv6FromString("8001:db8:0:0:0:0:2:1/128", 128), filterFunc) assert.Zero(t, len(tags)) - tags = tree.FindTagsWithFilter(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66), filterFunc) + tags = tags[:0] + tags = tree.FindTagsWithFilterAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 66), filterFunc) assert.Zero(t, len(tags)) } @@ -220,26 +235,31 @@ func TestRootNodeV6(t *testing.T) { tree.Add(patricia.IPv6Address{}, tagB, nil) // query the root node with no address - tags = tree.FindTags(tags, patricia.IPv6Address{}) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, patricia.IPv6Address{}) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // query a node that doesn't exist - tags = tree.FindTags(tags, ipv6FromString("FFFF:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("FFFF:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB})) // create a new /65 node with C & D tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 65), tagC, nil) tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 65), tagD, nil) - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) // create a node under the /65 node tree.Add(ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), tagZ, nil) - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD, tagZ})) // check the /77 and make sure we still get the /65 and root - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 77)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 77)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagD})) } @@ -250,6 +270,7 @@ func TestDelete1V6(t *testing.T) { return tagData.(string) == val.(string) } + buf := make([]GeneratedType, 0, 10) tagA := "tagA" tagB := "tagB" tagC := "tagC" @@ -267,73 +288,68 @@ func TestDelete1V6(t *testing.T) { assert.Equal(t, 4, tree.countNodes(1)) // three tags in a hierarchy - ask for an exact match, receive all 3 and the root - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) // 1. delete a tag that doesn't exist count := 0 - count = tree.Delete(tags, ipv6FromString("F001:db8:0:0:0:0:2:1/128", 128), matchFunc, "bad tag") + count = tree.DeleteWithBuffer(buf, ipv6FromString("F001:db8:0:0:0:0:2:1/128", 128), matchFunc, "bad tag") assert.Equal(t, 0, count) assert.Equal(t, 4, tree.countTags(1)) assert.Equal(t, 4, tree.countNodes(1)) - assert.Equal(t, 0, len(tags)) // 2. delete a tag on an address that exists, but doesn't have the tag - count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "bad tag") + count = tree.DeleteWithBuffer(buf, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "bad tag") assert.Equal(t, 0, count) - assert.Equal(t, 0, len(tags)) // verify - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC, tagZ})) assert.Equal(t, 4, tree.countNodes(1)) assert.Equal(t, 4, tree.countTags(1)) - tags = tags[:0] // 3. delete the default/root tag - count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 0), matchFunc, "tagZ") + count = tree.DeleteWithBuffer(buf, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 0), matchFunc, "tagZ") assert.Equal(t, 1, count) assert.Equal(t, 4, tree.countNodes(1)) // doesn't delete anything assert.Equal(t, 3, tree.countTags(1)) - assert.Equal(t, 0, len(tags)) // three tags in a hierarchy - ask for an exact match, receive all 3, not the root, which we deleted - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) - assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC})) tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + assert.True(t, tagArraysEqual(tags, []string{tagA, tagB, tagC})) // 4. delete tagA - count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "tagA") + count = tree.DeleteWithBuffer(buf, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 67), matchFunc, "tagA") assert.Equal(t, 1, count) - assert.Equal(t, 0, len(tags)) // verify - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagB, tagC})) assert.Equal(t, 3, tree.countNodes(1)) assert.Equal(t, 2, tree.countTags(1)) - tags = tags[:0] // 5. delete tag B - count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 2), matchFunc, "tagB") + count = tree.DeleteWithBuffer(buf, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 2), matchFunc, "tagB") assert.Equal(t, 1, count) - assert.Equal(t, 0, len(tags)) // verify - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{tagC})) assert.Equal(t, 2, tree.countNodes(1)) assert.Equal(t, 1, tree.countTags(1)) - tags = tags[:0] // 6. delete tag C - count = tree.Delete(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), matchFunc, "tagC") + count = tree.DeleteWithBuffer(buf, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128), matchFunc, "tagC") assert.Equal(t, 1, count) - assert.Equal(t, 0, len(tags)) // verify - tags = tree.FindTags(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) + tags = tags[:0] + tags = tree.FindTagsAppend(tags, ipv6FromString("2001:db8:0:0:0:0:2:1/128", 128)) assert.True(t, tagArraysEqual(tags, []string{})) assert.Equal(t, 1, tree.countNodes(1)) assert.Equal(t, 0, tree.countTags(1)) From 822d2f8c3427ee168375e274efd4d03de36f24aa Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Tue, 31 Aug 2021 16:51:13 +0000 Subject: [PATCH 11/19] code gen --- bool_tree/tree_v4.go | 53 ++++++++++++++++++++-------- bool_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- byte_tree/tree_v4.go | 53 ++++++++++++++++++++-------- byte_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- complex128_tree/tree_v4.go | 53 ++++++++++++++++++++-------- complex128_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- complex64_tree/tree_v4.go | 53 ++++++++++++++++++++-------- complex64_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- float32_tree/tree_v4.go | 53 ++++++++++++++++++++-------- float32_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- float64_tree/tree_v4.go | 53 ++++++++++++++++++++-------- float64_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- int16_tree/tree_v4.go | 53 ++++++++++++++++++++-------- int16_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- int32_tree/tree_v4.go | 53 ++++++++++++++++++++-------- int32_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- int64_tree/tree_v4.go | 53 ++++++++++++++++++++-------- int64_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- int8_tree/tree_v4.go | 53 ++++++++++++++++++++-------- int8_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- int_tree/tree_v4.go | 53 ++++++++++++++++++++-------- int_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- rune_tree/tree_v4.go | 53 ++++++++++++++++++++-------- rune_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- string_tree/tree_v4.go | 53 ++++++++++++++++++++-------- string_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- template/tree_v6_generated.go | 53 ++++++++++++++++++++-------- uint16_tree/tree_v4.go | 53 ++++++++++++++++++++-------- uint16_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- uint32_tree/tree_v4.go | 53 ++++++++++++++++++++-------- uint32_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- uint64_tree/tree_v4.go | 53 ++++++++++++++++++++-------- uint64_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- uint8_tree/tree_v4.go | 53 ++++++++++++++++++++-------- uint8_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- uint_tree/tree_v4.go | 53 ++++++++++++++++++++-------- uint_tree/tree_v6_generated.go | 53 ++++++++++++++++++++-------- 37 files changed, 1443 insertions(+), 518 deletions(-) diff --git a/bool_tree/tree_v4.go b/bool_tree/tree_v4.go index 72bf53a..4a02207 100644 --- a/bool_tree/tree_v4.go +++ b/bool_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal bool) int { + return t.DeleteWithBuffer(make([]bool, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []bool, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal bool) int { +func (t *TreeV4) DeleteWithBuffer(buf []bool, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal bool) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []bool, address patricia.IPv4Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []bool, address patricia.IPv4Address, filterFunc FilterFunc) []bool { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []bool { + ret := make([]bool, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []bool, address patricia.IPv4Address, filterFunc FilterFunc) []bool { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []bool, address patricia.IPv4Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []bool, address patricia.IPv4Address) []bool { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []bool { + ret := make([]bool, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []bool, address patricia.IPv4Address) []bool { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, bool) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []bool, address patricia.IPv4Address) (bool, []bool) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []bool) { + ret := make([]bool, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []bool, address patricia.IPv4Address) (bool, []bool) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/bool_tree/tree_v6_generated.go b/bool_tree/tree_v6_generated.go index b4fc560..2ed579a 100644 --- a/bool_tree/tree_v6_generated.go +++ b/bool_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal bool) int { + return t.DeleteWithBuffer(make([]bool, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []bool, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal bool) int { +func (t *TreeV6) DeleteWithBuffer(buf []bool, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal bool) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []bool, address patricia.IPv6Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []bool, address patricia.IPv6Address, filterFunc FilterFunc) []bool { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []bool { + ret := make([]bool, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []bool, address patricia.IPv6Address, filterFunc FilterFunc) []bool { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []bool, address patricia.IPv6Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []bool, address patricia.IPv6Address) []bool { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []bool { + ret := make([]bool, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []bool, address patricia.IPv6Address) []bool { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, bool) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []bool, address patricia.IPv6Address) (bool, []bool) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []bool) { + ret := make([]bool, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []bool, address patricia.IPv6Address) (bool, []bool) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/byte_tree/tree_v4.go b/byte_tree/tree_v4.go index 422772b..0ba1fdf 100644 --- a/byte_tree/tree_v4.go +++ b/byte_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal byte) int { + return t.DeleteWithBuffer(make([]byte, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []byte, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal byte) int { +func (t *TreeV4) DeleteWithBuffer(buf []byte, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal byte) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []byte, address patricia.IPv4Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []byte, address patricia.IPv4Address, filterFunc FilterFunc) []byte { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []byte { + ret := make([]byte, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []byte, address patricia.IPv4Address, filterFunc FilterFunc) []byte { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []byte, address patricia.IPv4Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []byte, address patricia.IPv4Address) []byte { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []byte { + ret := make([]byte, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []byte, address patricia.IPv4Address) []byte { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, byte) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []byte, address patricia.IPv4Address) (bool, []byte) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []byte) { + ret := make([]byte, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []byte, address patricia.IPv4Address) (bool, []byte) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/byte_tree/tree_v6_generated.go b/byte_tree/tree_v6_generated.go index bbae6a6..334563d 100644 --- a/byte_tree/tree_v6_generated.go +++ b/byte_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal byte) int { + return t.DeleteWithBuffer(make([]byte, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []byte, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal byte) int { +func (t *TreeV6) DeleteWithBuffer(buf []byte, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal byte) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []byte, address patricia.IPv6Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []byte, address patricia.IPv6Address, filterFunc FilterFunc) []byte { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []byte { + ret := make([]byte, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []byte, address patricia.IPv6Address, filterFunc FilterFunc) []byte { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []byte, address patricia.IPv6Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []byte, address patricia.IPv6Address) []byte { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []byte { + ret := make([]byte, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []byte, address patricia.IPv6Address) []byte { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, byte) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []byte, address patricia.IPv6Address) (bool, []byte) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []byte) { + ret := make([]byte, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []byte, address patricia.IPv6Address) (bool, []byte) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/complex128_tree/tree_v4.go b/complex128_tree/tree_v4.go index daf3ef4..3203c3b 100644 --- a/complex128_tree/tree_v4.go +++ b/complex128_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex128) int { + return t.DeleteWithBuffer(make([]complex128, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []complex128, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex128) int { +func (t *TreeV4) DeleteWithBuffer(buf []complex128, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex128) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []complex128, address patricia.IPv4Address, matchFun } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []complex128, address patricia.IPv4Address, filterFunc FilterFunc) []complex128 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []complex128 { + ret := make([]complex128, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []complex128, address patricia.IPv4Address, filterFunc FilterFunc) []complex128 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []complex128, address patricia.IPv4Addre return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []complex128, address patricia.IPv4Address) []complex128 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []complex128 { + ret := make([]complex128, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []complex128, address patricia.IPv4Address) []complex128 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex128) } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []complex128, address patricia.IPv4Address) (bool, []complex128) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex128) { + ret := make([]complex128, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []complex128, address patricia.IPv4Address) (bool, []complex128) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/complex128_tree/tree_v6_generated.go b/complex128_tree/tree_v6_generated.go index 91129a6..caabde6 100644 --- a/complex128_tree/tree_v6_generated.go +++ b/complex128_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex128) int { + return t.DeleteWithBuffer(make([]complex128, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []complex128, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex128) int { +func (t *TreeV6) DeleteWithBuffer(buf []complex128, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex128) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []complex128, address patricia.IPv6Address, matchFun } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []complex128, address patricia.IPv6Address, filterFunc FilterFunc) []complex128 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []complex128 { + ret := make([]complex128, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []complex128, address patricia.IPv6Address, filterFunc FilterFunc) []complex128 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []complex128, address patricia.IPv6Addre return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []complex128, address patricia.IPv6Address) []complex128 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []complex128 { + ret := make([]complex128, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []complex128, address patricia.IPv6Address) []complex128 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex128) } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []complex128, address patricia.IPv6Address) (bool, []complex128) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex128) { + ret := make([]complex128, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []complex128, address patricia.IPv6Address) (bool, []complex128) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/complex64_tree/tree_v4.go b/complex64_tree/tree_v4.go index c9ae9c9..fd5076f 100644 --- a/complex64_tree/tree_v4.go +++ b/complex64_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex64) int { + return t.DeleteWithBuffer(make([]complex64, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []complex64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex64) int { +func (t *TreeV4) DeleteWithBuffer(buf []complex64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []complex64, address patricia.IPv4Address, matchFunc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []complex64, address patricia.IPv4Address, filterFunc FilterFunc) []complex64 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []complex64 { + ret := make([]complex64, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []complex64, address patricia.IPv4Address, filterFunc FilterFunc) []complex64 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []complex64, address patricia.IPv4Addres return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []complex64, address patricia.IPv4Address) []complex64 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []complex64 { + ret := make([]complex64, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []complex64, address patricia.IPv4Address) []complex64 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, complex64) } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []complex64, address patricia.IPv4Address) (bool, []complex64) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []complex64) { + ret := make([]complex64, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []complex64, address patricia.IPv4Address) (bool, []complex64) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/complex64_tree/tree_v6_generated.go b/complex64_tree/tree_v6_generated.go index 5254a1b..6e83666 100644 --- a/complex64_tree/tree_v6_generated.go +++ b/complex64_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex64) int { + return t.DeleteWithBuffer(make([]complex64, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []complex64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex64) int { +func (t *TreeV6) DeleteWithBuffer(buf []complex64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []complex64, address patricia.IPv6Address, matchFunc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []complex64, address patricia.IPv6Address, filterFunc FilterFunc) []complex64 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []complex64 { + ret := make([]complex64, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []complex64, address patricia.IPv6Address, filterFunc FilterFunc) []complex64 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []complex64, address patricia.IPv6Addres return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []complex64, address patricia.IPv6Address) []complex64 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []complex64 { + ret := make([]complex64, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []complex64, address patricia.IPv6Address) []complex64 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, complex64) } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []complex64, address patricia.IPv6Address) (bool, []complex64) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []complex64) { + ret := make([]complex64, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []complex64, address patricia.IPv6Address) (bool, []complex64) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/float32_tree/tree_v4.go b/float32_tree/tree_v4.go index 1fc1a19..af7b6ae 100644 --- a/float32_tree/tree_v4.go +++ b/float32_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float32) int { + return t.DeleteWithBuffer(make([]float32, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []float32, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float32) int { +func (t *TreeV4) DeleteWithBuffer(buf []float32, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []float32, address patricia.IPv4Address, matchFunc M } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []float32, address patricia.IPv4Address, filterFunc FilterFunc) []float32 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []float32 { + ret := make([]float32, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []float32, address patricia.IPv4Address, filterFunc FilterFunc) []float32 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []float32, address patricia.IPv4Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []float32, address patricia.IPv4Address) []float32 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []float32 { + ret := make([]float32, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []float32, address patricia.IPv4Address) []float32 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []float32, address patricia.IPv4Address) (bool, []float32) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float32) { + ret := make([]float32, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []float32, address patricia.IPv4Address) (bool, []float32) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/float32_tree/tree_v6_generated.go b/float32_tree/tree_v6_generated.go index 2055cbf..c2a787d 100644 --- a/float32_tree/tree_v6_generated.go +++ b/float32_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float32) int { + return t.DeleteWithBuffer(make([]float32, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []float32, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float32) int { +func (t *TreeV6) DeleteWithBuffer(buf []float32, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []float32, address patricia.IPv6Address, matchFunc M } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []float32, address patricia.IPv6Address, filterFunc FilterFunc) []float32 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []float32 { + ret := make([]float32, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []float32, address patricia.IPv6Address, filterFunc FilterFunc) []float32 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []float32, address patricia.IPv6Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []float32, address patricia.IPv6Address) []float32 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []float32 { + ret := make([]float32, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []float32, address patricia.IPv6Address) []float32 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []float32, address patricia.IPv6Address) (bool, []float32) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float32) { + ret := make([]float32, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []float32, address patricia.IPv6Address) (bool, []float32) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/float64_tree/tree_v4.go b/float64_tree/tree_v4.go index 82ae019..2471a77 100644 --- a/float64_tree/tree_v4.go +++ b/float64_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float64) int { + return t.DeleteWithBuffer(make([]float64, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []float64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float64) int { +func (t *TreeV4) DeleteWithBuffer(buf []float64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []float64, address patricia.IPv4Address, matchFunc M } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []float64, address patricia.IPv4Address, filterFunc FilterFunc) []float64 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []float64 { + ret := make([]float64, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []float64, address patricia.IPv4Address, filterFunc FilterFunc) []float64 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []float64, address patricia.IPv4Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []float64, address patricia.IPv4Address) []float64 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []float64 { + ret := make([]float64, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []float64, address patricia.IPv4Address) []float64 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, float64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []float64, address patricia.IPv4Address) (bool, []float64) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []float64) { + ret := make([]float64, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []float64, address patricia.IPv4Address) (bool, []float64) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/float64_tree/tree_v6_generated.go b/float64_tree/tree_v6_generated.go index 35d80f0..3ea218f 100644 --- a/float64_tree/tree_v6_generated.go +++ b/float64_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float64) int { + return t.DeleteWithBuffer(make([]float64, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []float64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float64) int { +func (t *TreeV6) DeleteWithBuffer(buf []float64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []float64, address patricia.IPv6Address, matchFunc M } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []float64, address patricia.IPv6Address, filterFunc FilterFunc) []float64 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []float64 { + ret := make([]float64, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []float64, address patricia.IPv6Address, filterFunc FilterFunc) []float64 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []float64, address patricia.IPv6Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []float64, address patricia.IPv6Address) []float64 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []float64 { + ret := make([]float64, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []float64, address patricia.IPv6Address) []float64 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, float64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []float64, address patricia.IPv6Address) (bool, []float64) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []float64) { + ret := make([]float64, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []float64, address patricia.IPv6Address) (bool, []float64) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int16_tree/tree_v4.go b/int16_tree/tree_v4.go index cd0edf1..b1c090e 100644 --- a/int16_tree/tree_v4.go +++ b/int16_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int16) int { + return t.DeleteWithBuffer(make([]int16, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []int16, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int16) int { +func (t *TreeV4) DeleteWithBuffer(buf []int16, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []int16, address patricia.IPv4Address, matchFunc Mat } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []int16, address patricia.IPv4Address, filterFunc FilterFunc) []int16 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int16 { + ret := make([]int16, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int16, address patricia.IPv4Address, filterFunc FilterFunc) []int16 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []int16, address patricia.IPv4Address, f return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []int16, address patricia.IPv4Address) []int16 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int16 { + ret := make([]int16, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int16, address patricia.IPv4Address) []int16 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int16) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []int16, address patricia.IPv4Address) (bool, []int16) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int16) { + ret := make([]int16, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []int16, address patricia.IPv4Address) (bool, []int16) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int16_tree/tree_v6_generated.go b/int16_tree/tree_v6_generated.go index 7f3fe09..3bc4366 100644 --- a/int16_tree/tree_v6_generated.go +++ b/int16_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int16) int { + return t.DeleteWithBuffer(make([]int16, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []int16, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int16) int { +func (t *TreeV6) DeleteWithBuffer(buf []int16, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []int16, address patricia.IPv6Address, matchFunc Mat } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []int16, address patricia.IPv6Address, filterFunc FilterFunc) []int16 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int16 { + ret := make([]int16, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int16, address patricia.IPv6Address, filterFunc FilterFunc) []int16 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []int16, address patricia.IPv6Address, f return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []int16, address patricia.IPv6Address) []int16 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int16 { + ret := make([]int16, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int16, address patricia.IPv6Address) []int16 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int16) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []int16, address patricia.IPv6Address) (bool, []int16) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int16) { + ret := make([]int16, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []int16, address patricia.IPv6Address) (bool, []int16) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int32_tree/tree_v4.go b/int32_tree/tree_v4.go index 0f70a5d..15d62a5 100644 --- a/int32_tree/tree_v4.go +++ b/int32_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int32) int { + return t.DeleteWithBuffer(make([]int32, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []int32, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int32) int { +func (t *TreeV4) DeleteWithBuffer(buf []int32, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []int32, address patricia.IPv4Address, matchFunc Mat } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []int32, address patricia.IPv4Address, filterFunc FilterFunc) []int32 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int32 { + ret := make([]int32, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int32, address patricia.IPv4Address, filterFunc FilterFunc) []int32 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []int32, address patricia.IPv4Address, f return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []int32, address patricia.IPv4Address) []int32 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int32 { + ret := make([]int32, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int32, address patricia.IPv4Address) []int32 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []int32, address patricia.IPv4Address) (bool, []int32) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int32) { + ret := make([]int32, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []int32, address patricia.IPv4Address) (bool, []int32) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int32_tree/tree_v6_generated.go b/int32_tree/tree_v6_generated.go index 73ddb66..6093324 100644 --- a/int32_tree/tree_v6_generated.go +++ b/int32_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int32) int { + return t.DeleteWithBuffer(make([]int32, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []int32, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int32) int { +func (t *TreeV6) DeleteWithBuffer(buf []int32, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []int32, address patricia.IPv6Address, matchFunc Mat } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []int32, address patricia.IPv6Address, filterFunc FilterFunc) []int32 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int32 { + ret := make([]int32, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int32, address patricia.IPv6Address, filterFunc FilterFunc) []int32 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []int32, address patricia.IPv6Address, f return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []int32, address patricia.IPv6Address) []int32 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int32 { + ret := make([]int32, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int32, address patricia.IPv6Address) []int32 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []int32, address patricia.IPv6Address) (bool, []int32) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int32) { + ret := make([]int32, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []int32, address patricia.IPv6Address) (bool, []int32) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int64_tree/tree_v4.go b/int64_tree/tree_v4.go index 20abcfc..076e9df 100644 --- a/int64_tree/tree_v4.go +++ b/int64_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int64) int { + return t.DeleteWithBuffer(make([]int64, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []int64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int64) int { +func (t *TreeV4) DeleteWithBuffer(buf []int64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []int64, address patricia.IPv4Address, matchFunc Mat } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []int64, address patricia.IPv4Address, filterFunc FilterFunc) []int64 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int64 { + ret := make([]int64, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int64, address patricia.IPv4Address, filterFunc FilterFunc) []int64 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []int64, address patricia.IPv4Address, f return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []int64, address patricia.IPv4Address) []int64 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int64 { + ret := make([]int64, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int64, address patricia.IPv4Address) []int64 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []int64, address patricia.IPv4Address) (bool, []int64) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int64) { + ret := make([]int64, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []int64, address patricia.IPv4Address) (bool, []int64) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int64_tree/tree_v6_generated.go b/int64_tree/tree_v6_generated.go index 370f055..45da713 100644 --- a/int64_tree/tree_v6_generated.go +++ b/int64_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int64) int { + return t.DeleteWithBuffer(make([]int64, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []int64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int64) int { +func (t *TreeV6) DeleteWithBuffer(buf []int64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []int64, address patricia.IPv6Address, matchFunc Mat } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []int64, address patricia.IPv6Address, filterFunc FilterFunc) []int64 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int64 { + ret := make([]int64, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int64, address patricia.IPv6Address, filterFunc FilterFunc) []int64 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []int64, address patricia.IPv6Address, f return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []int64, address patricia.IPv6Address) []int64 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int64 { + ret := make([]int64, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int64, address patricia.IPv6Address) []int64 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []int64, address patricia.IPv6Address) (bool, []int64) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int64) { + ret := make([]int64, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []int64, address patricia.IPv6Address) (bool, []int64) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int8_tree/tree_v4.go b/int8_tree/tree_v4.go index f775599..f032ef3 100644 --- a/int8_tree/tree_v4.go +++ b/int8_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int8) int { + return t.DeleteWithBuffer(make([]int8, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []int8, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int8) int { +func (t *TreeV4) DeleteWithBuffer(buf []int8, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []int8, address patricia.IPv4Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []int8, address patricia.IPv4Address, filterFunc FilterFunc) []int8 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int8 { + ret := make([]int8, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int8, address patricia.IPv4Address, filterFunc FilterFunc) []int8 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []int8, address patricia.IPv4Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []int8, address patricia.IPv4Address) []int8 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int8 { + ret := make([]int8, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int8, address patricia.IPv4Address) []int8 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int8) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []int8, address patricia.IPv4Address) (bool, []int8) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int8) { + ret := make([]int8, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []int8, address patricia.IPv4Address) (bool, []int8) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int8_tree/tree_v6_generated.go b/int8_tree/tree_v6_generated.go index 04e6071..996a6fc 100644 --- a/int8_tree/tree_v6_generated.go +++ b/int8_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int8) int { + return t.DeleteWithBuffer(make([]int8, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []int8, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int8) int { +func (t *TreeV6) DeleteWithBuffer(buf []int8, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []int8, address patricia.IPv6Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []int8, address patricia.IPv6Address, filterFunc FilterFunc) []int8 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int8 { + ret := make([]int8, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int8, address patricia.IPv6Address, filterFunc FilterFunc) []int8 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []int8, address patricia.IPv6Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []int8, address patricia.IPv6Address) []int8 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int8 { + ret := make([]int8, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int8, address patricia.IPv6Address) []int8 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int8) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []int8, address patricia.IPv6Address) (bool, []int8) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int8) { + ret := make([]int8, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []int8, address patricia.IPv6Address) (bool, []int8) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int_tree/tree_v4.go b/int_tree/tree_v4.go index a7f28d8..8f45798 100644 --- a/int_tree/tree_v4.go +++ b/int_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int) int { + return t.DeleteWithBuffer(make([]int, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []int, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int) int { +func (t *TreeV4) DeleteWithBuffer(buf []int, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []int, address patricia.IPv4Address, matchFunc Match } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []int, address patricia.IPv4Address, filterFunc FilterFunc) []int { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []int { + ret := make([]int, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int, address patricia.IPv4Address, filterFunc FilterFunc) []int { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []int, address patricia.IPv4Address, fil return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []int, address patricia.IPv4Address) []int { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []int { + ret := make([]int, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int, address patricia.IPv4Address) []int { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, int) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []int, address patricia.IPv4Address) (bool, []int) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []int) { + ret := make([]int, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []int, address patricia.IPv4Address) (bool, []int) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/int_tree/tree_v6_generated.go b/int_tree/tree_v6_generated.go index f4b16de..4d27047 100644 --- a/int_tree/tree_v6_generated.go +++ b/int_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int) int { + return t.DeleteWithBuffer(make([]int, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []int, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int) int { +func (t *TreeV6) DeleteWithBuffer(buf []int, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []int, address patricia.IPv6Address, matchFunc Match } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []int, address patricia.IPv6Address, filterFunc FilterFunc) []int { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []int { + ret := make([]int, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int, address patricia.IPv6Address, filterFunc FilterFunc) []int { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []int, address patricia.IPv6Address, fil return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []int, address patricia.IPv6Address) []int { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []int { + ret := make([]int, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int, address patricia.IPv6Address) []int { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, int) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []int, address patricia.IPv6Address) (bool, []int) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []int) { + ret := make([]int, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []int, address patricia.IPv6Address) (bool, []int) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/rune_tree/tree_v4.go b/rune_tree/tree_v4.go index c0fcd7f..466da6d 100644 --- a/rune_tree/tree_v4.go +++ b/rune_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal rune) int { + return t.DeleteWithBuffer(make([]rune, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []rune, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal rune) int { +func (t *TreeV4) DeleteWithBuffer(buf []rune, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal rune) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []rune, address patricia.IPv4Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []rune, address patricia.IPv4Address, filterFunc FilterFunc) []rune { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []rune { + ret := make([]rune, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []rune, address patricia.IPv4Address, filterFunc FilterFunc) []rune { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []rune, address patricia.IPv4Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []rune, address patricia.IPv4Address) []rune { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []rune { + ret := make([]rune, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []rune, address patricia.IPv4Address) []rune { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, rune) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []rune, address patricia.IPv4Address) (bool, []rune) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []rune) { + ret := make([]rune, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []rune, address patricia.IPv4Address) (bool, []rune) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/rune_tree/tree_v6_generated.go b/rune_tree/tree_v6_generated.go index ec30078..af0e50a 100644 --- a/rune_tree/tree_v6_generated.go +++ b/rune_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal rune) int { + return t.DeleteWithBuffer(make([]rune, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []rune, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal rune) int { +func (t *TreeV6) DeleteWithBuffer(buf []rune, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal rune) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []rune, address patricia.IPv6Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []rune, address patricia.IPv6Address, filterFunc FilterFunc) []rune { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []rune { + ret := make([]rune, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []rune, address patricia.IPv6Address, filterFunc FilterFunc) []rune { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []rune, address patricia.IPv6Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []rune, address patricia.IPv6Address) []rune { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []rune { + ret := make([]rune, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []rune, address patricia.IPv6Address) []rune { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, rune) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []rune, address patricia.IPv6Address) (bool, []rune) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []rune) { + ret := make([]rune, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []rune, address patricia.IPv6Address) (bool, []rune) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/string_tree/tree_v4.go b/string_tree/tree_v4.go index b3fb336..64580db 100644 --- a/string_tree/tree_v4.go +++ b/string_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal string) int { + return t.DeleteWithBuffer(make([]string, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []string, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal string) int { +func (t *TreeV4) DeleteWithBuffer(buf []string, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal string) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []string, address patricia.IPv4Address, matchFunc Ma } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []string, address patricia.IPv4Address, filterFunc FilterFunc) []string { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []string { + ret := make([]string, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []string, address patricia.IPv4Address, filterFunc FilterFunc) []string { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []string, address patricia.IPv4Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []string, address patricia.IPv4Address) []string { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []string { + ret := make([]string, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []string, address patricia.IPv4Address) []string { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, string) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []string, address patricia.IPv4Address) (bool, []string) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []string) { + ret := make([]string, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []string, address patricia.IPv4Address) (bool, []string) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/string_tree/tree_v6_generated.go b/string_tree/tree_v6_generated.go index f04de5d..65d1bad 100644 --- a/string_tree/tree_v6_generated.go +++ b/string_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal string) int { + return t.DeleteWithBuffer(make([]string, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []string, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal string) int { +func (t *TreeV6) DeleteWithBuffer(buf []string, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal string) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []string, address patricia.IPv6Address, matchFunc Ma } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []string, address patricia.IPv6Address, filterFunc FilterFunc) []string { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []string { + ret := make([]string, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []string, address patricia.IPv6Address, filterFunc FilterFunc) []string { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []string, address patricia.IPv6Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []string, address patricia.IPv6Address) []string { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []string { + ret := make([]string, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []string, address patricia.IPv6Address) []string { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, string) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []string, address patricia.IPv6Address) (bool, []string) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []string) { + ret := make([]string, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []string, address patricia.IPv6Address) (bool, []string) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/template/tree_v6_generated.go b/template/tree_v6_generated.go index a33695b..1db2292 100644 --- a/template/tree_v6_generated.go +++ b/template/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal GeneratedType) int { + return t.DeleteWithBuffer(make([]GeneratedType, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []GeneratedType, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal GeneratedType) int { +func (t *TreeV6) DeleteWithBuffer(buf []GeneratedType, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal GeneratedType) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []GeneratedType, address patricia.IPv6Address, match } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []GeneratedType, address patricia.IPv6Address, filterFunc FilterFunc) []GeneratedType { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []GeneratedType { + ret := make([]GeneratedType, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []GeneratedType, address patricia.IPv6Address, filterFunc FilterFunc) []GeneratedType { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []GeneratedType, address patricia.IPv6Ad return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []GeneratedType, address patricia.IPv6Address) []GeneratedType { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []GeneratedType { + ret := make([]GeneratedType, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []GeneratedType, address patricia.IPv6Address) []GeneratedType { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, GeneratedTy } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []GeneratedType, address patricia.IPv6Address) (bool, []GeneratedType) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []GeneratedType) { + ret := make([]GeneratedType, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []GeneratedType, address patricia.IPv6Address) (bool, []GeneratedType) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint16_tree/tree_v4.go b/uint16_tree/tree_v4.go index 85ec32a..5268478 100644 --- a/uint16_tree/tree_v4.go +++ b/uint16_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint16) int { + return t.DeleteWithBuffer(make([]uint16, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []uint16, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint16) int { +func (t *TreeV4) DeleteWithBuffer(buf []uint16, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []uint16, address patricia.IPv4Address, matchFunc Ma } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []uint16, address patricia.IPv4Address, filterFunc FilterFunc) []uint16 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint16 { + ret := make([]uint16, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint16, address patricia.IPv4Address, filterFunc FilterFunc) []uint16 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []uint16, address patricia.IPv4Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []uint16, address patricia.IPv4Address) []uint16 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint16 { + ret := make([]uint16, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint16, address patricia.IPv4Address) []uint16 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint16) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []uint16, address patricia.IPv4Address) (bool, []uint16) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint16) { + ret := make([]uint16, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []uint16, address patricia.IPv4Address) (bool, []uint16) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint16_tree/tree_v6_generated.go b/uint16_tree/tree_v6_generated.go index 084947d..96087a4 100644 --- a/uint16_tree/tree_v6_generated.go +++ b/uint16_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint16) int { + return t.DeleteWithBuffer(make([]uint16, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []uint16, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint16) int { +func (t *TreeV6) DeleteWithBuffer(buf []uint16, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint16) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []uint16, address patricia.IPv6Address, matchFunc Ma } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []uint16, address patricia.IPv6Address, filterFunc FilterFunc) []uint16 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint16 { + ret := make([]uint16, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint16, address patricia.IPv6Address, filterFunc FilterFunc) []uint16 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []uint16, address patricia.IPv6Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []uint16, address patricia.IPv6Address) []uint16 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint16 { + ret := make([]uint16, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint16, address patricia.IPv6Address) []uint16 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint16) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []uint16, address patricia.IPv6Address) (bool, []uint16) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint16) { + ret := make([]uint16, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []uint16, address patricia.IPv6Address) (bool, []uint16) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint32_tree/tree_v4.go b/uint32_tree/tree_v4.go index ae202f9..a576483 100644 --- a/uint32_tree/tree_v4.go +++ b/uint32_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint32) int { + return t.DeleteWithBuffer(make([]uint32, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []uint32, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint32) int { +func (t *TreeV4) DeleteWithBuffer(buf []uint32, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []uint32, address patricia.IPv4Address, matchFunc Ma } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []uint32, address patricia.IPv4Address, filterFunc FilterFunc) []uint32 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint32 { + ret := make([]uint32, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint32, address patricia.IPv4Address, filterFunc FilterFunc) []uint32 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []uint32, address patricia.IPv4Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []uint32, address patricia.IPv4Address) []uint32 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint32 { + ret := make([]uint32, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint32, address patricia.IPv4Address) []uint32 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []uint32, address patricia.IPv4Address) (bool, []uint32) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint32) { + ret := make([]uint32, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []uint32, address patricia.IPv4Address) (bool, []uint32) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint32_tree/tree_v6_generated.go b/uint32_tree/tree_v6_generated.go index 22ff55a..0f8fca9 100644 --- a/uint32_tree/tree_v6_generated.go +++ b/uint32_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint32) int { + return t.DeleteWithBuffer(make([]uint32, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []uint32, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint32) int { +func (t *TreeV6) DeleteWithBuffer(buf []uint32, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint32) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []uint32, address patricia.IPv6Address, matchFunc Ma } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []uint32, address patricia.IPv6Address, filterFunc FilterFunc) []uint32 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint32 { + ret := make([]uint32, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint32, address patricia.IPv6Address, filterFunc FilterFunc) []uint32 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []uint32, address patricia.IPv6Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []uint32, address patricia.IPv6Address) []uint32 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint32 { + ret := make([]uint32, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint32, address patricia.IPv6Address) []uint32 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint32) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []uint32, address patricia.IPv6Address) (bool, []uint32) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint32) { + ret := make([]uint32, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []uint32, address patricia.IPv6Address) (bool, []uint32) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint64_tree/tree_v4.go b/uint64_tree/tree_v4.go index a442044..80d2836 100644 --- a/uint64_tree/tree_v4.go +++ b/uint64_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint64) int { + return t.DeleteWithBuffer(make([]uint64, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []uint64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint64) int { +func (t *TreeV4) DeleteWithBuffer(buf []uint64, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []uint64, address patricia.IPv4Address, matchFunc Ma } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []uint64, address patricia.IPv4Address, filterFunc FilterFunc) []uint64 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint64 { + ret := make([]uint64, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint64, address patricia.IPv4Address, filterFunc FilterFunc) []uint64 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []uint64, address patricia.IPv4Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []uint64, address patricia.IPv4Address) []uint64 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint64 { + ret := make([]uint64, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint64, address patricia.IPv4Address) []uint64 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []uint64, address patricia.IPv4Address) (bool, []uint64) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint64) { + ret := make([]uint64, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []uint64, address patricia.IPv4Address) (bool, []uint64) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint64_tree/tree_v6_generated.go b/uint64_tree/tree_v6_generated.go index 3378db6..67d770b 100644 --- a/uint64_tree/tree_v6_generated.go +++ b/uint64_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint64) int { + return t.DeleteWithBuffer(make([]uint64, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []uint64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint64) int { +func (t *TreeV6) DeleteWithBuffer(buf []uint64, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint64) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []uint64, address patricia.IPv6Address, matchFunc Ma } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []uint64, address patricia.IPv6Address, filterFunc FilterFunc) []uint64 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint64 { + ret := make([]uint64, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint64, address patricia.IPv6Address, filterFunc FilterFunc) []uint64 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []uint64, address patricia.IPv6Address, return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []uint64, address patricia.IPv6Address) []uint64 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint64 { + ret := make([]uint64, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint64, address patricia.IPv6Address) []uint64 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint64) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []uint64, address patricia.IPv6Address) (bool, []uint64) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint64) { + ret := make([]uint64, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []uint64, address patricia.IPv6Address) (bool, []uint64) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint8_tree/tree_v4.go b/uint8_tree/tree_v4.go index 37a3f25..8feae1f 100644 --- a/uint8_tree/tree_v4.go +++ b/uint8_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint8) int { + return t.DeleteWithBuffer(make([]uint8, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []uint8, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint8) int { +func (t *TreeV4) DeleteWithBuffer(buf []uint8, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []uint8, address patricia.IPv4Address, matchFunc Mat } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []uint8, address patricia.IPv4Address, filterFunc FilterFunc) []uint8 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint8 { + ret := make([]uint8, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint8, address patricia.IPv4Address, filterFunc FilterFunc) []uint8 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []uint8, address patricia.IPv4Address, f return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []uint8, address patricia.IPv4Address) []uint8 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint8 { + ret := make([]uint8, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint8, address patricia.IPv4Address) []uint8 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint8) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []uint8, address patricia.IPv4Address) (bool, []uint8) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint8) { + ret := make([]uint8, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []uint8, address patricia.IPv4Address) (bool, []uint8) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint8_tree/tree_v6_generated.go b/uint8_tree/tree_v6_generated.go index 301dc2e..f183c3a 100644 --- a/uint8_tree/tree_v6_generated.go +++ b/uint8_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint8) int { + return t.DeleteWithBuffer(make([]uint8, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []uint8, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint8) int { +func (t *TreeV6) DeleteWithBuffer(buf []uint8, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint8) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []uint8, address patricia.IPv6Address, matchFunc Mat } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []uint8, address patricia.IPv6Address, filterFunc FilterFunc) []uint8 { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint8 { + ret := make([]uint8, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint8, address patricia.IPv6Address, filterFunc FilterFunc) []uint8 { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []uint8, address patricia.IPv6Address, f return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []uint8, address patricia.IPv6Address) []uint8 { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint8 { + ret := make([]uint8, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint8, address patricia.IPv6Address) []uint8 { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint8) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []uint8, address patricia.IPv6Address) (bool, []uint8) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint8) { + ret := make([]uint8, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []uint8, address patricia.IPv6Address) (bool, []uint8) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint_tree/tree_v4.go b/uint_tree/tree_v4.go index fab806a..a7ae218 100644 --- a/uint_tree/tree_v4.go +++ b/uint_tree/tree_v4.go @@ -319,8 +319,14 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint) int { + return t.DeleteWithBuffer(make([]uint, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV4) Delete(buf []uint, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint) int { +func (t *TreeV4) DeleteWithBuffer(buf []uint, address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV4) Delete(buf []uint, address patricia.IPv4Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV4) FindTagsWithFilter(ret []uint, address patricia.IPv4Address, filterFunc FilterFunc) []uint { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc FilterFunc) []uint { + ret := make([]uint, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint, address patricia.IPv4Address, filterFunc FilterFunc) []uint { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV4) FindTagsWithFilter(ret []uint, address patricia.IPv4Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV4) FindTags(ret []uint, address patricia.IPv4Address) []uint { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint { + ret := make([]uint, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint, address patricia.IPv4Address) []uint { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV4) FindDeepestTag(address patricia.IPv4Address) (bool, uint) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV4) FindDeepestTags(ret []uint, address patricia.IPv4Address) (bool, []uint) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV4) FindDeepestTags(address patricia.IPv4Address) (bool, []uint) { + ret := make([]uint, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV4) FindDeepestTagsAppend(ret []uint, address patricia.IPv4Address) (bool, []uint) { root := &t.nodes[1] var found bool var retTagIndex uint diff --git a/uint_tree/tree_v6_generated.go b/uint_tree/tree_v6_generated.go index 2f975e2..d7efcf4 100644 --- a/uint_tree/tree_v6_generated.go +++ b/uint_tree/tree_v6_generated.go @@ -319,8 +319,14 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu } // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed +// - use DeleteWithBuffer if you can reuse slices, to cut down on allocations +func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint) int { + return t.DeleteWithBuffer(make([]uint, 0), address, matchFunc, matchVal) +} + +// DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - uses input slice to reduce allocations -func (t *TreeV6) Delete(buf []uint, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint) int { +func (t *TreeV6) DeleteWithBuffer(buf []uint, address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint) int { // traverse the tree, finding the node and its parent root := &t.nodes[1] var parentIndex uint @@ -464,16 +470,26 @@ func (t *TreeV6) Delete(buf []uint, address patricia.IPv6Address, matchFunc Matc } // FindTagsWithFilter finds all matching tags that passes the filter function -// - input slice is used to reduce allocations - will be reset before it's used -func (t *TreeV6) FindTagsWithFilter(ret []uint, address patricia.IPv6Address, filterFunc FilterFunc) []uint { - ret = t.FindTags(ret, address) +// - use FindTagsWithFilterAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc FilterFunc) []uint { + ret := make([]uint, 0) + return t.FindTagsWithFilterAppend(ret, address, filterFunc) +} - if len(ret) == 0 || filterFunc == nil { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint, address patricia.IPv6Address, filterFunc FilterFunc) []uint { + retPos := len(ret) + ret = t.FindTagsAppend(ret, address) + + if len(ret) == retPos || filterFunc == nil { return ret } - retPos := 0 - for _, val := range ret { + // filter in place + length := len(ret) + for i := retPos; i < length; i++ { + val := ret[i] if filterFunc(val) { ret[retPos] = val retPos++ @@ -482,11 +498,15 @@ func (t *TreeV6) FindTagsWithFilter(ret []uint, address patricia.IPv6Address, fi return ret[:retPos] } -// FindTags finds all matching tags for given address and appends them to ret -// - may return nil if none found -func (t *TreeV6) FindTags(ret []uint, address patricia.IPv6Address) []uint { - ret = ret[:0] +// FindTags finds all matching tags for given address +// - use FindTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint { + ret := make([]uint, 0) + return t.FindTagsAppend(ret, address) +} +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint, address patricia.IPv6Address) []uint { var matchCount uint root := &t.nodes[1] @@ -600,10 +620,15 @@ func (t *TreeV6) FindDeepestTag(address patricia.IPv6Address) (bool, uint) { } // FindDeepestTags finds all tags at the deepest level in the tree, representing the closest match -// - may return nil if nothing found -func (t *TreeV6) FindDeepestTags(ret []uint, address patricia.IPv6Address) (bool, []uint) { - ret = ret[:0] +// - use FindDeepestTagsAppend if you can reuse slices, to cut down on allocations +func (t *TreeV6) FindDeepestTags(address patricia.IPv6Address) (bool, []uint) { + ret := make([]uint, 0) + return t.FindDeepestTagsAppend(ret, address) +} +// FindDeepestTagsAppend finds all tags at the deepest level in the tree, representing the closest match +// - appends results to the input slice +func (t *TreeV6) FindDeepestTagsAppend(ret []uint, address patricia.IPv6Address) (bool, []uint) { root := &t.nodes[1] var found bool var retTagIndex uint From 84f9891666365a80dfe228a70f49681fe513a1a7 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Tue, 31 Aug 2021 17:35:15 +0000 Subject: [PATCH 12/19] Added tests to ensure that the *Append methods append, not just replace --- template/tree_v4_test.go | 118 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/template/tree_v4_test.go b/template/tree_v4_test.go index 54d06a5..cf20fe8 100644 --- a/template/tree_v4_test.go +++ b/template/tree_v4_test.go @@ -17,6 +17,29 @@ func ipv4FromBytes(bytes []byte, length int) patricia.IPv4Address { } } +func BenchmarkFindTags(b *testing.B) { + tagA := "tagA" + tagB := "tagB" + tagC := "tagC" + tagZ := "tagD" + + tree := NewTreeV4() + + tree.Add(patricia.IPv4Address{}, tagZ, nil) // default + tree.Add(ipv4FromBytes([]byte{129, 0, 0, 1}, 7), tagA, nil) + tree.Add(ipv4FromBytes([]byte{160, 0, 0, 0}, 2), tagB, nil) // 160 -> 128 + tree.Add(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), tagC, nil) + + address := patricia.NewIPv4Address(uint32(2156823809), 32) + + var buf []GeneratedType + b.ResetTimer() + for n := 0; n < b.N; n++ { + buf = tree.FindTags(address) + } + _ = buf +} + func BenchmarkFindTagsAppend(b *testing.B) { tagA := "tagA" tagB := "tagB" @@ -31,9 +54,10 @@ func BenchmarkFindTagsAppend(b *testing.B) { tree.Add(ipv4FromBytes([]byte{160, 0, 0, 0}, 2), tagB, nil) // 160 -> 128 tree.Add(ipv4FromBytes([]byte{128, 3, 6, 240}, 32), tagC, nil) + address := patricia.NewIPv4Address(uint32(2156823809), 32) + b.ResetTimer() for n := 0; n < b.N; n++ { - address := patricia.NewIPv4Address(uint32(2156823809), 32) buf = buf[:0] buf = tree.FindTagsAppend(buf, address) } @@ -324,6 +348,98 @@ func TestSimpleTree1(t *testing.T) { assert.Equal(t, "tagC", tag) } +// TestSimpleTree1Append tests that FindTagsAppend appends +func TestSimpleTree1Append(t *testing.T) { + tree := NewTreeV4() + + ipv4a := ipv4FromBytes([]byte{98, 139, 183, 24}, 32) + ipv4b := ipv4FromBytes([]byte{198, 186, 190, 179}, 32) + ipv4c := ipv4FromBytes([]byte{151, 101, 124, 84}, 32) + + tree.Add(ipv4a, "tagA", nil) + tree.Add(ipv4b, "tagB", nil) + tree.Add(ipv4c, "tagC", nil) + + tags := make([]GeneratedType, 0) + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{98, 139, 183, 24}, 32)) + assert.Equal(t, 1, len(tags)) + assert.Equal(t, "tagA", tags[0]) + + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{198, 186, 190, 179}, 32)) + assert.Equal(t, 2, len(tags)) + assert.Equal(t, "tagA", tags[0]) + assert.Equal(t, "tagB", tags[1]) + + tags = tree.FindTagsAppend(tags, ipv4FromBytes([]byte{151, 101, 124, 84}, 32)) + assert.Equal(t, 3, len(tags)) + assert.Equal(t, "tagA", tags[0]) + assert.Equal(t, "tagB", tags[1]) + assert.Equal(t, "tagC", tags[2]) +} + +// TestSimpleTree1FilterAppend tests that FindTagsWithFilterAppend appends +func TestSimpleTree1FilterAppend(t *testing.T) { + assert := assert.New(t) + + include := true + filterFunc := func(val GeneratedType) bool { + return include + } + + tree := NewTreeV4() + + ipv4a := ipv4FromBytes([]byte{98, 139, 183, 24}, 32) + ipv4b := ipv4FromBytes([]byte{198, 186, 190, 179}, 32) + ipv4c := ipv4FromBytes([]byte{151, 101, 124, 84}, 32) + + tree.Add(ipv4a, "tagA", nil) + tree.Add(ipv4b, "tagB", nil) + tree.Add(ipv4c, "tagC", nil) + + include = false + tags := make([]GeneratedType, 0) + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{98, 139, 183, 24}, 32), filterFunc) + assert.Equal(0, len(tags)) + + include = true + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{98, 139, 183, 24}, 32), filterFunc) + assert.Equal(1, len(tags)) + assert.Equal("tagA", tags[0]) + + include = false + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{198, 186, 190, 179}, 32), filterFunc) + assert.Equal(1, len(tags)) + + include = true + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{198, 186, 190, 179}, 32), filterFunc) + assert.Equal(2, len(tags)) + assert.Equal("tagA", tags[0]) + assert.Equal("tagB", tags[1]) + + include = false + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{151, 101, 124, 84}, 32), filterFunc) + assert.Equal(2, len(tags)) + + include = true + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{151, 101, 124, 84}, 32), filterFunc) + assert.Equal(3, len(tags)) + assert.Equal("tagA", tags[0]) + assert.Equal("tagB", tags[1]) + assert.Equal("tagC", tags[2]) + + include = false + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{151, 101, 124, 84}, 32), filterFunc) + assert.Equal(3, len(tags)) + + include = true + tags = tree.FindTagsWithFilterAppend(tags, ipv4FromBytes([]byte{151, 101, 124, 84}, 32), filterFunc) + assert.Equal(4, len(tags)) + assert.Equal("tagA", tags[0]) + assert.Equal("tagB", tags[1]) + assert.Equal("tagC", tags[2]) + assert.Equal("tagC", tags[2]) +} + // Test having a couple of inner nodes func TestSimpleTree2(t *testing.T) { buf := make([]GeneratedType, 0) From 2ab2476a2525e2a86b3f43c8c3c0b4f64c366902 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Tue, 31 Aug 2021 18:41:20 +0000 Subject: [PATCH 13/19] Added unit tests for self-allocating methods Unit tests for FindDeepestTags, FindTags, FindTagsWithFilter --- template/tree_v4_test.go | 200 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/template/tree_v4_test.go b/template/tree_v4_test.go index cf20fe8..9f8a3e6 100644 --- a/template/tree_v4_test.go +++ b/template/tree_v4_test.go @@ -282,6 +282,123 @@ func TestTree2(t *testing.T) { assert.Equal(t, "root_node", tag) } +// TestFindDeepestTags tests self-allocating FindDeepestTags +func TestFindDeepestTags(t *testing.T) { + assert := assert.New(t) + + tags := make([]GeneratedType, 0) + found := false + + tree := NewTreeV4() + // insert a bunch of tags + v4, _, err := patricia.ParseIPFromString("1.2.3.0/24") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "foo", nil) + tree.Add(*v4, "bar", nil) + + v4, _, err = patricia.ParseIPFromString("188.212.216.242") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "a", nil) + + v4, _, err = patricia.ParseIPFromString("171.233.143.228") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "b", nil) + + v4, _, err = patricia.ParseIPFromString("186.244.183.12") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "c", nil) + + v4, _, err = patricia.ParseIPFromString("171.233.143.222") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "d", nil) + + v4, _, err = patricia.ParseIPFromString("190.207.189.24") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "e", nil) + + v4, _, err = patricia.ParseIPFromString("188.212.216.240") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "f", nil) + + v4, _, err = patricia.ParseIPFromString("185.76.10.148") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "g", nil) + + v4, _, err = patricia.ParseIPFromString("14.208.248.50") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "h", nil) + + v4, _, err = patricia.ParseIPFromString("59.60.75.52") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "i", nil) + + v4, _, err = patricia.ParseIPFromString("185.76.10.146") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "j", nil) + tree.Add(*v4, "k", nil) + + // now test + v4, _, _ = patricia.ParseIPFromString("185.76.10.146") + found, tags = tree.FindDeepestTags(*v4) + assert.True(found) + assert.Equal("j", tags[0]) + assert.Equal("k", tags[1]) + assert.Equal(2, len(tags)) + + // test searching for addresses with no leaf nodes + v4, _, _ = patricia.ParseIPFromString("1.2.3.4") + found, tags = tree.FindDeepestTags(*v4) + assert.True(found) + assert.Equal("foo", tags[0]) + assert.Equal("bar", tags[1]) + assert.Equal(2, len(tags)) + + v4, _, _ = patricia.ParseIPFromString("1.2.3.5") + found, tags = tree.FindDeepestTags(*v4) + assert.True(found) + assert.Equal("foo", tags[0]) + assert.Equal("bar", tags[1]) + assert.Equal(2, len(tags)) + + // test searching for an address that has nothing + v4, _, _ = patricia.ParseIPFromString("9.9.9.9") + found, tags = tree.FindDeepestTags(*v4) + assert.False(found) + assert.NotNil(tags) + assert.Equal(0, len(tags)) + + // test searching for an empty address + v4, _, _ = patricia.ParseIPFromString("9.9.9.9/0") + found, tags = tree.FindDeepestTags(*v4) + assert.False(found) + assert.NotNil(tags) + assert.Equal(0, len(tags)) + + // add a root node tag and try again + v4, _, err = patricia.ParseIPFromString("1.1.1.1/0") + assert.NoError(err) + assert.NotNil(v4) + tree.Add(*v4, "root_node", nil) + + v4, _, _ = patricia.ParseIPFromString("9.9.9.9/0") + found, tags = tree.FindDeepestTags(*v4) + assert.True(found) + assert.NotNil(tags) + assert.Equal(1, len(tags)) + assert.Equal("root_node", tags[0]) +} + // test that the find functions don't destroy an address - too brittle and confusing for caller for what gains? func TestAddressReusable(t *testing.T) { tags := make([]GeneratedType, 0) @@ -377,6 +494,32 @@ func TestSimpleTree1Append(t *testing.T) { assert.Equal(t, "tagC", tags[2]) } +// TestSimpleTree1Append tests the self-allocating FindTags +func TestSimpleTree1FindTags(t *testing.T) { + tree := NewTreeV4() + + ipv4a := ipv4FromBytes([]byte{98, 139, 183, 24}, 32) + ipv4b := ipv4FromBytes([]byte{198, 186, 190, 179}, 32) + ipv4c := ipv4FromBytes([]byte{151, 101, 124, 84}, 32) + + tree.Add(ipv4a, "tagA", nil) + tree.Add(ipv4b, "tagB", nil) + tree.Add(ipv4c, "tagC", nil) + + tags := make([]GeneratedType, 0) + tags = tree.FindTags(ipv4FromBytes([]byte{98, 139, 183, 24}, 32)) + assert.Equal(t, 1, len(tags)) + assert.Equal(t, "tagA", tags[0]) + + tags = tree.FindTags(ipv4FromBytes([]byte{198, 186, 190, 179}, 32)) + assert.Equal(t, 1, len(tags)) + assert.Equal(t, "tagB", tags[0]) + + tags = tree.FindTags(ipv4FromBytes([]byte{151, 101, 124, 84}, 32)) + assert.Equal(t, 1, len(tags)) + assert.Equal(t, "tagC", tags[0]) +} + // TestSimpleTree1FilterAppend tests that FindTagsWithFilterAppend appends func TestSimpleTree1FilterAppend(t *testing.T) { assert := assert.New(t) @@ -440,6 +583,63 @@ func TestSimpleTree1FilterAppend(t *testing.T) { assert.Equal("tagC", tags[2]) } +// TestSimpleTree1Filter tests that FindTagsWithFilter +func TestSimpleTree1Filter(t *testing.T) { + assert := assert.New(t) + + include := true + filterFunc := func(val GeneratedType) bool { + return include + } + + tree := NewTreeV4() + + ipv4a := ipv4FromBytes([]byte{98, 139, 183, 24}, 32) + ipv4b := ipv4FromBytes([]byte{198, 186, 190, 179}, 32) + ipv4c := ipv4FromBytes([]byte{151, 101, 124, 84}, 32) + + tree.Add(ipv4a, "tagA", nil) + tree.Add(ipv4b, "tagB", nil) + tree.Add(ipv4c, "tagC", nil) + + include = false + tags := make([]GeneratedType, 0) + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{98, 139, 183, 24}, 32), filterFunc) + assert.Equal(0, len(tags)) + + include = true + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{98, 139, 183, 24}, 32), filterFunc) + assert.Equal(1, len(tags)) + assert.Equal("tagA", tags[0]) + + include = false + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{198, 186, 190, 179}, 32), filterFunc) + assert.Equal(0, len(tags)) + + include = true + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{198, 186, 190, 179}, 32), filterFunc) + assert.Equal(1, len(tags)) + assert.Equal("tagB", tags[0]) + + include = false + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{151, 101, 124, 84}, 32), filterFunc) + assert.Equal(0, len(tags)) + + include = true + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{151, 101, 124, 84}, 32), filterFunc) + assert.Equal(1, len(tags)) + assert.Equal("tagC", tags[0]) + + include = false + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{151, 101, 124, 84}, 32), filterFunc) + assert.Equal(0, len(tags)) + + include = true + tags = tree.FindTagsWithFilter(ipv4FromBytes([]byte{151, 101, 124, 84}, 32), filterFunc) + assert.Equal(1, len(tags)) + assert.Equal("tagC", tags[0]) +} + // Test having a couple of inner nodes func TestSimpleTree2(t *testing.T) { buf := make([]GeneratedType, 0) From 7bf755ca5a8129bcc9968d600fb473236b7a68a9 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Tue, 31 Aug 2021 18:45:39 +0000 Subject: [PATCH 14/19] Added unit tests for self-allocating Delete method --- template/tree_v4_test.go | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/template/tree_v4_test.go b/template/tree_v4_test.go index 9f8a3e6..ccd7bfb 100644 --- a/template/tree_v4_test.go +++ b/template/tree_v4_test.go @@ -683,6 +683,47 @@ func TestSimpleTree2(t *testing.T) { assert.Equal(t, 1, tree.countNodes(1)) } +// Test having a couple of inner nodes - with self-allocating Delete method +func TestSimpleTree2WithDelete(t *testing.T) { + ipA, _, _ := patricia.ParseIPFromString("203.143.220.0/23") + ipB, _, _ := patricia.ParseIPFromString("203.143.220.198/32") + ipC, _, _ := patricia.ParseIPFromString("203.143.0.0/16") + ipD, _, _ := patricia.ParseIPFromString("203.143.221.75/32") + + // add the 4 addresses + tree := NewTreeV4() + tree.Add(*ipA, "A", nil) + tree.Add(*ipB, "B", nil) + tree.Add(*ipC, "C", nil) + tree.Add(*ipD, "D", nil) + + // find the 4 addresses + found, _ := tree.FindDeepestTag(*ipA) + assert.True(t, found) + found, _ = tree.FindDeepestTag(*ipB) + assert.True(t, found) + found, _ = tree.FindDeepestTag(*ipC) + assert.True(t, found) + found, _ = tree.FindDeepestTag(*ipD) + assert.True(t, found) + + // delete each one + matchFunc := func(a GeneratedType, b GeneratedType) bool { + return a == b + } + deleteCount := tree.Delete(*ipA, matchFunc, "A") + assert.Equal(t, 1, deleteCount) + deleteCount = tree.Delete(*ipB, matchFunc, "B") + assert.Equal(t, 1, deleteCount) + deleteCount = tree.Delete(*ipC, matchFunc, "C") + assert.Equal(t, 1, deleteCount) + deleteCount = tree.Delete(*ipD, matchFunc, "D") + assert.Equal(t, 1, deleteCount) + + // should have zero logical nodes except for root + assert.Equal(t, 1, tree.countNodes(1)) +} + func TestSimpleTree(t *testing.T) { tags := make([]GeneratedType, 0) From b60eacf32db8464316314e20f014c4970f860ba5 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Wed, 1 Sep 2021 20:48:32 +0000 Subject: [PATCH 15/19] removed unnecessary counter --- template/tree_v4.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/template/tree_v4.go b/template/tree_v4.go index 8b0c577..6d2ed65 100644 --- a/template/tree_v4.go +++ b/template/tree_v4.go @@ -527,9 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []GeneratedType, address patricia.IPv4Addres } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } From 94f2b4b98276939729c217ed336a8bd22adec731 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Thu, 2 Sep 2021 03:36:46 +0000 Subject: [PATCH 16/19] Finding tags with filter now reduces allocations when no match The methods that take a filter no longer allocate first, then filter out. We now only add them to the slice if they match. Did this by putting the main logic in the *Filter methods, then having the non-Filter methods call them, with a nil filter. --- template/tree_v4.go | 52 ++++++++++++++------------------------ template/tree_v4_manual.go | 2 +- template/tree_v4_test.go | 22 ++++++++-------- template/tree_v6_manual.go | 2 +- 4 files changed, 32 insertions(+), 46 deletions(-) diff --git a/template/tree_v4.go b/template/tree_v4.go index 6d2ed65..f320cd1 100644 --- a/template/tree_v4.go +++ b/template/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag GeneratedType, nodeIndex uint, matchFunc MatchesFunc return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []GeneratedType, nodeIndex uint) []GeneratedType { +func (t *TreeV4) tagsForNode(ret []GeneratedType, nodeIndex uint, filterFunc FilterFunc) []GeneratedType { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []GeneratedType, nodeIndex uint) []GeneratedTyp tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) GeneratedType { func (t *TreeV4) deleteTag(buf []GeneratedType, nodeIndex uint, matchTag GeneratedType, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []GeneratedType, address patricia.IPv4Address, filterFunc FilterFunc) []GeneratedType { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []GeneratedType, address patricia.IPv4Address) []GeneratedType { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []GeneratedType { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []GeneratedType, address patricia.IPv4Address) []GeneratedType { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []GeneratedType, address patricia.IPv4Address, filterFunc FilterFunc) []GeneratedType { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -541,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []GeneratedType, address patricia.IPv4Addres // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -638,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []GeneratedType, address patricia.IPv if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -651,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []GeneratedType, address patricia.IPv // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -669,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []GeneratedType, address patricia.IPv if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/template/tree_v4_manual.go b/template/tree_v4_manual.go index 0d18b52..106cbd6 100644 --- a/template/tree_v4_manual.go +++ b/template/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]GeneratedType, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/template/tree_v4_test.go b/template/tree_v4_test.go index ccd7bfb..46e77a6 100644 --- a/template/tree_v4_test.go +++ b/template/tree_v4_test.go @@ -1031,13 +1031,13 @@ func TestDelete1(t *testing.T) { // verify status of internal nodes collections assert.Zero(t, len(tree.availableIndexes)) - assert.Equal(t, "tagZ", tree.tagsForNode(tags, 1)[0]) + assert.Equal(t, "tagZ", tree.tagsForNode(tags, 1, nil)[0], nil) tags = tags[:0] - assert.Equal(t, "tagA", tree.tagsForNode(tags, 2)[0]) + assert.Equal(t, "tagA", tree.tagsForNode(tags, 2, nil)[0], nil) tags = tags[:0] - assert.Equal(t, "tagB", tree.tagsForNode(tags, 3)[0]) + assert.Equal(t, "tagB", tree.tagsForNode(tags, 3, nil)[0], nil) tags = tags[:0] - assert.Equal(t, "tagC", tree.tagsForNode(tags, 4)[0]) + assert.Equal(t, "tagC", tree.tagsForNode(tags, 4, nil)[0], nil) tags = tags[:0] // three tags in a hierarchy - ask for an exact match, receive all 3 and the root @@ -1112,7 +1112,7 @@ func TestDelete1(t *testing.T) { assert.Equal(t, uint(2), tree.availableIndexes[0]) tags = tags[:0] - assert.Equal(t, "tagE", tree.tagsForNode(tags, 3)[0]) + assert.Equal(t, "tagE", tree.tagsForNode(tags, 3, nil)[0]) // 6. delete tag C count = tree.DeleteWithBuffer(tags, ipv4FromBytes([]byte{128, 3, 6, 240}, 32), matchFunc, "tagC") @@ -1153,16 +1153,16 @@ func TestTagsMap(t *testing.T) { // verify assert.Equal(t, 3, tree.nodes[1].TagCount) assert.Equal(t, "tagA", tree.firstTagForNode(1)) - assert.Equal(t, 3, len(tree.tagsForNode(tags, 1))) + assert.Equal(t, 3, len(tree.tagsForNode(tags, 1, nil))) tags = tags[:0] - assert.Equal(t, "tagA", tree.tagsForNode(tags, 1)[0]) + assert.Equal(t, "tagA", tree.tagsForNode(tags, 1, nil)[0]) tags = tags[:0] - assert.Equal(t, "tagB", tree.tagsForNode(tags, 1)[1]) + assert.Equal(t, "tagB", tree.tagsForNode(tags, 1, nil)[1]) tags = tags[:0] - assert.Equal(t, "tagC", tree.tagsForNode(tags, 1)[2]) + assert.Equal(t, "tagC", tree.tagsForNode(tags, 1, nil)[2]) tags = tags[:0] // delete tagB @@ -1176,10 +1176,10 @@ func TestTagsMap(t *testing.T) { assert.Equal(t, 1, deleted) assert.Equal(t, 2, kept) assert.Equal(t, 2, tree.nodes[1].TagCount) - assert.Equal(t, "tagA", tree.tagsForNode(tags, 1)[0]) + assert.Equal(t, "tagA", tree.tagsForNode(tags, 1, nil)[0]) tags = tags[:0] - assert.Equal(t, "tagC", tree.tagsForNode(tags, 1)[1]) + assert.Equal(t, "tagC", tree.tagsForNode(tags, 1, nil)[1]) tags = tags[:0] } diff --git a/template/tree_v6_manual.go b/template/tree_v6_manual.go index 6f36820..26688b3 100644 --- a/template/tree_v6_manual.go +++ b/template/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]GeneratedType, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } From 5588ed12552355fd8518ca94e5cea1c848a6869e Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Thu, 2 Sep 2021 03:38:01 +0000 Subject: [PATCH 17/19] code gen --- bool_tree/tree_v4.go | 54 ++++++++++------------------ bool_tree/tree_v4_manual.go | 2 +- bool_tree/tree_v6_generated.go | 54 ++++++++++------------------ bool_tree/tree_v6_manual.go | 2 +- byte_tree/tree_v4.go | 54 ++++++++++------------------ byte_tree/tree_v4_manual.go | 2 +- byte_tree/tree_v6_generated.go | 54 ++++++++++------------------ byte_tree/tree_v6_manual.go | 2 +- complex128_tree/tree_v4.go | 54 ++++++++++------------------ complex128_tree/tree_v4_manual.go | 2 +- complex128_tree/tree_v6_generated.go | 54 ++++++++++------------------ complex128_tree/tree_v6_manual.go | 2 +- complex64_tree/tree_v4.go | 54 ++++++++++------------------ complex64_tree/tree_v4_manual.go | 2 +- complex64_tree/tree_v6_generated.go | 54 ++++++++++------------------ complex64_tree/tree_v6_manual.go | 2 +- float32_tree/tree_v4.go | 54 ++++++++++------------------ float32_tree/tree_v4_manual.go | 2 +- float32_tree/tree_v6_generated.go | 54 ++++++++++------------------ float32_tree/tree_v6_manual.go | 2 +- float64_tree/tree_v4.go | 54 ++++++++++------------------ float64_tree/tree_v4_manual.go | 2 +- float64_tree/tree_v6_generated.go | 54 ++++++++++------------------ float64_tree/tree_v6_manual.go | 2 +- int16_tree/tree_v4.go | 54 ++++++++++------------------ int16_tree/tree_v4_manual.go | 2 +- int16_tree/tree_v6_generated.go | 54 ++++++++++------------------ int16_tree/tree_v6_manual.go | 2 +- int32_tree/tree_v4.go | 54 ++++++++++------------------ int32_tree/tree_v4_manual.go | 2 +- int32_tree/tree_v6_generated.go | 54 ++++++++++------------------ int32_tree/tree_v6_manual.go | 2 +- int64_tree/tree_v4.go | 54 ++++++++++------------------ int64_tree/tree_v4_manual.go | 2 +- int64_tree/tree_v6_generated.go | 54 ++++++++++------------------ int64_tree/tree_v6_manual.go | 2 +- int8_tree/tree_v4.go | 54 ++++++++++------------------ int8_tree/tree_v4_manual.go | 2 +- int8_tree/tree_v6_generated.go | 54 ++++++++++------------------ int8_tree/tree_v6_manual.go | 2 +- int_tree/tree_v4.go | 54 ++++++++++------------------ int_tree/tree_v4_manual.go | 2 +- int_tree/tree_v6_generated.go | 54 ++++++++++------------------ int_tree/tree_v6_manual.go | 2 +- rune_tree/tree_v4.go | 54 ++++++++++------------------ rune_tree/tree_v4_manual.go | 2 +- rune_tree/tree_v6_generated.go | 54 ++++++++++------------------ rune_tree/tree_v6_manual.go | 2 +- string_tree/tree_v4.go | 54 ++++++++++------------------ string_tree/tree_v4_manual.go | 2 +- string_tree/tree_v6_generated.go | 54 ++++++++++------------------ string_tree/tree_v6_manual.go | 2 +- template/tree_v6_generated.go | 54 ++++++++++------------------ uint16_tree/tree_v4.go | 54 ++++++++++------------------ uint16_tree/tree_v4_manual.go | 2 +- uint16_tree/tree_v6_generated.go | 54 ++++++++++------------------ uint16_tree/tree_v6_manual.go | 2 +- uint32_tree/tree_v4.go | 54 ++++++++++------------------ uint32_tree/tree_v4_manual.go | 2 +- uint32_tree/tree_v6_generated.go | 54 ++++++++++------------------ uint32_tree/tree_v6_manual.go | 2 +- uint64_tree/tree_v4.go | 54 ++++++++++------------------ uint64_tree/tree_v4_manual.go | 2 +- uint64_tree/tree_v6_generated.go | 54 ++++++++++------------------ uint64_tree/tree_v6_manual.go | 2 +- uint8_tree/tree_v4.go | 54 ++++++++++------------------ uint8_tree/tree_v4_manual.go | 2 +- uint8_tree/tree_v6_generated.go | 54 ++++++++++------------------ uint8_tree/tree_v6_manual.go | 2 +- uint_tree/tree_v4.go | 54 ++++++++++------------------ uint_tree/tree_v4_manual.go | 2 +- uint_tree/tree_v6_generated.go | 54 ++++++++++------------------ uint_tree/tree_v6_manual.go | 2 +- 73 files changed, 739 insertions(+), 1331 deletions(-) diff --git a/bool_tree/tree_v4.go b/bool_tree/tree_v4.go index 4a02207..5234fe2 100644 --- a/bool_tree/tree_v4.go +++ b/bool_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag bool, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []bool, nodeIndex uint) []bool { +func (t *TreeV4) tagsForNode(ret []bool, nodeIndex uint, filterFunc FilterFunc) []bool { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []bool, nodeIndex uint) []bool { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) bool { func (t *TreeV4) deleteTag(buf []bool, nodeIndex uint, matchTag bool, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []bool, address patricia.IPv4Address, filterFunc FilterFunc) []bool { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []bool, address patricia.IPv4Address) []bool { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []bool { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []bool, address patricia.IPv4Address) []bool { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []bool, address patricia.IPv4Address, filterFunc FilterFunc) []bool { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []bool, address patricia.IPv4Address) []bool } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []bool, address patricia.IPv4Address) []bool // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []bool, address patricia.IPv4Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []bool, address patricia.IPv4Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []bool, address patricia.IPv4Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/bool_tree/tree_v4_manual.go b/bool_tree/tree_v4_manual.go index 68d0e43..833a9f9 100644 --- a/bool_tree/tree_v4_manual.go +++ b/bool_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]bool, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/bool_tree/tree_v6_generated.go b/bool_tree/tree_v6_generated.go index 2ed579a..f804306 100644 --- a/bool_tree/tree_v6_generated.go +++ b/bool_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag bool, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []bool, nodeIndex uint) []bool { +func (t *TreeV6) tagsForNode(ret []bool, nodeIndex uint, filterFunc FilterFunc) []bool { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []bool, nodeIndex uint) []bool { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) bool { func (t *TreeV6) deleteTag(buf []bool, nodeIndex uint, matchTag bool, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []bool, address patricia.IPv6Address, filterFunc FilterFunc) []bool { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []bool, address patricia.IPv6Address) []bool { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []bool { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []bool, address patricia.IPv6Address) []bool { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []bool, address patricia.IPv6Address, filterFunc FilterFunc) []bool { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []bool, address patricia.IPv6Address) []bool } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []bool, address patricia.IPv6Address) []bool // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []bool, address patricia.IPv6Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []bool, address patricia.IPv6Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []bool, address patricia.IPv6Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/bool_tree/tree_v6_manual.go b/bool_tree/tree_v6_manual.go index 6d8e2f0..b209e5f 100644 --- a/bool_tree/tree_v6_manual.go +++ b/bool_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]bool, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/byte_tree/tree_v4.go b/byte_tree/tree_v4.go index 0ba1fdf..23f29cb 100644 --- a/byte_tree/tree_v4.go +++ b/byte_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag byte, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []byte, nodeIndex uint) []byte { +func (t *TreeV4) tagsForNode(ret []byte, nodeIndex uint, filterFunc FilterFunc) []byte { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []byte, nodeIndex uint) []byte { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) byte { func (t *TreeV4) deleteTag(buf []byte, nodeIndex uint, matchTag byte, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []byte, address patricia.IPv4Address, filterFunc FilterFunc) []byte { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []byte, address patricia.IPv4Address) []byte { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []byte { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []byte, address patricia.IPv4Address) []byte { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []byte, address patricia.IPv4Address, filterFunc FilterFunc) []byte { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []byte, address patricia.IPv4Address) []byte } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []byte, address patricia.IPv4Address) []byte // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []byte, address patricia.IPv4Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []byte, address patricia.IPv4Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []byte, address patricia.IPv4Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/byte_tree/tree_v4_manual.go b/byte_tree/tree_v4_manual.go index addbc75..e9edfa8 100644 --- a/byte_tree/tree_v4_manual.go +++ b/byte_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]byte, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/byte_tree/tree_v6_generated.go b/byte_tree/tree_v6_generated.go index 334563d..900dcf6 100644 --- a/byte_tree/tree_v6_generated.go +++ b/byte_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag byte, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []byte, nodeIndex uint) []byte { +func (t *TreeV6) tagsForNode(ret []byte, nodeIndex uint, filterFunc FilterFunc) []byte { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []byte, nodeIndex uint) []byte { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) byte { func (t *TreeV6) deleteTag(buf []byte, nodeIndex uint, matchTag byte, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []byte, address patricia.IPv6Address, filterFunc FilterFunc) []byte { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []byte, address patricia.IPv6Address) []byte { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []byte { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []byte, address patricia.IPv6Address) []byte { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []byte, address patricia.IPv6Address, filterFunc FilterFunc) []byte { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []byte, address patricia.IPv6Address) []byte } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []byte, address patricia.IPv6Address) []byte // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []byte, address patricia.IPv6Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []byte, address patricia.IPv6Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []byte, address patricia.IPv6Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/byte_tree/tree_v6_manual.go b/byte_tree/tree_v6_manual.go index 201342f..5dff890 100644 --- a/byte_tree/tree_v6_manual.go +++ b/byte_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]byte, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/complex128_tree/tree_v4.go b/complex128_tree/tree_v4.go index 3203c3b..910e3a0 100644 --- a/complex128_tree/tree_v4.go +++ b/complex128_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag complex128, nodeIndex uint, matchFunc MatchesFunc, r return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []complex128, nodeIndex uint) []complex128 { +func (t *TreeV4) tagsForNode(ret []complex128, nodeIndex uint, filterFunc FilterFunc) []complex128 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []complex128, nodeIndex uint) []complex128 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) complex128 { func (t *TreeV4) deleteTag(buf []complex128, nodeIndex uint, matchTag complex128, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []complex128, address patricia.IPv4Address, filterFunc FilterFunc) []complex128 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []complex128, address patricia.IPv4Address) []complex128 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []complex128 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []complex128, address patricia.IPv4Address) []complex128 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []complex128, address patricia.IPv4Address, filterFunc FilterFunc) []complex128 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []complex128, address patricia.IPv4Address) } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []complex128, address patricia.IPv4Address) // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []complex128, address patricia.IPv4Ad if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []complex128, address patricia.IPv4Ad // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []complex128, address patricia.IPv4Ad if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/complex128_tree/tree_v4_manual.go b/complex128_tree/tree_v4_manual.go index 2e43f23..12730a5 100644 --- a/complex128_tree/tree_v4_manual.go +++ b/complex128_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]complex128, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/complex128_tree/tree_v6_generated.go b/complex128_tree/tree_v6_generated.go index caabde6..8d01bb0 100644 --- a/complex128_tree/tree_v6_generated.go +++ b/complex128_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag complex128, nodeIndex uint, matchFunc MatchesFunc, r return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []complex128, nodeIndex uint) []complex128 { +func (t *TreeV6) tagsForNode(ret []complex128, nodeIndex uint, filterFunc FilterFunc) []complex128 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []complex128, nodeIndex uint) []complex128 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) complex128 { func (t *TreeV6) deleteTag(buf []complex128, nodeIndex uint, matchTag complex128, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []complex128, address patricia.IPv6Address, filterFunc FilterFunc) []complex128 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []complex128, address patricia.IPv6Address) []complex128 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []complex128 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []complex128, address patricia.IPv6Address) []complex128 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []complex128, address patricia.IPv6Address, filterFunc FilterFunc) []complex128 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []complex128, address patricia.IPv6Address) } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []complex128, address patricia.IPv6Address) // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []complex128, address patricia.IPv6Ad if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []complex128, address patricia.IPv6Ad // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []complex128, address patricia.IPv6Ad if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/complex128_tree/tree_v6_manual.go b/complex128_tree/tree_v6_manual.go index ced60da..0c81ed1 100644 --- a/complex128_tree/tree_v6_manual.go +++ b/complex128_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]complex128, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/complex64_tree/tree_v4.go b/complex64_tree/tree_v4.go index fd5076f..1851a92 100644 --- a/complex64_tree/tree_v4.go +++ b/complex64_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag complex64, nodeIndex uint, matchFunc MatchesFunc, re return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []complex64, nodeIndex uint) []complex64 { +func (t *TreeV4) tagsForNode(ret []complex64, nodeIndex uint, filterFunc FilterFunc) []complex64 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []complex64, nodeIndex uint) []complex64 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) complex64 { func (t *TreeV4) deleteTag(buf []complex64, nodeIndex uint, matchTag complex64, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []complex64, address patricia.IPv4Address, filterFunc FilterFunc) []complex64 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []complex64, address patricia.IPv4Address) []complex64 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []complex64 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []complex64, address patricia.IPv4Address) []complex64 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []complex64, address patricia.IPv4Address, filterFunc FilterFunc) []complex64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []complex64, address patricia.IPv4Address) [ } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []complex64, address patricia.IPv4Address) [ // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []complex64, address patricia.IPv4Add if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []complex64, address patricia.IPv4Add // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []complex64, address patricia.IPv4Add if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/complex64_tree/tree_v4_manual.go b/complex64_tree/tree_v4_manual.go index 224167c..5351cd0 100644 --- a/complex64_tree/tree_v4_manual.go +++ b/complex64_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]complex64, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/complex64_tree/tree_v6_generated.go b/complex64_tree/tree_v6_generated.go index 6e83666..0859750 100644 --- a/complex64_tree/tree_v6_generated.go +++ b/complex64_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag complex64, nodeIndex uint, matchFunc MatchesFunc, re return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []complex64, nodeIndex uint) []complex64 { +func (t *TreeV6) tagsForNode(ret []complex64, nodeIndex uint, filterFunc FilterFunc) []complex64 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []complex64, nodeIndex uint) []complex64 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) complex64 { func (t *TreeV6) deleteTag(buf []complex64, nodeIndex uint, matchTag complex64, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []complex64, address patricia.IPv6Address, filterFunc FilterFunc) []complex64 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []complex64, address patricia.IPv6Address) []complex64 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []complex64 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []complex64, address patricia.IPv6Address) []complex64 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []complex64, address patricia.IPv6Address, filterFunc FilterFunc) []complex64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []complex64, address patricia.IPv6Address) [ } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []complex64, address patricia.IPv6Address) [ // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []complex64, address patricia.IPv6Add if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []complex64, address patricia.IPv6Add // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []complex64, address patricia.IPv6Add if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/complex64_tree/tree_v6_manual.go b/complex64_tree/tree_v6_manual.go index c4ea91f..2a4604a 100644 --- a/complex64_tree/tree_v6_manual.go +++ b/complex64_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]complex64, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/float32_tree/tree_v4.go b/float32_tree/tree_v4.go index af7b6ae..74ed9e3 100644 --- a/float32_tree/tree_v4.go +++ b/float32_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag float32, nodeIndex uint, matchFunc MatchesFunc, repl return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []float32, nodeIndex uint) []float32 { +func (t *TreeV4) tagsForNode(ret []float32, nodeIndex uint, filterFunc FilterFunc) []float32 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []float32, nodeIndex uint) []float32 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) float32 { func (t *TreeV4) deleteTag(buf []float32, nodeIndex uint, matchTag float32, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []float32, address patricia.IPv4Address, filterFunc FilterFunc) []float32 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []float32, address patricia.IPv4Address) []float32 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []float32 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []float32, address patricia.IPv4Address) []float32 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []float32, address patricia.IPv4Address, filterFunc FilterFunc) []float32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []float32, address patricia.IPv4Address) []f } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []float32, address patricia.IPv4Address) []f // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []float32, address patricia.IPv4Addre if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []float32, address patricia.IPv4Addre // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []float32, address patricia.IPv4Addre if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/float32_tree/tree_v4_manual.go b/float32_tree/tree_v4_manual.go index 61455df..687fbdb 100644 --- a/float32_tree/tree_v4_manual.go +++ b/float32_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]float32, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/float32_tree/tree_v6_generated.go b/float32_tree/tree_v6_generated.go index c2a787d..3f3bc9d 100644 --- a/float32_tree/tree_v6_generated.go +++ b/float32_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag float32, nodeIndex uint, matchFunc MatchesFunc, repl return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []float32, nodeIndex uint) []float32 { +func (t *TreeV6) tagsForNode(ret []float32, nodeIndex uint, filterFunc FilterFunc) []float32 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []float32, nodeIndex uint) []float32 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) float32 { func (t *TreeV6) deleteTag(buf []float32, nodeIndex uint, matchTag float32, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []float32, address patricia.IPv6Address, filterFunc FilterFunc) []float32 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []float32, address patricia.IPv6Address) []float32 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []float32 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []float32, address patricia.IPv6Address) []float32 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []float32, address patricia.IPv6Address, filterFunc FilterFunc) []float32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []float32, address patricia.IPv6Address) []f } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []float32, address patricia.IPv6Address) []f // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []float32, address patricia.IPv6Addre if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []float32, address patricia.IPv6Addre // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []float32, address patricia.IPv6Addre if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/float32_tree/tree_v6_manual.go b/float32_tree/tree_v6_manual.go index 063dc21..f46002c 100644 --- a/float32_tree/tree_v6_manual.go +++ b/float32_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]float32, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/float64_tree/tree_v4.go b/float64_tree/tree_v4.go index 2471a77..c781c09 100644 --- a/float64_tree/tree_v4.go +++ b/float64_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag float64, nodeIndex uint, matchFunc MatchesFunc, repl return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []float64, nodeIndex uint) []float64 { +func (t *TreeV4) tagsForNode(ret []float64, nodeIndex uint, filterFunc FilterFunc) []float64 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []float64, nodeIndex uint) []float64 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) float64 { func (t *TreeV4) deleteTag(buf []float64, nodeIndex uint, matchTag float64, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []float64, address patricia.IPv4Address, filterFunc FilterFunc) []float64 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []float64, address patricia.IPv4Address) []float64 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []float64 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []float64, address patricia.IPv4Address) []float64 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []float64, address patricia.IPv4Address, filterFunc FilterFunc) []float64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []float64, address patricia.IPv4Address) []f } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []float64, address patricia.IPv4Address) []f // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []float64, address patricia.IPv4Addre if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []float64, address patricia.IPv4Addre // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []float64, address patricia.IPv4Addre if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/float64_tree/tree_v4_manual.go b/float64_tree/tree_v4_manual.go index 0f069db..adcdcf8 100644 --- a/float64_tree/tree_v4_manual.go +++ b/float64_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]float64, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/float64_tree/tree_v6_generated.go b/float64_tree/tree_v6_generated.go index 3ea218f..27cb247 100644 --- a/float64_tree/tree_v6_generated.go +++ b/float64_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag float64, nodeIndex uint, matchFunc MatchesFunc, repl return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []float64, nodeIndex uint) []float64 { +func (t *TreeV6) tagsForNode(ret []float64, nodeIndex uint, filterFunc FilterFunc) []float64 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []float64, nodeIndex uint) []float64 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) float64 { func (t *TreeV6) deleteTag(buf []float64, nodeIndex uint, matchTag float64, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []float64, address patricia.IPv6Address, filterFunc FilterFunc) []float64 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []float64, address patricia.IPv6Address) []float64 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []float64 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []float64, address patricia.IPv6Address) []float64 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []float64, address patricia.IPv6Address, filterFunc FilterFunc) []float64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []float64, address patricia.IPv6Address) []f } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []float64, address patricia.IPv6Address) []f // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []float64, address patricia.IPv6Addre if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []float64, address patricia.IPv6Addre // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []float64, address patricia.IPv6Addre if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/float64_tree/tree_v6_manual.go b/float64_tree/tree_v6_manual.go index b5c4086..c5fc87e 100644 --- a/float64_tree/tree_v6_manual.go +++ b/float64_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]float64, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int16_tree/tree_v4.go b/int16_tree/tree_v4.go index b1c090e..4b09d75 100644 --- a/int16_tree/tree_v4.go +++ b/int16_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag int16, nodeIndex uint, matchFunc MatchesFunc, replac return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []int16, nodeIndex uint) []int16 { +func (t *TreeV4) tagsForNode(ret []int16, nodeIndex uint, filterFunc FilterFunc) []int16 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []int16, nodeIndex uint) []int16 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int16 { func (t *TreeV4) deleteTag(buf []int16, nodeIndex uint, matchTag int16, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []int16, address patricia.IPv4Address, filterFunc FilterFunc) []int16 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int16, address patricia.IPv4Address) []int16 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []int16 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int16, address patricia.IPv4Address) []int16 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int16, address patricia.IPv4Address, filterFunc FilterFunc) []int16 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []int16, address patricia.IPv4Address) []int } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []int16, address patricia.IPv4Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int16, address patricia.IPv4Address if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int16, address patricia.IPv4Address // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int16, address patricia.IPv4Address if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int16_tree/tree_v4_manual.go b/int16_tree/tree_v4_manual.go index 3221573..4dbc45c 100644 --- a/int16_tree/tree_v4_manual.go +++ b/int16_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]int16, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int16_tree/tree_v6_generated.go b/int16_tree/tree_v6_generated.go index 3bc4366..3be110d 100644 --- a/int16_tree/tree_v6_generated.go +++ b/int16_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag int16, nodeIndex uint, matchFunc MatchesFunc, replac return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []int16, nodeIndex uint) []int16 { +func (t *TreeV6) tagsForNode(ret []int16, nodeIndex uint, filterFunc FilterFunc) []int16 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []int16, nodeIndex uint) []int16 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int16 { func (t *TreeV6) deleteTag(buf []int16, nodeIndex uint, matchTag int16, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []int16, address patricia.IPv6Address, filterFunc FilterFunc) []int16 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int16, address patricia.IPv6Address) []int16 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []int16 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int16, address patricia.IPv6Address) []int16 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int16, address patricia.IPv6Address, filterFunc FilterFunc) []int16 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []int16, address patricia.IPv6Address) []int } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []int16, address patricia.IPv6Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int16, address patricia.IPv6Address if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int16, address patricia.IPv6Address // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int16, address patricia.IPv6Address if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int16_tree/tree_v6_manual.go b/int16_tree/tree_v6_manual.go index 3d16e81..d8424e4 100644 --- a/int16_tree/tree_v6_manual.go +++ b/int16_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]int16, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int32_tree/tree_v4.go b/int32_tree/tree_v4.go index 15d62a5..183be14 100644 --- a/int32_tree/tree_v4.go +++ b/int32_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag int32, nodeIndex uint, matchFunc MatchesFunc, replac return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []int32, nodeIndex uint) []int32 { +func (t *TreeV4) tagsForNode(ret []int32, nodeIndex uint, filterFunc FilterFunc) []int32 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []int32, nodeIndex uint) []int32 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int32 { func (t *TreeV4) deleteTag(buf []int32, nodeIndex uint, matchTag int32, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []int32, address patricia.IPv4Address, filterFunc FilterFunc) []int32 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int32, address patricia.IPv4Address) []int32 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []int32 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int32, address patricia.IPv4Address) []int32 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int32, address patricia.IPv4Address, filterFunc FilterFunc) []int32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []int32, address patricia.IPv4Address) []int } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []int32, address patricia.IPv4Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int32, address patricia.IPv4Address if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int32, address patricia.IPv4Address // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int32, address patricia.IPv4Address if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int32_tree/tree_v4_manual.go b/int32_tree/tree_v4_manual.go index 1450a01..b7786d4 100644 --- a/int32_tree/tree_v4_manual.go +++ b/int32_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]int32, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int32_tree/tree_v6_generated.go b/int32_tree/tree_v6_generated.go index 6093324..6c181fc 100644 --- a/int32_tree/tree_v6_generated.go +++ b/int32_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag int32, nodeIndex uint, matchFunc MatchesFunc, replac return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []int32, nodeIndex uint) []int32 { +func (t *TreeV6) tagsForNode(ret []int32, nodeIndex uint, filterFunc FilterFunc) []int32 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []int32, nodeIndex uint) []int32 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int32 { func (t *TreeV6) deleteTag(buf []int32, nodeIndex uint, matchTag int32, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []int32, address patricia.IPv6Address, filterFunc FilterFunc) []int32 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int32, address patricia.IPv6Address) []int32 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []int32 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int32, address patricia.IPv6Address) []int32 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int32, address patricia.IPv6Address, filterFunc FilterFunc) []int32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []int32, address patricia.IPv6Address) []int } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []int32, address patricia.IPv6Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int32, address patricia.IPv6Address if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int32, address patricia.IPv6Address // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int32, address patricia.IPv6Address if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int32_tree/tree_v6_manual.go b/int32_tree/tree_v6_manual.go index 572615d..cb834cf 100644 --- a/int32_tree/tree_v6_manual.go +++ b/int32_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]int32, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int64_tree/tree_v4.go b/int64_tree/tree_v4.go index 076e9df..8ae6990 100644 --- a/int64_tree/tree_v4.go +++ b/int64_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag int64, nodeIndex uint, matchFunc MatchesFunc, replac return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []int64, nodeIndex uint) []int64 { +func (t *TreeV4) tagsForNode(ret []int64, nodeIndex uint, filterFunc FilterFunc) []int64 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []int64, nodeIndex uint) []int64 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int64 { func (t *TreeV4) deleteTag(buf []int64, nodeIndex uint, matchTag int64, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []int64, address patricia.IPv4Address, filterFunc FilterFunc) []int64 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int64, address patricia.IPv4Address) []int64 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []int64 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int64, address patricia.IPv4Address) []int64 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int64, address patricia.IPv4Address, filterFunc FilterFunc) []int64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []int64, address patricia.IPv4Address) []int } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []int64, address patricia.IPv4Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int64, address patricia.IPv4Address if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int64, address patricia.IPv4Address // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int64, address patricia.IPv4Address if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int64_tree/tree_v4_manual.go b/int64_tree/tree_v4_manual.go index 11f70e2..a45eb98 100644 --- a/int64_tree/tree_v4_manual.go +++ b/int64_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]int64, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int64_tree/tree_v6_generated.go b/int64_tree/tree_v6_generated.go index 45da713..4ad5f17 100644 --- a/int64_tree/tree_v6_generated.go +++ b/int64_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag int64, nodeIndex uint, matchFunc MatchesFunc, replac return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []int64, nodeIndex uint) []int64 { +func (t *TreeV6) tagsForNode(ret []int64, nodeIndex uint, filterFunc FilterFunc) []int64 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []int64, nodeIndex uint) []int64 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int64 { func (t *TreeV6) deleteTag(buf []int64, nodeIndex uint, matchTag int64, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []int64, address patricia.IPv6Address, filterFunc FilterFunc) []int64 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int64, address patricia.IPv6Address) []int64 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []int64 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int64, address patricia.IPv6Address) []int64 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int64, address patricia.IPv6Address, filterFunc FilterFunc) []int64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []int64, address patricia.IPv6Address) []int } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []int64, address patricia.IPv6Address) []int // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int64, address patricia.IPv6Address if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int64, address patricia.IPv6Address // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int64, address patricia.IPv6Address if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int64_tree/tree_v6_manual.go b/int64_tree/tree_v6_manual.go index d49a930..c6a673e 100644 --- a/int64_tree/tree_v6_manual.go +++ b/int64_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]int64, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int8_tree/tree_v4.go b/int8_tree/tree_v4.go index f032ef3..92d3289 100644 --- a/int8_tree/tree_v4.go +++ b/int8_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag int8, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []int8, nodeIndex uint) []int8 { +func (t *TreeV4) tagsForNode(ret []int8, nodeIndex uint, filterFunc FilterFunc) []int8 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []int8, nodeIndex uint) []int8 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int8 { func (t *TreeV4) deleteTag(buf []int8, nodeIndex uint, matchTag int8, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []int8, address patricia.IPv4Address, filterFunc FilterFunc) []int8 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int8, address patricia.IPv4Address) []int8 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []int8 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int8, address patricia.IPv4Address) []int8 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int8, address patricia.IPv4Address, filterFunc FilterFunc) []int8 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []int8, address patricia.IPv4Address) []int8 } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []int8, address patricia.IPv4Address) []int8 // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int8, address patricia.IPv4Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int8, address patricia.IPv4Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int8, address patricia.IPv4Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int8_tree/tree_v4_manual.go b/int8_tree/tree_v4_manual.go index 5f0aff9..4bf0bbd 100644 --- a/int8_tree/tree_v4_manual.go +++ b/int8_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]int8, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int8_tree/tree_v6_generated.go b/int8_tree/tree_v6_generated.go index 996a6fc..10f7f15 100644 --- a/int8_tree/tree_v6_generated.go +++ b/int8_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag int8, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []int8, nodeIndex uint) []int8 { +func (t *TreeV6) tagsForNode(ret []int8, nodeIndex uint, filterFunc FilterFunc) []int8 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []int8, nodeIndex uint) []int8 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int8 { func (t *TreeV6) deleteTag(buf []int8, nodeIndex uint, matchTag int8, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []int8, address patricia.IPv6Address, filterFunc FilterFunc) []int8 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int8, address patricia.IPv6Address) []int8 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []int8 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int8, address patricia.IPv6Address) []int8 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int8, address patricia.IPv6Address, filterFunc FilterFunc) []int8 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []int8, address patricia.IPv6Address) []int8 } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []int8, address patricia.IPv6Address) []int8 // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int8, address patricia.IPv6Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int8, address patricia.IPv6Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int8, address patricia.IPv6Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int8_tree/tree_v6_manual.go b/int8_tree/tree_v6_manual.go index e128d23..ce9b132 100644 --- a/int8_tree/tree_v6_manual.go +++ b/int8_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]int8, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int_tree/tree_v4.go b/int_tree/tree_v4.go index 8f45798..f93cdd1 100644 --- a/int_tree/tree_v4.go +++ b/int_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag int, nodeIndex uint, matchFunc MatchesFunc, replaceF return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []int, nodeIndex uint) []int { +func (t *TreeV4) tagsForNode(ret []int, nodeIndex uint, filterFunc FilterFunc) []int { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []int, nodeIndex uint) []int { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) int { func (t *TreeV4) deleteTag(buf []int, nodeIndex uint, matchTag int, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []int, address patricia.IPv4Address, filterFunc FilterFunc) []int { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []int, address patricia.IPv4Address) []int { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []int { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []int, address patricia.IPv4Address) []int { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []int, address patricia.IPv4Address, filterFunc FilterFunc) []int { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []int, address patricia.IPv4Address) []int { } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []int, address patricia.IPv4Address) []int { // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int, address patricia.IPv4Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int, address patricia.IPv4Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []int, address patricia.IPv4Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int_tree/tree_v4_manual.go b/int_tree/tree_v4_manual.go index bde6a36..3fafaa5 100644 --- a/int_tree/tree_v4_manual.go +++ b/int_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]int, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/int_tree/tree_v6_generated.go b/int_tree/tree_v6_generated.go index 4d27047..f4ce296 100644 --- a/int_tree/tree_v6_generated.go +++ b/int_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag int, nodeIndex uint, matchFunc MatchesFunc, replaceF return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []int, nodeIndex uint) []int { +func (t *TreeV6) tagsForNode(ret []int, nodeIndex uint, filterFunc FilterFunc) []int { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []int, nodeIndex uint) []int { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) int { func (t *TreeV6) deleteTag(buf []int, nodeIndex uint, matchTag int, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []int, address patricia.IPv6Address, filterFunc FilterFunc) []int { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []int, address patricia.IPv6Address) []int { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []int { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []int, address patricia.IPv6Address) []int { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []int, address patricia.IPv6Address, filterFunc FilterFunc) []int { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []int, address patricia.IPv6Address) []int { } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []int, address patricia.IPv6Address) []int { // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int, address patricia.IPv6Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int, address patricia.IPv6Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []int, address patricia.IPv6Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/int_tree/tree_v6_manual.go b/int_tree/tree_v6_manual.go index d35ec8b..a8a4c35 100644 --- a/int_tree/tree_v6_manual.go +++ b/int_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]int, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/rune_tree/tree_v4.go b/rune_tree/tree_v4.go index 466da6d..9a8788f 100644 --- a/rune_tree/tree_v4.go +++ b/rune_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag rune, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []rune, nodeIndex uint) []rune { +func (t *TreeV4) tagsForNode(ret []rune, nodeIndex uint, filterFunc FilterFunc) []rune { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []rune, nodeIndex uint) []rune { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) rune { func (t *TreeV4) deleteTag(buf []rune, nodeIndex uint, matchTag rune, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []rune, address patricia.IPv4Address, filterFunc FilterFunc) []rune { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []rune, address patricia.IPv4Address) []rune { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []rune { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []rune, address patricia.IPv4Address) []rune { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []rune, address patricia.IPv4Address, filterFunc FilterFunc) []rune { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []rune, address patricia.IPv4Address) []rune } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []rune, address patricia.IPv4Address) []rune // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []rune, address patricia.IPv4Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []rune, address patricia.IPv4Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []rune, address patricia.IPv4Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/rune_tree/tree_v4_manual.go b/rune_tree/tree_v4_manual.go index b2fb65f..e016d74 100644 --- a/rune_tree/tree_v4_manual.go +++ b/rune_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]rune, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/rune_tree/tree_v6_generated.go b/rune_tree/tree_v6_generated.go index af0e50a..87414a7 100644 --- a/rune_tree/tree_v6_generated.go +++ b/rune_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag rune, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []rune, nodeIndex uint) []rune { +func (t *TreeV6) tagsForNode(ret []rune, nodeIndex uint, filterFunc FilterFunc) []rune { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []rune, nodeIndex uint) []rune { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) rune { func (t *TreeV6) deleteTag(buf []rune, nodeIndex uint, matchTag rune, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []rune, address patricia.IPv6Address, filterFunc FilterFunc) []rune { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []rune, address patricia.IPv6Address) []rune { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []rune { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []rune, address patricia.IPv6Address) []rune { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []rune, address patricia.IPv6Address, filterFunc FilterFunc) []rune { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []rune, address patricia.IPv6Address) []rune } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []rune, address patricia.IPv6Address) []rune // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []rune, address patricia.IPv6Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []rune, address patricia.IPv6Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []rune, address patricia.IPv6Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/rune_tree/tree_v6_manual.go b/rune_tree/tree_v6_manual.go index 4235695..2fa1470 100644 --- a/rune_tree/tree_v6_manual.go +++ b/rune_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]rune, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/string_tree/tree_v4.go b/string_tree/tree_v4.go index 64580db..ad8d929 100644 --- a/string_tree/tree_v4.go +++ b/string_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag string, nodeIndex uint, matchFunc MatchesFunc, repla return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []string, nodeIndex uint) []string { +func (t *TreeV4) tagsForNode(ret []string, nodeIndex uint, filterFunc FilterFunc) []string { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []string, nodeIndex uint) []string { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) string { func (t *TreeV4) deleteTag(buf []string, nodeIndex uint, matchTag string, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []string, address patricia.IPv4Address, filterFunc FilterFunc) []string { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []string, address patricia.IPv4Address) []string { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []string { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []string, address patricia.IPv4Address) []string { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []string, address patricia.IPv4Address, filterFunc FilterFunc) []string { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []string, address patricia.IPv4Address) []st } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []string, address patricia.IPv4Address) []st // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []string, address patricia.IPv4Addres if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []string, address patricia.IPv4Addres // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []string, address patricia.IPv4Addres if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/string_tree/tree_v4_manual.go b/string_tree/tree_v4_manual.go index ce1444c..2bc0bae 100644 --- a/string_tree/tree_v4_manual.go +++ b/string_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]string, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/string_tree/tree_v6_generated.go b/string_tree/tree_v6_generated.go index 65d1bad..b77a3b4 100644 --- a/string_tree/tree_v6_generated.go +++ b/string_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag string, nodeIndex uint, matchFunc MatchesFunc, repla return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []string, nodeIndex uint) []string { +func (t *TreeV6) tagsForNode(ret []string, nodeIndex uint, filterFunc FilterFunc) []string { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []string, nodeIndex uint) []string { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) string { func (t *TreeV6) deleteTag(buf []string, nodeIndex uint, matchTag string, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []string, address patricia.IPv6Address, filterFunc FilterFunc) []string { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []string, address patricia.IPv6Address) []string { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []string { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []string, address patricia.IPv6Address) []string { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []string, address patricia.IPv6Address, filterFunc FilterFunc) []string { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []string, address patricia.IPv6Address) []st } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []string, address patricia.IPv6Address) []st // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []string, address patricia.IPv6Addres if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []string, address patricia.IPv6Addres // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []string, address patricia.IPv6Addres if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/string_tree/tree_v6_manual.go b/string_tree/tree_v6_manual.go index ecbc077..cbc2987 100644 --- a/string_tree/tree_v6_manual.go +++ b/string_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]string, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/template/tree_v6_generated.go b/template/tree_v6_generated.go index 1db2292..21dc4b6 100644 --- a/template/tree_v6_generated.go +++ b/template/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag GeneratedType, nodeIndex uint, matchFunc MatchesFunc return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []GeneratedType, nodeIndex uint) []GeneratedType { +func (t *TreeV6) tagsForNode(ret []GeneratedType, nodeIndex uint, filterFunc FilterFunc) []GeneratedType { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []GeneratedType, nodeIndex uint) []GeneratedTyp tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) GeneratedType { func (t *TreeV6) deleteTag(buf []GeneratedType, nodeIndex uint, matchTag GeneratedType, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []GeneratedType, address patricia.IPv6Address, filterFunc FilterFunc) []GeneratedType { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []GeneratedType, address patricia.IPv6Address) []GeneratedType { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []GeneratedType { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []GeneratedType, address patricia.IPv6Address) []GeneratedType { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []GeneratedType, address patricia.IPv6Address, filterFunc FilterFunc) []GeneratedType { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []GeneratedType, address patricia.IPv6Addres } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []GeneratedType, address patricia.IPv6Addres // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []GeneratedType, address patricia.IPv if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []GeneratedType, address patricia.IPv // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []GeneratedType, address patricia.IPv if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v4.go b/uint16_tree/tree_v4.go index 5268478..9a542ed 100644 --- a/uint16_tree/tree_v4.go +++ b/uint16_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag uint16, nodeIndex uint, matchFunc MatchesFunc, repla return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []uint16, nodeIndex uint) []uint16 { +func (t *TreeV4) tagsForNode(ret []uint16, nodeIndex uint, filterFunc FilterFunc) []uint16 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []uint16, nodeIndex uint) []uint16 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint16 { func (t *TreeV4) deleteTag(buf []uint16, nodeIndex uint, matchTag uint16, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []uint16, address patricia.IPv4Address, filterFunc FilterFunc) []uint16 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint16, address patricia.IPv4Address) []uint16 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint16 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint16, address patricia.IPv4Address) []uint16 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint16, address patricia.IPv4Address, filterFunc FilterFunc) []uint16 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint16, address patricia.IPv4Address) []ui } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint16, address patricia.IPv4Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint16, address patricia.IPv4Addres if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint16, address patricia.IPv4Addres // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint16, address patricia.IPv4Addres if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v4_manual.go b/uint16_tree/tree_v4_manual.go index 9796aab..bae1cce 100644 --- a/uint16_tree/tree_v4_manual.go +++ b/uint16_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]uint16, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/uint16_tree/tree_v6_generated.go b/uint16_tree/tree_v6_generated.go index 96087a4..3ae2ab3 100644 --- a/uint16_tree/tree_v6_generated.go +++ b/uint16_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag uint16, nodeIndex uint, matchFunc MatchesFunc, repla return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []uint16, nodeIndex uint) []uint16 { +func (t *TreeV6) tagsForNode(ret []uint16, nodeIndex uint, filterFunc FilterFunc) []uint16 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []uint16, nodeIndex uint) []uint16 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint16 { func (t *TreeV6) deleteTag(buf []uint16, nodeIndex uint, matchTag uint16, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []uint16, address patricia.IPv6Address, filterFunc FilterFunc) []uint16 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint16, address patricia.IPv6Address) []uint16 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint16 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint16, address patricia.IPv6Address) []uint16 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint16, address patricia.IPv6Address, filterFunc FilterFunc) []uint16 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint16, address patricia.IPv6Address) []ui } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint16, address patricia.IPv6Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint16, address patricia.IPv6Addres if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint16, address patricia.IPv6Addres // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint16, address patricia.IPv6Addres if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint16_tree/tree_v6_manual.go b/uint16_tree/tree_v6_manual.go index 3a11bb8..16b5d4b 100644 --- a/uint16_tree/tree_v6_manual.go +++ b/uint16_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]uint16, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/uint32_tree/tree_v4.go b/uint32_tree/tree_v4.go index a576483..7762449 100644 --- a/uint32_tree/tree_v4.go +++ b/uint32_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag uint32, nodeIndex uint, matchFunc MatchesFunc, repla return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []uint32, nodeIndex uint) []uint32 { +func (t *TreeV4) tagsForNode(ret []uint32, nodeIndex uint, filterFunc FilterFunc) []uint32 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []uint32, nodeIndex uint) []uint32 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint32 { func (t *TreeV4) deleteTag(buf []uint32, nodeIndex uint, matchTag uint32, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []uint32, address patricia.IPv4Address, filterFunc FilterFunc) []uint32 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint32, address patricia.IPv4Address) []uint32 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint32 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint32, address patricia.IPv4Address) []uint32 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint32, address patricia.IPv4Address, filterFunc FilterFunc) []uint32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint32, address patricia.IPv4Address) []ui } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint32, address patricia.IPv4Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint32, address patricia.IPv4Addres if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint32, address patricia.IPv4Addres // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint32, address patricia.IPv4Addres if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint32_tree/tree_v4_manual.go b/uint32_tree/tree_v4_manual.go index 02e3146..d67cb9b 100644 --- a/uint32_tree/tree_v4_manual.go +++ b/uint32_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]uint32, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/uint32_tree/tree_v6_generated.go b/uint32_tree/tree_v6_generated.go index 0f8fca9..e0b7a87 100644 --- a/uint32_tree/tree_v6_generated.go +++ b/uint32_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag uint32, nodeIndex uint, matchFunc MatchesFunc, repla return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []uint32, nodeIndex uint) []uint32 { +func (t *TreeV6) tagsForNode(ret []uint32, nodeIndex uint, filterFunc FilterFunc) []uint32 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []uint32, nodeIndex uint) []uint32 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint32 { func (t *TreeV6) deleteTag(buf []uint32, nodeIndex uint, matchTag uint32, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []uint32, address patricia.IPv6Address, filterFunc FilterFunc) []uint32 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint32, address patricia.IPv6Address) []uint32 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint32 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint32, address patricia.IPv6Address) []uint32 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint32, address patricia.IPv6Address, filterFunc FilterFunc) []uint32 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint32, address patricia.IPv6Address) []ui } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint32, address patricia.IPv6Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint32, address patricia.IPv6Addres if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint32, address patricia.IPv6Addres // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint32, address patricia.IPv6Addres if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint32_tree/tree_v6_manual.go b/uint32_tree/tree_v6_manual.go index 339638a..76cb4fe 100644 --- a/uint32_tree/tree_v6_manual.go +++ b/uint32_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]uint32, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/uint64_tree/tree_v4.go b/uint64_tree/tree_v4.go index 80d2836..38bdd22 100644 --- a/uint64_tree/tree_v4.go +++ b/uint64_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag uint64, nodeIndex uint, matchFunc MatchesFunc, repla return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []uint64, nodeIndex uint) []uint64 { +func (t *TreeV4) tagsForNode(ret []uint64, nodeIndex uint, filterFunc FilterFunc) []uint64 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []uint64, nodeIndex uint) []uint64 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint64 { func (t *TreeV4) deleteTag(buf []uint64, nodeIndex uint, matchTag uint64, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []uint64, address patricia.IPv4Address, filterFunc FilterFunc) []uint64 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint64, address patricia.IPv4Address) []uint64 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint64 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint64, address patricia.IPv4Address) []uint64 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint64, address patricia.IPv4Address, filterFunc FilterFunc) []uint64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint64, address patricia.IPv4Address) []ui } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint64, address patricia.IPv4Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint64, address patricia.IPv4Addres if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint64, address patricia.IPv4Addres // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint64, address patricia.IPv4Addres if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint64_tree/tree_v4_manual.go b/uint64_tree/tree_v4_manual.go index 45b1ec0..ff969f2 100644 --- a/uint64_tree/tree_v4_manual.go +++ b/uint64_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]uint64, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/uint64_tree/tree_v6_generated.go b/uint64_tree/tree_v6_generated.go index 67d770b..10917dc 100644 --- a/uint64_tree/tree_v6_generated.go +++ b/uint64_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag uint64, nodeIndex uint, matchFunc MatchesFunc, repla return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []uint64, nodeIndex uint) []uint64 { +func (t *TreeV6) tagsForNode(ret []uint64, nodeIndex uint, filterFunc FilterFunc) []uint64 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []uint64, nodeIndex uint) []uint64 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint64 { func (t *TreeV6) deleteTag(buf []uint64, nodeIndex uint, matchTag uint64, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []uint64, address patricia.IPv6Address, filterFunc FilterFunc) []uint64 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint64, address patricia.IPv6Address) []uint64 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint64 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint64, address patricia.IPv6Address) []uint64 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint64, address patricia.IPv6Address, filterFunc FilterFunc) []uint64 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint64, address patricia.IPv6Address) []ui } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint64, address patricia.IPv6Address) []ui // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint64, address patricia.IPv6Addres if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint64, address patricia.IPv6Addres // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint64, address patricia.IPv6Addres if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint64_tree/tree_v6_manual.go b/uint64_tree/tree_v6_manual.go index d88b6c9..3724d3e 100644 --- a/uint64_tree/tree_v6_manual.go +++ b/uint64_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]uint64, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/uint8_tree/tree_v4.go b/uint8_tree/tree_v4.go index 8feae1f..5f92bbf 100644 --- a/uint8_tree/tree_v4.go +++ b/uint8_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag uint8, nodeIndex uint, matchFunc MatchesFunc, replac return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []uint8, nodeIndex uint) []uint8 { +func (t *TreeV4) tagsForNode(ret []uint8, nodeIndex uint, filterFunc FilterFunc) []uint8 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []uint8, nodeIndex uint) []uint8 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint8 { func (t *TreeV4) deleteTag(buf []uint8, nodeIndex uint, matchTag uint8, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []uint8, address patricia.IPv4Address, filterFunc FilterFunc) []uint8 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint8, address patricia.IPv4Address) []uint8 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint8 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint8, address patricia.IPv4Address) []uint8 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint8, address patricia.IPv4Address, filterFunc FilterFunc) []uint8 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint8, address patricia.IPv4Address) []uin } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint8, address patricia.IPv4Address) []uin // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint8, address patricia.IPv4Address if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint8, address patricia.IPv4Address // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint8, address patricia.IPv4Address if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint8_tree/tree_v4_manual.go b/uint8_tree/tree_v4_manual.go index dfb4e14..0251084 100644 --- a/uint8_tree/tree_v4_manual.go +++ b/uint8_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]uint8, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/uint8_tree/tree_v6_generated.go b/uint8_tree/tree_v6_generated.go index f183c3a..2dda2d5 100644 --- a/uint8_tree/tree_v6_generated.go +++ b/uint8_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag uint8, nodeIndex uint, matchFunc MatchesFunc, replac return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []uint8, nodeIndex uint) []uint8 { +func (t *TreeV6) tagsForNode(ret []uint8, nodeIndex uint, filterFunc FilterFunc) []uint8 { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []uint8, nodeIndex uint) []uint8 { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint8 { func (t *TreeV6) deleteTag(buf []uint8, nodeIndex uint, matchTag uint8, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []uint8, address patricia.IPv6Address, filterFunc FilterFunc) []uint8 { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint8, address patricia.IPv6Address) []uint8 { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint8 { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint8, address patricia.IPv6Address) []uint8 { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint8, address patricia.IPv6Address, filterFunc FilterFunc) []uint8 { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint8, address patricia.IPv6Address) []uin } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint8, address patricia.IPv6Address) []uin // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint8, address patricia.IPv6Address if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint8, address patricia.IPv6Address // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint8, address patricia.IPv6Address if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint8_tree/tree_v6_manual.go b/uint8_tree/tree_v6_manual.go index 5aa79a6..ca42b3c 100644 --- a/uint8_tree/tree_v6_manual.go +++ b/uint8_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]uint8, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/uint_tree/tree_v4.go b/uint_tree/tree_v4.go index a7ae218..826c0e3 100644 --- a/uint_tree/tree_v4.go +++ b/uint_tree/tree_v4.go @@ -79,10 +79,9 @@ func (t *TreeV4) addTag(tag uint, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV4) tagsForNode(ret []uint, nodeIndex uint) []uint { +func (t *TreeV4) tagsForNode(ret []uint, nodeIndex uint, filterFunc FilterFunc) []uint { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV4) tagsForNode(ret []uint, nodeIndex uint) []uint { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV4) firstTagForNode(nodeIndex uint) uint { func (t *TreeV4) deleteTag(buf []uint, nodeIndex uint, matchTag uint, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV4) FindTagsWithFilter(address patricia.IPv4Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV4) FindTagsWithFilterAppend(ret []uint, address patricia.IPv4Address, filterFunc FilterFunc) []uint { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV4) FindTagsAppend(ret []uint, address patricia.IPv4Address) []uint { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV4) FindTags(address patricia.IPv4Address) []uint { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV4) FindTagsAppend(ret []uint, address patricia.IPv4Address) []uint { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV4) FindTagsWithFilterAppend(ret []uint, address patricia.IPv4Address, filterFunc FilterFunc) []uint { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint, address patricia.IPv4Address) []uint } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV4) FindTagsAppend(ret []uint, address patricia.IPv4Address) []uint // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint, address patricia.IPv4Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint, address patricia.IPv4Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV4) FindDeepestTagsAppend(ret []uint, address patricia.IPv4Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint_tree/tree_v4_manual.go b/uint_tree/tree_v4_manual.go index efc8580..aff0bbf 100644 --- a/uint_tree/tree_v4_manual.go +++ b/uint_tree/tree_v4_manual.go @@ -26,6 +26,6 @@ func (t *TreeV4) print() { buf := make([]uint, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefix), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } diff --git a/uint_tree/tree_v6_generated.go b/uint_tree/tree_v6_generated.go index d7efcf4..30426dd 100644 --- a/uint_tree/tree_v6_generated.go +++ b/uint_tree/tree_v6_generated.go @@ -79,10 +79,9 @@ func (t *TreeV6) addTag(tag uint, nodeIndex uint, matchFunc MatchesFunc, replace return ret } -// return the tags at the input node index - appending to the input slice -// - nil if none found +// return the tags at the input node index - appending to the input slice if they pass the optional filter func // - ret is only appended to -func (t *TreeV6) tagsForNode(ret []uint, nodeIndex uint) []uint { +func (t *TreeV6) tagsForNode(ret []uint, nodeIndex uint, filterFunc FilterFunc) []uint { if nodeIndex == 0 { // useful for base cases where we haven't found anything return ret @@ -92,7 +91,10 @@ func (t *TreeV6) tagsForNode(ret []uint, nodeIndex uint) []uint { tagCount := t.nodes[nodeIndex].TagCount key := uint64(nodeIndex) << 32 for i := 0; i < tagCount; i++ { - ret = append(ret, t.tags[key+uint64(i)]) + tag := t.tags[key+uint64(i)] + if filterFunc == nil || filterFunc(tag) { + ret = append(ret, tag) + } } return ret } @@ -118,7 +120,7 @@ func (t *TreeV6) firstTagForNode(nodeIndex uint) uint { func (t *TreeV6) deleteTag(buf []uint, nodeIndex uint, matchTag uint, matchFunc MatchesFunc) (int, int) { // get tags buf = buf[:0] - buf = t.tagsForNode(buf, nodeIndex) + buf = t.tagsForNode(buf, nodeIndex, nil) if len(buf) == 0 { return 0, 0 } @@ -476,26 +478,9 @@ func (t *TreeV6) FindTagsWithFilter(address patricia.IPv6Address, filterFunc Fil return t.FindTagsWithFilterAppend(ret, address, filterFunc) } -// FindTagsWithFilterAppend finds all matching tags that passes the filter function -// - results are appended to the input slice -func (t *TreeV6) FindTagsWithFilterAppend(ret []uint, address patricia.IPv6Address, filterFunc FilterFunc) []uint { - retPos := len(ret) - ret = t.FindTagsAppend(ret, address) - - if len(ret) == retPos || filterFunc == nil { - return ret - } - - // filter in place - length := len(ret) - for i := retPos; i < length; i++ { - val := ret[i] - if filterFunc(val) { - ret[retPos] = val - retPos++ - } - } - return ret[:retPos] +// FindTagsAppend finds all matching tags for given address and appends them to ret +func (t *TreeV6) FindTagsAppend(ret []uint, address patricia.IPv6Address) []uint { + return t.FindTagsWithFilterAppend(ret, address, nil) } // FindTags finds all matching tags for given address @@ -505,13 +490,14 @@ func (t *TreeV6) FindTags(address patricia.IPv6Address) []uint { return t.FindTagsAppend(ret, address) } -// FindTagsAppend finds all matching tags for given address and appends them to ret -func (t *TreeV6) FindTagsAppend(ret []uint, address patricia.IPv6Address) []uint { +// FindTagsWithFilterAppend finds all matching tags that passes the filter function +// - results are appended to the input slice +func (t *TreeV6) FindTagsWithFilterAppend(ret []uint, address patricia.IPv6Address, filterFunc FilterFunc) []uint { var matchCount uint root := &t.nodes[1] if root.TagCount > 0 { - ret = t.tagsForNode(ret, 1) + ret = t.tagsForNode(ret, 1, filterFunc) } if address.Length == 0 { @@ -527,9 +513,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint, address patricia.IPv6Address) []uint } // traverse the tree - count := 0 for { - count++ if nodeIndex == 0 { return ret } @@ -543,7 +527,7 @@ func (t *TreeV6) FindTagsAppend(ret []uint, address patricia.IPv6Address) []uint // matched the full node - get its tags, then chop off the bits we've already matched and continue if node.TagCount > 0 { - ret = t.tagsForNode(ret, nodeIndex) + ret = t.tagsForNode(ret, nodeIndex, filterFunc) } if matchCount == address.Length { @@ -640,7 +624,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint, address patricia.IPv6Address) if address.Length == 0 { // caller just looking for root tags - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } var nodeIndex uint @@ -653,14 +637,14 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint, address patricia.IPv6Address) // traverse the tree for { if nodeIndex == 0 { - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } node := &t.nodes[nodeIndex] matchCount := node.MatchCount(address) if matchCount < node.prefixLength { // didn't match the entire node - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // matched the full node - get its tags, then chop off the bits we've already matched and continue @@ -671,7 +655,7 @@ func (t *TreeV6) FindDeepestTagsAppend(ret []uint, address patricia.IPv6Address) if matchCount == address.Length { // exact match - we're done - return found, t.tagsForNode(ret, retTagIndex) + return found, t.tagsForNode(ret, retTagIndex, nil) } // there's still more address - keep traversing diff --git a/uint_tree/tree_v6_manual.go b/uint_tree/tree_v6_manual.go index d34c30d..1095ec5 100644 --- a/uint_tree/tree_v6_manual.go +++ b/uint_tree/tree_v6_manual.go @@ -26,6 +26,6 @@ func (t *TreeV6) print() { buf := make([]uint, 0) for i := range t.nodes { buf = buf[:0] - fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i))) + fmt.Printf("%d: \tleft: %d, right: %d, prefix: %032b %032b (%d), tags: (%d): %v\n", i, int(t.nodes[i].Left), int(t.nodes[i].Right), int(t.nodes[i].prefixLeft), int(t.nodes[i].prefixRight), int(t.nodes[i].prefixLength), t.nodes[i].TagCount, t.tagsForNode(buf, uint(i), nil)) } } From 60674e0d5e5dee64c4e709a154e8261c5f93cce7 Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Thu, 9 Sep 2021 16:44:46 +0000 Subject: [PATCH 18/19] removed unnecessary allocation in Delete() --- template/tree_v4.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/tree_v4.go b/template/tree_v4.go index f320cd1..077ff8b 100644 --- a/template/tree_v4.go +++ b/template/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag GeneratedType, matchFunc // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal GeneratedType) int { - return t.DeleteWithBuffer(make([]GeneratedType, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed From ec449a92d85386756307d6ff6751337365ad629c Mon Sep 17 00:00:00 2001 From: Blake Caldwell Date: Thu, 9 Sep 2021 16:45:02 +0000 Subject: [PATCH 19/19] codegen --- bool_tree/tree_v4.go | 2 +- bool_tree/tree_v6_generated.go | 2 +- byte_tree/tree_v4.go | 2 +- byte_tree/tree_v6_generated.go | 2 +- complex128_tree/tree_v4.go | 2 +- complex128_tree/tree_v6_generated.go | 2 +- complex64_tree/tree_v4.go | 2 +- complex64_tree/tree_v6_generated.go | 2 +- float32_tree/tree_v4.go | 2 +- float32_tree/tree_v6_generated.go | 2 +- float64_tree/tree_v4.go | 2 +- float64_tree/tree_v6_generated.go | 2 +- int16_tree/tree_v4.go | 2 +- int16_tree/tree_v6_generated.go | 2 +- int32_tree/tree_v4.go | 2 +- int32_tree/tree_v6_generated.go | 2 +- int64_tree/tree_v4.go | 2 +- int64_tree/tree_v6_generated.go | 2 +- int8_tree/tree_v4.go | 2 +- int8_tree/tree_v6_generated.go | 2 +- int_tree/tree_v4.go | 2 +- int_tree/tree_v6_generated.go | 2 +- rune_tree/tree_v4.go | 2 +- rune_tree/tree_v6_generated.go | 2 +- string_tree/tree_v4.go | 2 +- string_tree/tree_v6_generated.go | 2 +- template/tree_v6_generated.go | 2 +- uint16_tree/tree_v4.go | 2 +- uint16_tree/tree_v6_generated.go | 2 +- uint32_tree/tree_v4.go | 2 +- uint32_tree/tree_v6_generated.go | 2 +- uint64_tree/tree_v4.go | 2 +- uint64_tree/tree_v6_generated.go | 2 +- uint8_tree/tree_v4.go | 2 +- uint8_tree/tree_v6_generated.go | 2 +- uint_tree/tree_v4.go | 2 +- uint_tree/tree_v6_generated.go | 2 +- 37 files changed, 37 insertions(+), 37 deletions(-) diff --git a/bool_tree/tree_v4.go b/bool_tree/tree_v4.go index 5234fe2..1e43254 100644 --- a/bool_tree/tree_v4.go +++ b/bool_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag bool, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal bool) int { - return t.DeleteWithBuffer(make([]bool, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/bool_tree/tree_v6_generated.go b/bool_tree/tree_v6_generated.go index f804306..800485e 100644 --- a/bool_tree/tree_v6_generated.go +++ b/bool_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag bool, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal bool) int { - return t.DeleteWithBuffer(make([]bool, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/byte_tree/tree_v4.go b/byte_tree/tree_v4.go index 23f29cb..7e7e712 100644 --- a/byte_tree/tree_v4.go +++ b/byte_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag byte, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal byte) int { - return t.DeleteWithBuffer(make([]byte, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/byte_tree/tree_v6_generated.go b/byte_tree/tree_v6_generated.go index 900dcf6..29d49af 100644 --- a/byte_tree/tree_v6_generated.go +++ b/byte_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag byte, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal byte) int { - return t.DeleteWithBuffer(make([]byte, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/complex128_tree/tree_v4.go b/complex128_tree/tree_v4.go index 910e3a0..10f1650 100644 --- a/complex128_tree/tree_v4.go +++ b/complex128_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex128, matchFunc Mat // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex128) int { - return t.DeleteWithBuffer(make([]complex128, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/complex128_tree/tree_v6_generated.go b/complex128_tree/tree_v6_generated.go index 8d01bb0..df1293f 100644 --- a/complex128_tree/tree_v6_generated.go +++ b/complex128_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex128, matchFunc Mat // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex128) int { - return t.DeleteWithBuffer(make([]complex128, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/complex64_tree/tree_v4.go b/complex64_tree/tree_v4.go index 1851a92..92a3a31 100644 --- a/complex64_tree/tree_v4.go +++ b/complex64_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag complex64, matchFunc Matc // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal complex64) int { - return t.DeleteWithBuffer(make([]complex64, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/complex64_tree/tree_v6_generated.go b/complex64_tree/tree_v6_generated.go index 0859750..bda546b 100644 --- a/complex64_tree/tree_v6_generated.go +++ b/complex64_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag complex64, matchFunc Matc // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal complex64) int { - return t.DeleteWithBuffer(make([]complex64, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/float32_tree/tree_v4.go b/float32_tree/tree_v4.go index 74ed9e3..629b8e6 100644 --- a/float32_tree/tree_v4.go +++ b/float32_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float32, matchFunc Matche // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float32) int { - return t.DeleteWithBuffer(make([]float32, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/float32_tree/tree_v6_generated.go b/float32_tree/tree_v6_generated.go index 3f3bc9d..81232ee 100644 --- a/float32_tree/tree_v6_generated.go +++ b/float32_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float32, matchFunc Matche // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float32) int { - return t.DeleteWithBuffer(make([]float32, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/float64_tree/tree_v4.go b/float64_tree/tree_v4.go index c781c09..9516fab 100644 --- a/float64_tree/tree_v4.go +++ b/float64_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag float64, matchFunc Matche // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal float64) int { - return t.DeleteWithBuffer(make([]float64, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/float64_tree/tree_v6_generated.go b/float64_tree/tree_v6_generated.go index 27cb247..8d05d61 100644 --- a/float64_tree/tree_v6_generated.go +++ b/float64_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag float64, matchFunc Matche // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal float64) int { - return t.DeleteWithBuffer(make([]float64, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int16_tree/tree_v4.go b/int16_tree/tree_v4.go index 4b09d75..38b5024 100644 --- a/int16_tree/tree_v4.go +++ b/int16_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int16, matchFunc MatchesF // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int16) int { - return t.DeleteWithBuffer(make([]int16, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int16_tree/tree_v6_generated.go b/int16_tree/tree_v6_generated.go index 3be110d..6ee4829 100644 --- a/int16_tree/tree_v6_generated.go +++ b/int16_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int16, matchFunc MatchesF // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int16) int { - return t.DeleteWithBuffer(make([]int16, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int32_tree/tree_v4.go b/int32_tree/tree_v4.go index 183be14..72c957c 100644 --- a/int32_tree/tree_v4.go +++ b/int32_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int32, matchFunc MatchesF // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int32) int { - return t.DeleteWithBuffer(make([]int32, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int32_tree/tree_v6_generated.go b/int32_tree/tree_v6_generated.go index 6c181fc..c657206 100644 --- a/int32_tree/tree_v6_generated.go +++ b/int32_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int32, matchFunc MatchesF // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int32) int { - return t.DeleteWithBuffer(make([]int32, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int64_tree/tree_v4.go b/int64_tree/tree_v4.go index 8ae6990..055b3b3 100644 --- a/int64_tree/tree_v4.go +++ b/int64_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int64, matchFunc MatchesF // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int64) int { - return t.DeleteWithBuffer(make([]int64, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int64_tree/tree_v6_generated.go b/int64_tree/tree_v6_generated.go index 4ad5f17..7c75a91 100644 --- a/int64_tree/tree_v6_generated.go +++ b/int64_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int64, matchFunc MatchesF // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int64) int { - return t.DeleteWithBuffer(make([]int64, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int8_tree/tree_v4.go b/int8_tree/tree_v4.go index 92d3289..36eb552 100644 --- a/int8_tree/tree_v4.go +++ b/int8_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int8, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int8) int { - return t.DeleteWithBuffer(make([]int8, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int8_tree/tree_v6_generated.go b/int8_tree/tree_v6_generated.go index 10f7f15..dda7d67 100644 --- a/int8_tree/tree_v6_generated.go +++ b/int8_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int8, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int8) int { - return t.DeleteWithBuffer(make([]int8, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int_tree/tree_v4.go b/int_tree/tree_v4.go index f93cdd1..4d07772 100644 --- a/int_tree/tree_v4.go +++ b/int_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag int, matchFunc MatchesFun // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal int) int { - return t.DeleteWithBuffer(make([]int, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/int_tree/tree_v6_generated.go b/int_tree/tree_v6_generated.go index f4ce296..2a74df6 100644 --- a/int_tree/tree_v6_generated.go +++ b/int_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag int, matchFunc MatchesFun // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal int) int { - return t.DeleteWithBuffer(make([]int, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/rune_tree/tree_v4.go b/rune_tree/tree_v4.go index 9a8788f..ca5e837 100644 --- a/rune_tree/tree_v4.go +++ b/rune_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag rune, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal rune) int { - return t.DeleteWithBuffer(make([]rune, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/rune_tree/tree_v6_generated.go b/rune_tree/tree_v6_generated.go index 87414a7..fd6b9da 100644 --- a/rune_tree/tree_v6_generated.go +++ b/rune_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag rune, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal rune) int { - return t.DeleteWithBuffer(make([]rune, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/string_tree/tree_v4.go b/string_tree/tree_v4.go index ad8d929..b47a65e 100644 --- a/string_tree/tree_v4.go +++ b/string_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag string, matchFunc Matches // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal string) int { - return t.DeleteWithBuffer(make([]string, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/string_tree/tree_v6_generated.go b/string_tree/tree_v6_generated.go index b77a3b4..6434c67 100644 --- a/string_tree/tree_v6_generated.go +++ b/string_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag string, matchFunc Matches // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal string) int { - return t.DeleteWithBuffer(make([]string, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/template/tree_v6_generated.go b/template/tree_v6_generated.go index 21dc4b6..afd3ca8 100644 --- a/template/tree_v6_generated.go +++ b/template/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag GeneratedType, matchFunc // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal GeneratedType) int { - return t.DeleteWithBuffer(make([]GeneratedType, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint16_tree/tree_v4.go b/uint16_tree/tree_v4.go index 9a542ed..8ef258d 100644 --- a/uint16_tree/tree_v4.go +++ b/uint16_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint16, matchFunc Matches // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint16) int { - return t.DeleteWithBuffer(make([]uint16, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint16_tree/tree_v6_generated.go b/uint16_tree/tree_v6_generated.go index 3ae2ab3..c1c2757 100644 --- a/uint16_tree/tree_v6_generated.go +++ b/uint16_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint16, matchFunc Matches // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint16) int { - return t.DeleteWithBuffer(make([]uint16, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint32_tree/tree_v4.go b/uint32_tree/tree_v4.go index 7762449..b39df36 100644 --- a/uint32_tree/tree_v4.go +++ b/uint32_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint32, matchFunc Matches // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint32) int { - return t.DeleteWithBuffer(make([]uint32, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint32_tree/tree_v6_generated.go b/uint32_tree/tree_v6_generated.go index e0b7a87..7bb8a30 100644 --- a/uint32_tree/tree_v6_generated.go +++ b/uint32_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint32, matchFunc Matches // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint32) int { - return t.DeleteWithBuffer(make([]uint32, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint64_tree/tree_v4.go b/uint64_tree/tree_v4.go index 38bdd22..eaa74c3 100644 --- a/uint64_tree/tree_v4.go +++ b/uint64_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint64, matchFunc Matches // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint64) int { - return t.DeleteWithBuffer(make([]uint64, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint64_tree/tree_v6_generated.go b/uint64_tree/tree_v6_generated.go index 10917dc..ad7e9da 100644 --- a/uint64_tree/tree_v6_generated.go +++ b/uint64_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint64, matchFunc Matches // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint64) int { - return t.DeleteWithBuffer(make([]uint64, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint8_tree/tree_v4.go b/uint8_tree/tree_v4.go index 5f92bbf..9399d43 100644 --- a/uint8_tree/tree_v4.go +++ b/uint8_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint8, matchFunc MatchesF // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint8) int { - return t.DeleteWithBuffer(make([]uint8, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint8_tree/tree_v6_generated.go b/uint8_tree/tree_v6_generated.go index 2dda2d5..87a2fc7 100644 --- a/uint8_tree/tree_v6_generated.go +++ b/uint8_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint8, matchFunc MatchesF // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint8) int { - return t.DeleteWithBuffer(make([]uint8, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint_tree/tree_v4.go b/uint_tree/tree_v4.go index 826c0e3..d2fa247 100644 --- a/uint_tree/tree_v4.go +++ b/uint_tree/tree_v4.go @@ -323,7 +323,7 @@ func (t *TreeV4) add(address patricia.IPv4Address, tag uint, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV4) Delete(address patricia.IPv4Address, matchFunc MatchesFunc, matchVal uint) int { - return t.DeleteWithBuffer(make([]uint, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed diff --git a/uint_tree/tree_v6_generated.go b/uint_tree/tree_v6_generated.go index 30426dd..900f880 100644 --- a/uint_tree/tree_v6_generated.go +++ b/uint_tree/tree_v6_generated.go @@ -323,7 +323,7 @@ func (t *TreeV6) add(address patricia.IPv6Address, tag uint, matchFunc MatchesFu // Delete a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed // - use DeleteWithBuffer if you can reuse slices, to cut down on allocations func (t *TreeV6) Delete(address patricia.IPv6Address, matchFunc MatchesFunc, matchVal uint) int { - return t.DeleteWithBuffer(make([]uint, 0), address, matchFunc, matchVal) + return t.DeleteWithBuffer(nil, address, matchFunc, matchVal) } // DeleteWithBuffer a tag from the tree if it matches matchVal, as determined by matchFunc. Returns how many tags are removed