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
|
# 32-bit fixed-point number, with 6 bits of precision.
type LUnit* = distinct int32
{.push overflowChecks: off, rangeChecks: off.}
template satlu(a: int64): LUnit =
if unlikely(a < int32.low):
LUnit.low
elif unlikely(a > int32.high):
LUnit.high
else:
LUnit(a)
when sizeof(int) == 4 and not defined(nimEmulateOverflowChecks) and
(defined(gcc) or defined(clang)):
func nimAddInt(a, b: int; res: ptr int): bool {.importc, nodecl.}
func nimSubInt(a, b: int; res: ptr int): bool {.importc, nodecl.}
func `+`*(a, b: LUnit): LUnit {.inline.} =
let a = int(a)
let b = int(b)
var res {.noinit.}: int
if nimAddInt(a, b, addr res):
if a > 0:
return LUnit.high
return LUnit.low
return LUnit(res)
func `-`*(a, b: LUnit): LUnit {.inline.} =
let a = int(a)
let b = int(b)
var res {.noinit.}: int
if nimSubInt(a, b, addr res):
if b < 0:
return LUnit.high
return LUnit.low
return LUnit(res)
else:
when sizeof(int) == 4:
{.warning: """Using 64-bit lunit ops on a 32-bit arch.
If you are using GCC/clang, report this at https://todo.sr.ht/~bptato/chawan""".}
func `+`*(a, b: LUnit): LUnit {.inline.} =
let ab = int64(a) + int64(b)
return satlu(ab)
func `-`*(a, b: LUnit): LUnit {.inline.} =
let ab = int64(a) - int64(b)
return satlu(ab)
func `*`*(a, b: LUnit): LUnit {.inline.} =
let ab = (int64(a) * int64(b)) shr 6
return satlu(ab)
func `div`*(a, b: LUnit): LUnit {.inline.} =
let a = int64(uint64(a) shl 12)
let b = int64(b)
return LUnit((a div b) shr 6)
converter toLUnit*(a: int32): LUnit =
let a = int64(a) shl 6
return satlu(a)
converter toLUnit*(a: int): LUnit =
let a = int64(a) shl 6
return satlu(a)
func `-`*(a: LUnit): LUnit {.inline.} =
let a = int32(a)
if unlikely(a == int32.high):
return LUnit.low
return LUnit(-a)
{.pop.} # overflowChecks, rangeChecks
func `==`*(a, b: LUnit): bool {.borrow.}
func `<`*(a, b: LUnit): bool {.borrow.}
func `<=`*(a, b: LUnit): bool {.borrow.}
func toInt*(a: LUnit): int =
if a < 0:
return -(int32(-a) shr 6)
return int32(a) shr 6
func `+=`*(a: var LUnit; b: LUnit) {.inline.} =
a = a + b
func `-=`*(a: var LUnit; b: LUnit) {.inline.} =
a = a - b
func `*=`*(a: var LUnit; b: LUnit) {.inline.} =
a = a * b
func toLUnit*(a: float32): LUnit =
let a = a * 64
if unlikely(a == Inf):
return LUnit(high(int32))
elif unlikely(a == -Inf):
return LUnit(low(int32))
return LUnit(int32(a))
func toFloat32*(a: LUnit): float64 =
return float32(int32(a)) / 64
func `$`*(a: LUnit): string =
$toFloat32(a)
func min*(a, b: LUnit): LUnit {.borrow.}
func max*(a, b: LUnit): LUnit {.borrow.}
func ceilTo*(a: LUnit; prec: int): LUnit =
return (1 + ((a - 1) div prec).toInt) * prec
|