// 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

import (
	
	
	
)

func ( *Profile) () []decoder {
	return profileDecoder
}

// preEncode populates the unexported fields to be used by encode
// (with suffix X) from the corresponding exported fields. The
// exported fields are cleared up to facilitate testing.
func ( *Profile) () {
	 := make(map[string]int)
	addString(, "")

	for ,  := range .SampleType {
		.typeX = addString(, .Type)
		.unitX = addString(, .Unit)
	}

	for ,  := range .Sample {
		.labelX = nil
		var  []string
		for  := range .Label {
			 = append(, )
		}
		sort.Strings()
		for ,  := range  {
			 := .Label[]
			for ,  := range  {
				.labelX = append(.labelX,
					label{
						keyX: addString(, ),
						strX: addString(, ),
					},
				)
			}
		}
		var  []string
		for  := range .NumLabel {
			 = append(, )
		}
		sort.Strings()
		for ,  := range  {
			 := addString(, )
			 := .NumLabel[]
			 := .NumUnit[]
			for ,  := range  {
				var  int64
				if len() != 0 {
					 = addString(, [])
				}
				.labelX = append(.labelX,
					label{
						keyX:  ,
						numX:  ,
						unitX: ,
					},
				)
			}
		}
		.locationIDX = make([]uint64, len(.Location))
		for ,  := range .Location {
			.locationIDX[] = .ID
		}
	}

	for ,  := range .Mapping {
		.fileX = addString(, .File)
		.buildIDX = addString(, .BuildID)
	}

	for ,  := range .Location {
		for ,  := range .Line {
			if .Function != nil {
				.Line[].functionIDX = .Function.ID
			} else {
				.Line[].functionIDX = 0
			}
		}
		if .Mapping != nil {
			.mappingIDX = .Mapping.ID
		} else {
			.mappingIDX = 0
		}
	}
	for ,  := range .Function {
		.nameX = addString(, .Name)
		.systemNameX = addString(, .SystemName)
		.filenameX = addString(, .Filename)
	}

	.dropFramesX = addString(, .DropFrames)
	.keepFramesX = addString(, .KeepFrames)

	if  := .PeriodType;  != nil {
		.typeX = addString(, .Type)
		.unitX = addString(, .Unit)
	}

	.commentX = nil
	for ,  := range .Comments {
		.commentX = append(.commentX, addString(, ))
	}

	.defaultSampleTypeX = addString(, .DefaultSampleType)
	.docURLX = addString(, .DocURL)

	.stringTable = make([]string, len())
	for ,  := range  {
		.stringTable[] = 
	}
}

func ( *Profile) ( *buffer) {
	for ,  := range .SampleType {
		encodeMessage(, 1, )
	}
	for ,  := range .Sample {
		encodeMessage(, 2, )
	}
	for ,  := range .Mapping {
		encodeMessage(, 3, )
	}
	for ,  := range .Location {
		encodeMessage(, 4, )
	}
	for ,  := range .Function {
		encodeMessage(, 5, )
	}
	encodeStrings(, 6, .stringTable)
	encodeInt64Opt(, 7, .dropFramesX)
	encodeInt64Opt(, 8, .keepFramesX)
	encodeInt64Opt(, 9, .TimeNanos)
	encodeInt64Opt(, 10, .DurationNanos)
	if  := .PeriodType;  != nil && (.typeX != 0 || .unitX != 0) {
		encodeMessage(, 11, .PeriodType)
	}
	encodeInt64Opt(, 12, .Period)
	encodeInt64s(, 13, .commentX)
	encodeInt64(, 14, .defaultSampleTypeX)
	encodeInt64Opt(, 15, .docURLX)
}

var profileDecoder = []decoder{
	nil, // 0
	// repeated ValueType sample_type = 1
	func( *buffer,  message) error {
		 := new(ValueType)
		 := .(*Profile)
		.SampleType = append(.SampleType, )
		return decodeMessage(, )
	},
	// repeated Sample sample = 2
	func( *buffer,  message) error {
		 := new(Sample)
		 := .(*Profile)
		.Sample = append(.Sample, )
		return decodeMessage(, )
	},
	// repeated Mapping mapping = 3
	func( *buffer,  message) error {
		 := new(Mapping)
		 := .(*Profile)
		.Mapping = append(.Mapping, )
		return decodeMessage(, )
	},
	// repeated Location location = 4
	func( *buffer,  message) error {
		 := new(Location)
		.Line = .tmpLines[:0] // Use shared space temporarily
		 := .(*Profile)
		.Location = append(.Location, )
		 := decodeMessage(, )
		.tmpLines = .Line[:0]
		// Copy to shrink size and detach from shared space.
		.Line = append([]Line(nil), .Line...)
		return 
	},
	// repeated Function function = 5
	func( *buffer,  message) error {
		 := new(Function)
		 := .(*Profile)
		.Function = append(.Function, )
		return decodeMessage(, )
	},
	// repeated string string_table = 6
	func( *buffer,  message) error {
		 := decodeStrings(, &.(*Profile).stringTable)
		if  != nil {
			return 
		}
		if .(*Profile).stringTable[0] != "" {
			return errors.New("string_table[0] must be ''")
		}
		return nil
	},
	// int64 drop_frames = 7
	func( *buffer,  message) error { return decodeInt64(, &.(*Profile).dropFramesX) },
	// int64 keep_frames = 8
	func( *buffer,  message) error { return decodeInt64(, &.(*Profile).keepFramesX) },
	// int64 time_nanos = 9
	func( *buffer,  message) error {
		if .(*Profile).TimeNanos != 0 {
			return errConcatProfile
		}
		return decodeInt64(, &.(*Profile).TimeNanos)
	},
	// int64 duration_nanos = 10
	func( *buffer,  message) error { return decodeInt64(, &.(*Profile).DurationNanos) },
	// ValueType period_type = 11
	func( *buffer,  message) error {
		 := new(ValueType)
		 := .(*Profile)
		.PeriodType = 
		return decodeMessage(, )
	},
	// int64 period = 12
	func( *buffer,  message) error { return decodeInt64(, &.(*Profile).Period) },
	// repeated int64 comment = 13
	func( *buffer,  message) error { return decodeInt64s(, &.(*Profile).commentX) },
	// int64 defaultSampleType = 14
	func( *buffer,  message) error { return decodeInt64(, &.(*Profile).defaultSampleTypeX) },
	// string doc_link = 15;
	func( *buffer,  message) error { return decodeInt64(, &.(*Profile).docURLX) },
}

// postDecode takes the unexported fields populated by decode (with
// suffix X) and populates the corresponding exported fields.
// The unexported fields are cleared up to facilitate testing.
func ( *Profile) () error {
	var  error
	 := make(map[uint64]*Mapping, len(.Mapping))
	 := make([]*Mapping, len(.Mapping)+1)
	for ,  := range .Mapping {
		.File,  = getString(.stringTable, &.fileX, )
		.BuildID,  = getString(.stringTable, &.buildIDX, )
		if .ID < uint64(len()) {
			[.ID] = 
		} else {
			[.ID] = 
		}

		// If this a main linux kernel mapping with a relocation symbol suffix
		// ("[kernel.kallsyms]_text"), extract said suffix.
		// It is fairly hacky to handle at this level, but the alternatives appear even worse.
		const  = "[kernel.kallsyms]"
		if strings.HasPrefix(.File, ) {
			.KernelRelocationSymbol = .File[len():]
		}
	}

	 := make(map[uint64]*Function, len(.Function))
	 := make([]*Function, len(.Function)+1)
	for ,  := range .Function {
		.Name,  = getString(.stringTable, &.nameX, )
		.SystemName,  = getString(.stringTable, &.systemNameX, )
		.Filename,  = getString(.stringTable, &.filenameX, )
		if .ID < uint64(len()) {
			[.ID] = 
		} else {
			[.ID] = 
		}
	}

	 := make(map[uint64]*Location, len(.Location))
	 := make([]*Location, len(.Location)+1)
	for ,  := range .Location {
		if  := .mappingIDX;  < uint64(len()) {
			.Mapping = []
		} else {
			.Mapping = []
		}
		.mappingIDX = 0
		for ,  := range .Line {
			if  := .functionIDX;  != 0 {
				.Line[].functionIDX = 0
				if  < uint64(len()) {
					.Line[].Function = []
				} else {
					.Line[].Function = []
				}
			}
		}
		if .ID < uint64(len()) {
			[.ID] = 
		} else {
			[.ID] = 
		}
	}

	for ,  := range .SampleType {
		.Type,  = getString(.stringTable, &.typeX, )
		.Unit,  = getString(.stringTable, &.unitX, )
	}

	// Pre-allocate space for all locations.
	 := 0
	for ,  := range .Sample {
		 += len(.locationIDX)
	}
	 := make([]*Location, )

	for ,  := range .Sample {
		if len(.labelX) > 0 {
			 := make(map[string][]string, len(.labelX))
			 := make(map[string][]int64, len(.labelX))
			 := make(map[string][]string, len(.labelX))
			for ,  := range .labelX {
				var ,  string
				,  = getString(.stringTable, &.keyX, )
				if .strX != 0 {
					,  = getString(.stringTable, &.strX, )
					[] = append([], )
				} else if .numX != 0 || .unitX != 0 {
					 := []
					 := []
					if .unitX != 0 {
						var  string
						,  = getString(.stringTable, &.unitX, )
						 = padStringArray(, len())
						[] = append(, )
					}
					[] = append([], .numX)
				}
			}
			if len() > 0 {
				.Label = 
			}
			if len() > 0 {
				.NumLabel = 
				for ,  := range  {
					if len() > 0 {
						[] = padStringArray(, len([]))
					}
				}
				.NumUnit = 
			}
		}

		.Location = [:len(.locationIDX)]
		 = [len(.locationIDX):]
		for ,  := range .locationIDX {
			if  < uint64(len()) {
				.Location[] = []
			} else {
				.Location[] = []
			}
		}
		.locationIDX = nil
	}

	.DropFrames,  = getString(.stringTable, &.dropFramesX, )
	.KeepFrames,  = getString(.stringTable, &.keepFramesX, )

	if  := .PeriodType;  == nil {
		.PeriodType = &ValueType{}
	}

	if  := .PeriodType;  != nil {
		.Type,  = getString(.stringTable, &.typeX, )
		.Unit,  = getString(.stringTable, &.unitX, )
	}

	for ,  := range .commentX {
		var  string
		,  = getString(.stringTable, &, )
		.Comments = append(.Comments, )
	}

	.commentX = nil
	.DefaultSampleType,  = getString(.stringTable, &.defaultSampleTypeX, )
	.DocURL,  = getString(.stringTable, &.docURLX, )
	.stringTable = nil
	return 
}

// padStringArray pads arr with enough empty strings to make arr
// length l when arr's length is less than l.
func padStringArray( []string,  int) []string {
	if  <= len() {
		return 
	}
	return append(, make([]string, -len())...)
}

func ( *ValueType) () []decoder {
	return valueTypeDecoder
}

func ( *ValueType) ( *buffer) {
	encodeInt64Opt(, 1, .typeX)
	encodeInt64Opt(, 2, .unitX)
}

var valueTypeDecoder = []decoder{
	nil, // 0
	// optional int64 type = 1
	func( *buffer,  message) error { return decodeInt64(, &.(*ValueType).typeX) },
	// optional int64 unit = 2
	func( *buffer,  message) error { return decodeInt64(, &.(*ValueType).unitX) },
}

func ( *Sample) () []decoder {
	return sampleDecoder
}

func ( *Sample) ( *buffer) {
	encodeUint64s(, 1, .locationIDX)
	encodeInt64s(, 2, .Value)
	for ,  := range .labelX {
		encodeMessage(, 3, )
	}
}

var sampleDecoder = []decoder{
	nil, // 0
	// repeated uint64 location = 1
	func( *buffer,  message) error { return decodeUint64s(, &.(*Sample).locationIDX) },
	// repeated int64 value = 2
	func( *buffer,  message) error { return decodeInt64s(, &.(*Sample).Value) },
	// repeated Label label = 3
	func( *buffer,  message) error {
		 := .(*Sample)
		 := len(.labelX)
		.labelX = append(.labelX, label{})
		return decodeMessage(, &.labelX[])
	},
}

func ( label) () []decoder {
	return labelDecoder
}

func ( label) ( *buffer) {
	encodeInt64Opt(, 1, .keyX)
	encodeInt64Opt(, 2, .strX)
	encodeInt64Opt(, 3, .numX)
	encodeInt64Opt(, 4, .unitX)
}

var labelDecoder = []decoder{
	nil, // 0
	// optional int64 key = 1
	func( *buffer,  message) error { return decodeInt64(, &.(*label).keyX) },
	// optional int64 str = 2
	func( *buffer,  message) error { return decodeInt64(, &.(*label).strX) },
	// optional int64 num = 3
	func( *buffer,  message) error { return decodeInt64(, &.(*label).numX) },
	// optional int64 num = 4
	func( *buffer,  message) error { return decodeInt64(, &.(*label).unitX) },
}

func ( *Mapping) () []decoder {
	return mappingDecoder
}

func ( *Mapping) ( *buffer) {
	encodeUint64Opt(, 1, .ID)
	encodeUint64Opt(, 2, .Start)
	encodeUint64Opt(, 3, .Limit)
	encodeUint64Opt(, 4, .Offset)
	encodeInt64Opt(, 5, .fileX)
	encodeInt64Opt(, 6, .buildIDX)
	encodeBoolOpt(, 7, .HasFunctions)
	encodeBoolOpt(, 8, .HasFilenames)
	encodeBoolOpt(, 9, .HasLineNumbers)
	encodeBoolOpt(, 10, .HasInlineFrames)
}

var mappingDecoder = []decoder{
	nil, // 0
	func( *buffer,  message) error { return decodeUint64(, &.(*Mapping).ID) },            // optional uint64 id = 1
	func( *buffer,  message) error { return decodeUint64(, &.(*Mapping).Start) },         // optional uint64 memory_offset = 2
	func( *buffer,  message) error { return decodeUint64(, &.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
	func( *buffer,  message) error { return decodeUint64(, &.(*Mapping).Offset) },        // optional uint64 file_offset = 4
	func( *buffer,  message) error { return decodeInt64(, &.(*Mapping).fileX) },          // optional int64 filename = 5
	func( *buffer,  message) error { return decodeInt64(, &.(*Mapping).buildIDX) },       // optional int64 build_id = 6
	func( *buffer,  message) error { return decodeBool(, &.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
	func( *buffer,  message) error { return decodeBool(, &.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
	func( *buffer,  message) error { return decodeBool(, &.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
	func( *buffer,  message) error { return decodeBool(, &.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
}

func ( *Location) () []decoder {
	return locationDecoder
}

func ( *Location) ( *buffer) {
	encodeUint64Opt(, 1, .ID)
	encodeUint64Opt(, 2, .mappingIDX)
	encodeUint64Opt(, 3, .Address)
	for  := range .Line {
		encodeMessage(, 4, &.Line[])
	}
	encodeBoolOpt(, 5, .IsFolded)
}

var locationDecoder = []decoder{
	nil, // 0
	func( *buffer,  message) error { return decodeUint64(, &.(*Location).ID) },         // optional uint64 id = 1;
	func( *buffer,  message) error { return decodeUint64(, &.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
	func( *buffer,  message) error { return decodeUint64(, &.(*Location).Address) },    // optional uint64 address = 3;
	func( *buffer,  message) error { // repeated Line line = 4
		 := .(*Location)
		 := len(.Line)
		.Line = append(.Line, Line{})
		return decodeMessage(, &.Line[])
	},
	func( *buffer,  message) error { return decodeBool(, &.(*Location).IsFolded) }, // optional bool is_folded = 5;
}

func ( *Line) () []decoder {
	return lineDecoder
}

func ( *Line) ( *buffer) {
	encodeUint64Opt(, 1, .functionIDX)
	encodeInt64Opt(, 2, .Line)
	encodeInt64Opt(, 3, .Column)
}

var lineDecoder = []decoder{
	nil, // 0
	// optional uint64 function_id = 1
	func( *buffer,  message) error { return decodeUint64(, &.(*Line).functionIDX) },
	// optional int64 line = 2
	func( *buffer,  message) error { return decodeInt64(, &.(*Line).Line) },
	// optional int64 column = 3
	func( *buffer,  message) error { return decodeInt64(, &.(*Line).Column) },
}

func ( *Function) () []decoder {
	return functionDecoder
}

func ( *Function) ( *buffer) {
	encodeUint64Opt(, 1, .ID)
	encodeInt64Opt(, 2, .nameX)
	encodeInt64Opt(, 3, .systemNameX)
	encodeInt64Opt(, 4, .filenameX)
	encodeInt64Opt(, 5, .StartLine)
}

var functionDecoder = []decoder{
	nil, // 0
	// optional uint64 id = 1
	func( *buffer,  message) error { return decodeUint64(, &.(*Function).ID) },
	// optional int64 function_name = 2
	func( *buffer,  message) error { return decodeInt64(, &.(*Function).nameX) },
	// optional int64 function_system_name = 3
	func( *buffer,  message) error { return decodeInt64(, &.(*Function).systemNameX) },
	// repeated int64 filename = 4
	func( *buffer,  message) error { return decodeInt64(, &.(*Function).filenameX) },
	// optional int64 start_line = 5
	func( *buffer,  message) error { return decodeInt64(, &.(*Function).StartLine) },
}

func addString( map[string]int,  string) int64 {
	,  := []
	if ! {
		 = len()
		[] = 
	}
	return int64()
}

func getString( []string,  *int64,  error) (string, error) {
	if  != nil {
		return "", 
	}
	 := int(*)
	if  < 0 ||  >= len() {
		return "", errMalformed
	}
	* = 0
	return [], nil
}