-
Notifications
You must be signed in to change notification settings - Fork 37
/
decomposer.go
115 lines (106 loc) · 4.34 KB
/
decomposer.go
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
// Copyright 2016 The Cockroach Authors.
//
// 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 apd
import "fmt"
// decomposer composes or decomposes a decimal value to and from individual parts.
// There are four separate parts: a boolean negative flag, a form byte with three possible states
// (finite=0, infinite=1, NaN=2), a base-2 big-endian integer
// coefficient (also known as a significand) as a []byte, and an int32 exponent.
// These are composed into a final value as "decimal = (neg) (form=finite) coefficient * 10 ^ exponent".
// A zero length coefficient is a zero value.
// If the form is not finite the coefficient and scale should be ignored.
// The negative parameter may be set to true for any form, although implementations are not required
// to respect the negative parameter in the non-finite form.
//
// Implementations may choose to signal a negative zero or negative NaN, but implementations
// that do not support these may also ignore the negative zero or negative NaN without error.
// If an implementation does not support Infinity it may be converted into a NaN without error.
// If a value is set that is larger then what is supported by an implementation is attempted to
// be set, an error must be returned.
// Implementations must return an error if a NaN or Infinity is attempted to be set while neither
// are supported.
type decomposer interface {
// Decompose returns the internal decimal state into parts. If the provided buf
// has sufficient capacity, buf may be returned as the coefficient with the
// value set and length set as appropriate. Note that it does not act like
// Append-like functions and does not fill necessarily from the beginning of the
// buffer.
Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32)
// Compose sets the internal decimal value from parts. If the value cannot be
// represented then an error should be returned.
// The coefficent should not be modified. Successive calls to compose with
// the same arguments should result in the same decimal value.
Compose(form byte, negative bool, coefficient []byte, exponent int32) error
}
var _ decomposer = &Decimal{}
// Decompose returns the internal decimal state into parts. If the provided buf
// has sufficient capacity, buf may be returned as the coefficient with the
// value set and length set as appropriate. Note that it does not act like
// Append-like functions and does not fill necessarily from the beginning of the
// buffer.
func (d *Decimal) Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) {
switch d.Form {
default:
panic(fmt.Errorf("unknown Form: %v", d.Form))
case Finite:
// Nothing, continue on.
case Infinite:
negative = d.Negative
form = 1
return
case NaNSignaling, NaN:
negative = d.Negative
form = 2
return
}
// Finite form.
negative = d.Negative
exponent = d.Exponent
sizeInBytes := (d.Coeff.BitLen() + 8 - 1) / 8 // math.Ceil(d.Coeff.BitLen()/8.0)
if cap(buf) >= sizeInBytes {
// It extends the buffer as the filling of bytes expects an already
// allocated slice.
buf = buf[:sizeInBytes]
// We can fit the coefficient in the given buffer which prevents an
// allocation.
coefficient = d.Coeff.FillBytes(buf)
} else {
coefficient = d.Coeff.Bytes()
}
return
}
// Compose sets the internal decimal value from parts. If the value cannot be
// represented then an error should be returned.
func (d *Decimal) Compose(form byte, negative bool, coefficient []byte, exponent int32) error {
switch form {
default:
return fmt.Errorf("unknown form: %v", form)
case 0:
d.Form = Finite
// Set rest of finite form below.
case 1:
d.Form = Infinite
d.Negative = negative
return nil
case 2:
d.Form = NaN
d.Negative = negative
return nil
}
// Finite form.
d.Negative = negative
d.Coeff.SetBytes(coefficient)
d.Exponent = exponent
return nil
}