Source file test/typeparam/absdiff2.go

     1  // run
     2  
     3  // Copyright 2022 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // absdiff example in which an Abs method is attached to a generic type, which is a
     8  // structure with a single field that may be a list of possible basic types.
     9  
    10  package main
    11  
    12  import (
    13  	"fmt"
    14  	"math"
    15  )
    16  
    17  type Numeric interface {
    18  	~int | ~int8 | ~int16 | ~int32 | ~int64 |
    19  		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
    20  		~float32 | ~float64 |
    21  		~complex64 | ~complex128
    22  }
    23  
    24  // numericAbs matches a struct containing a numeric type that has an Abs method.
    25  type numericAbs[T Numeric] interface {
    26  	~struct{ Value_ T }
    27  	Abs() T
    28  	Value() T
    29  }
    30  
    31  // absDifference computes the absolute value of the difference of
    32  // a and b, where the absolute value is determined by the Abs method.
    33  func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
    34  	d := a.Value() - b.Value()
    35  	dt := U{Value_: d}
    36  	return dt.Abs()
    37  }
    38  
    39  // orderedNumeric matches numeric types that support the < operator.
    40  type orderedNumeric interface {
    41  	~int | ~int8 | ~int16 | ~int32 | ~int64 |
    42  		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
    43  		~float32 | ~float64
    44  }
    45  
    46  // Complex matches the two complex types, which do not have a < operator.
    47  type Complex interface {
    48  	~complex64 | ~complex128
    49  }
    50  
    51  // orderedAbs is a helper type that defines an Abs method for
    52  // a struct containing an ordered numeric type.
    53  type orderedAbs[T orderedNumeric] struct {
    54  	Value_ T
    55  }
    56  
    57  func (a orderedAbs[T]) Abs() T {
    58  	if a.Value_ < 0 {
    59  		return -a.Value_
    60  	}
    61  	return a.Value_
    62  }
    63  
    64  // Field accesses through type parameters are disabled
    65  // until we have a more thorough understanding of the
    66  // implications on the spec. See issue #51576.
    67  // Use accessor method instead.
    68  
    69  func (a orderedAbs[T]) Value() T {
    70  	return a.Value_
    71  }
    72  
    73  // complexAbs is a helper type that defines an Abs method for
    74  // a struct containing a complex type.
    75  type complexAbs[T Complex] struct {
    76  	Value_ T
    77  }
    78  
    79  func realimag(x any) (re, im float64) {
    80  	switch z := x.(type) {
    81  	case complex64:
    82  		re = float64(real(z))
    83  		im = float64(imag(z))
    84  	case complex128:
    85  		re = real(z)
    86  		im = imag(z)
    87  	default:
    88  		panic("unknown complex type")
    89  	}
    90  	return
    91  }
    92  
    93  func (a complexAbs[T]) Abs() T {
    94  	// TODO use direct conversion instead of realimag once #50937 is fixed
    95  	r, i := realimag(a.Value_)
    96  	// r := float64(real(a.Value))
    97  	// i := float64(imag(a.Value))
    98  	d := math.Sqrt(r*r + i*i)
    99  	return T(complex(d, 0))
   100  }
   101  
   102  func (a complexAbs[T]) Value() T {
   103  	return a.Value_
   104  }
   105  
   106  // OrderedAbsDifference returns the absolute value of the difference
   107  // between a and b, where a and b are of an ordered type.
   108  func OrderedAbsDifference[T orderedNumeric](a, b T) T {
   109  	return absDifference(orderedAbs[T]{a}, orderedAbs[T]{b})
   110  }
   111  
   112  // ComplexAbsDifference returns the absolute value of the difference
   113  // between a and b, where a and b are of a complex type.
   114  func ComplexAbsDifference[T Complex](a, b T) T {
   115  	return absDifference(complexAbs[T]{a}, complexAbs[T]{b})
   116  }
   117  
   118  func main() {
   119  	if got, want := OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
   120  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
   121  	}
   122  	if got, want := OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
   123  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
   124  	}
   125  	if got, want := OrderedAbsDifference(-20, 15), 35; got != want {
   126  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
   127  	}
   128  
   129  	if got, want := ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
   130  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
   131  	}
   132  	if got, want := ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
   133  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
   134  	}
   135  }
   136  

View as plain text