This repository has been archived by the owner on Mar 14, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
ordered.go2
133 lines (114 loc) · 3.91 KB
/
ordered.go2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright 2020 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.
// ordered illustrates a workaround for the GeneralAbsDifference example in the
// Type Parameters draft, and the limitations of that workaround.
package main
import (
"fmt"
"math"
)
// Numeric is a constraint that matches any numeric type.
// It would likely be in a constraints package in the standard library.
type Numeric interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64,
complex64, complex128
}
// NumericAbs matches numeric types with an Abs method.
type NumericAbs(type T) interface {
Numeric
Abs() T
}
// AbsDifference computes the absolute value of the difference of
// a and b, where the absolute value is determined by the Abs method.
func AbsDifference(type T NumericAbs)(a, b T) T {
d := a - b
return d.Abs()
}
// OrderedNumeric matches numeric types that support the < operator.
type OrderedNumeric interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64
}
// Complex matches the two complex types, which do not have a < operator.
type Complex interface {
type complex64, complex128
}
// OrderedAbs is a helper type that defines an Abs method for
// ordered numeric types.
type OrderedAbs(type T OrderedNumeric) T
func (a OrderedAbs(T)) Abs() OrderedAbs(T) {
if a < 0 {
return -a
}
return a
}
// ComplexAbs is a helper type that defines an Abs method for
// complex types.
type ComplexAbs(type T Complex) T
func (a ComplexAbs(T)) Abs() ComplexAbs(T) {
d := math.Hypot(float64(real(a)), float64(imag(a)))
return ComplexAbs(T)(complex(d, 0))
}
// OrderedAbsDifference returns the absolute value of the difference
// between a and b, where a and b are of an ordered type.
func OrderedAbsDifference(type T OrderedNumeric)(a, b T) T {
return T(AbsDifference(OrderedAbs(T)(a), OrderedAbs(T)(b)))
}
// ComplexAbsDifference returns the absolute value of the difference
// between a and b, where a and b are of a complex type.
func ComplexAbsDifference(type T Complex)(a, b T) T {
return T(AbsDifference(ComplexAbs(T)(a), ComplexAbs(T)(b)))
}
func asSame(type T)(_ T, b interface{}) T {
return b.(T)
}
// GeneralAbsDifference implements AbsDifference for any *built-in* numeric type T.
//
// However, it panics for defined numeric types that are not built-in:
// handling those cases under the current design would require the use of reflection.
func GeneralAbsDifference(type T Numeric)(a, b T) T {
switch a := (interface{})(a).(type) {
case int:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case int8:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case int16:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case int32:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case int64:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case uint:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case uint8:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case uint16:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case uint32:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case uint64:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case uintptr:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case float32:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case float64:
return asSame(b, OrderedAbsDifference(a, asSame(a, b)))
case complex64:
return asSame(b, ComplexAbsDifference(a, asSame(a, b)))
case complex128:
return asSame(b, ComplexAbsDifference(a, asSame(a, b)))
default:
panic(fmt.Sprintf("%T is not a builtin numeric type", a))
}
}
type MyInt int
func main() {
fmt.Println(GeneralAbsDifference(42, 64))
fmt.Println(GeneralAbsDifference(42 + 3i, 64 + 0i))
fmt.Println(GeneralAbsDifference(MyInt(42), MyInt(64)))
}