Copyright 2014 Google Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

package profile
Implements methods to filter samples from profiles.

import 
FilterSamplesByName filters the samples in a profile and only keeps samples where at least one frame matches focus but none match ignore. Returns true is the corresponding regexp matched at least one sample.
func ( *Profile) (, , ,  *regexp.Regexp) (, , ,  bool) {
	 := make(map[uint64]bool)
	 := make(map[uint64]bool)
	for ,  := range .Location {
		if  != nil && .matchesName() {
			 = true
			[.ID] = false
		} else if  == nil || .matchesName() {
			 = true
			[.ID] = true
		}

		if  != nil && .matchesName() {
			 = true
			.Line = .unmatchedLines()
			if len(.Line) == 0 {
				[.ID] = true
			}
		}
		if  != nil {
			.Line = .matchedLines()
			if len(.Line) == 0 {
				[.ID] = true
			} else {
				 = true
			}
		}
	}

	 := make([]*Sample, 0, len(.Sample))
	for ,  := range .Sample {
		if focusedAndNotIgnored(.Location, ) {
			if len() > 0 {
				var  []*Location
				for ,  := range .Location {
					if ![.ID] {
						 = append(, )
					}
				}
Remove sample with no locations (by not adding it to s).
					continue
				}
				.Location = 
			}
			 = append(, )
		}
	}
	.Sample = 

	return
}
ShowFrom drops all stack frames above the highest matching frame and returns whether a match was found. If showFrom is nil it returns false and does not modify the profile. Example: consider a sample with frames [A, B, C, B], where A is the root. ShowFrom(nil) returns false and has frames [A, B, C, B]. ShowFrom(A) returns true and has frames [A, B, C, B]. ShowFrom(B) returns true and has frames [B, C, B]. ShowFrom(C) returns true and has frames [C, B]. ShowFrom(D) returns false and drops the sample because no frames remain.
func ( *Profile) ( *regexp.Regexp) ( bool) {
	if  == nil {
		return false
showFromLocs stores location IDs that matched ShowFrom.
Apply to locations.
	for ,  := range .Location {
		if filterShowFromLocation(, ) {
			[.ID] = true
			 = true
		}
For all samples, strip locations after the highest matching one.
	 := make([]*Sample, 0, len(.Sample))
	for ,  := range .Sample {
		for  := len(.Location) - 1;  >= 0; -- {
			if [.Location[].ID] {
				.Location = .Location[:+1]
				 = append(, )
				break
			}
		}
	}
	.Sample = 
	return 
}
filterShowFromLocation tests a showFrom regex against a location, removes lines after the last match and returns whether a match was found. If the mapping is matched, then all lines are kept.
func ( *Location,  *regexp.Regexp) bool {
	if  := .Mapping;  != nil && .MatchString(.File) {
		return true
	}
	if  := .lastMatchedLineIndex();  >= 0 {
		.Line = .Line[:+1]
		return true
	}
	return false
}
lastMatchedLineIndex returns the index of the last line that matches a regex, or -1 if no match is found.
func ( *Location) ( *regexp.Regexp) int {
	for  := len(.Line) - 1;  >= 0; -- {
		if  := .Line[].Function;  != nil {
			if .MatchString(.Name) || .MatchString(.Filename) {
				return 
			}
		}
	}
	return -1
}
FilterTagsByName filters the tags in a profile and only keeps tags that match show and not hide.
func ( *Profile) (,  *regexp.Regexp) (,  bool) {
	 := func( string) bool {
		 :=  == nil || .MatchString()
		 :=  != nil && .MatchString()

		if  {
			 = true
		}
		if  {
			 = true
		}
		return ! || 
	}
	for ,  := range .Sample {
		for  := range .Label {
			if () {
				delete(.Label, )
			}
		}
		for  := range .NumLabel {
			if () {
				delete(.NumLabel, )
			}
		}
	}
	return
}
matchesName returns whether the location matches the regular expression. It checks any available function names, file names, and mapping object filename.
func ( *Location) ( *regexp.Regexp) bool {
	for ,  := range .Line {
		if  := .Function;  != nil {
			if .MatchString(.Name) || .MatchString(.Filename) {
				return true
			}
		}
	}
	if  := .Mapping;  != nil && .MatchString(.File) {
		return true
	}
	return false
}
unmatchedLines returns the lines in the location that do not match the regular expression.
func ( *Location) ( *regexp.Regexp) []Line {
	if  := .Mapping;  != nil && .MatchString(.File) {
		return nil
	}
	var  []Line
	for ,  := range .Line {
		if  := .Function;  != nil {
			if .MatchString(.Name) || .MatchString(.Filename) {
				continue
			}
		}
		 = append(, )
	}
	return 
}
matchedLines returns the lines in the location that match the regular expression.
func ( *Location) ( *regexp.Regexp) []Line {
	if  := .Mapping;  != nil && .MatchString(.File) {
		return .Line
	}
	var  []Line
	for ,  := range .Line {
		if  := .Function;  != nil {
			if !.MatchString(.Name) && !.MatchString(.Filename) {
				continue
			}
		}
		 = append(, )
	}
	return 
}
focusedAndNotIgnored looks up a slice of ids against a map of focused/ignored locations. The map only contains locations that are explicitly focused or ignored. Returns whether there is at least one focused location but no ignored locations.
func ( []*Location,  map[uint64]bool) bool {
	var  bool
	for ,  := range  {
		if ,  := [.ID];  {
Found focused location. Must keep searching in case there is an ignored one as well.
				 = true
Found ignored location. Can return false right away.
				return false
			}
		}
	}
	return 
}
TagMatch selects tags for filtering
type TagMatch func(s *Sample) bool
FilterSamplesByTag removes all samples from the profile, except those that match focus and do not match the ignore regular expression.
func ( *Profile) (,  TagMatch) (,  bool) {
	 := make([]*Sample, 0, len(.Sample))
	for ,  := range .Sample {
		,  := true, false
		if  != nil {
			 = ()
		}
		if  != nil {
			 = ()
		}
		 =  || 
		 =  || 
		if  && ! {
			 = append(, )
		}
	}
	.Sample = 
	return