// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package value

import (
	
	
	
	
)

// SortKeys sorts a list of map keys, deduplicating keys if necessary.
// The type of each value must be comparable.
func ( []reflect.Value) []reflect.Value {
	if len() == 0 {
		return 
	}

	// Sort the map keys.
	sort.SliceStable(, func(,  int) bool { return isLess([], []) })

	// Deduplicate keys (fails for NaNs).
	 := [:1]
	for ,  := range [1:] {
		if isLess([len()-1], ) {
			 = append(, )
		}
	}
	return 
}

// isLess is a generic function for sorting arbitrary map keys.
// The inputs must be of the same type and must be comparable.
func (,  reflect.Value) bool {
	switch .Type().Kind() {
	case reflect.Bool:
		return !.Bool() && .Bool()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return .Int() < .Int()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return .Uint() < .Uint()
	case reflect.Float32, reflect.Float64:
		// NOTE: This does not sort -0 as less than +0
		// since Go maps treat -0 and +0 as equal keys.
		,  := .Float(), .Float()
		return  <  || math.IsNaN() && !math.IsNaN()
	case reflect.Complex64, reflect.Complex128:
		,  := .Complex(), .Complex()
		, , ,  := real(), imag(), real(), imag()
		if  ==  || (math.IsNaN() && math.IsNaN()) {
			return  <  || math.IsNaN() && !math.IsNaN()
		}
		return  <  || math.IsNaN() && !math.IsNaN()
	case reflect.Ptr, reflect.UnsafePointer, reflect.Chan:
		return .Pointer() < .Pointer()
	case reflect.String:
		return .String() < .String()
	case reflect.Array:
		for  := 0;  < .Len(); ++ {
			if (.Index(), .Index()) {
				return true
			}
			if (.Index(), .Index()) {
				return false
			}
		}
		return false
	case reflect.Struct:
		for  := 0;  < .NumField(); ++ {
			if (.Field(), .Field()) {
				return true
			}
			if (.Field(), .Field()) {
				return false
			}
		}
		return false
	case reflect.Interface:
		,  := .Elem(), .Elem()
		if !.IsValid() || !.IsValid() {
			return !.IsValid() && .IsValid()
		}
		,  := .Type(), .Type()
		if  ==  {
			return (.Elem(), .Elem())
		}
		if .Kind() != .Kind() {
			return .Kind() < .Kind()
		}
		if .String() != .String() {
			return .String() < .String()
		}
		if .PkgPath() != .PkgPath() {
			return .PkgPath() < .PkgPath()
		}
		// This can happen in rare situations, so we fallback to just comparing
		// the unique pointer for a reflect.Type. This guarantees deterministic
		// ordering within a program, but it is obviously not stable.
		return reflect.ValueOf(.Type()).Pointer() < reflect.ValueOf(.Type()).Pointer()
	default:
		// Must be Func, Map, or Slice; which are not comparable.
		panic(fmt.Sprintf("%T is not comparable", .Type()))
	}
}