Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / k8s.io / apimachinery / pkg / api / resource / amount.go
1 /*
2 Copyright 2014 The Kubernetes Authors.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8     http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 package resource
18
19 import (
20         "math/big"
21         "strconv"
22
23         inf "gopkg.in/inf.v0"
24 )
25
26 // Scale is used for getting and setting the base-10 scaled value.
27 // Base-2 scales are omitted for mathematical simplicity.
28 // See Quantity.ScaledValue for more details.
29 type Scale int32
30
31 // infScale adapts a Scale value to an inf.Scale value.
32 func (s Scale) infScale() inf.Scale {
33         return inf.Scale(-s) // inf.Scale is upside-down
34 }
35
36 const (
37         Nano  Scale = -9
38         Micro Scale = -6
39         Milli Scale = -3
40         Kilo  Scale = 3
41         Mega  Scale = 6
42         Giga  Scale = 9
43         Tera  Scale = 12
44         Peta  Scale = 15
45         Exa   Scale = 18
46 )
47
48 var (
49         Zero = int64Amount{}
50
51         // Used by quantity strings - treat as read only
52         zeroBytes = []byte("0")
53 )
54
55 // int64Amount represents a fixed precision numerator and arbitrary scale exponent. It is faster
56 // than operations on inf.Dec for values that can be represented as int64.
57 // +k8s:openapi-gen=true
58 type int64Amount struct {
59         value int64
60         scale Scale
61 }
62
63 // Sign returns 0 if the value is zero, -1 if it is less than 0, or 1 if it is greater than 0.
64 func (a int64Amount) Sign() int {
65         switch {
66         case a.value == 0:
67                 return 0
68         case a.value > 0:
69                 return 1
70         default:
71                 return -1
72         }
73 }
74
75 // AsInt64 returns the current amount as an int64 at scale 0, or false if the value cannot be
76 // represented in an int64 OR would result in a loss of precision. This method is intended as
77 // an optimization to avoid calling AsDec.
78 func (a int64Amount) AsInt64() (int64, bool) {
79         if a.scale == 0 {
80                 return a.value, true
81         }
82         if a.scale < 0 {
83                 // TODO: attempt to reduce factors, although it is assumed that factors are reduced prior
84                 // to the int64Amount being created.
85                 return 0, false
86         }
87         return positiveScaleInt64(a.value, a.scale)
88 }
89
90 // AsScaledInt64 returns an int64 representing the value of this amount at the specified scale,
91 // rounding up, or false if that would result in overflow. (1e20).AsScaledInt64(1) would result
92 // in overflow because 1e19 is not representable as an int64. Note that setting a scale larger
93 // than the current value may result in loss of precision - i.e. (1e-6).AsScaledInt64(0) would
94 // return 1, because 0.000001 is rounded up to 1.
95 func (a int64Amount) AsScaledInt64(scale Scale) (result int64, ok bool) {
96         if a.scale < scale {
97                 result, _ = negativeScaleInt64(a.value, scale-a.scale)
98                 return result, true
99         }
100         return positiveScaleInt64(a.value, a.scale-scale)
101 }
102
103 // AsDec returns an inf.Dec representation of this value.
104 func (a int64Amount) AsDec() *inf.Dec {
105         var base inf.Dec
106         base.SetUnscaled(a.value)
107         base.SetScale(inf.Scale(-a.scale))
108         return &base
109 }
110
111 // Cmp returns 0 if a and b are equal, 1 if a is greater than b, or -1 if a is less than b.
112 func (a int64Amount) Cmp(b int64Amount) int {
113         switch {
114         case a.scale == b.scale:
115                 // compare only the unscaled portion
116         case a.scale > b.scale:
117                 result, remainder, exact := divideByScaleInt64(b.value, a.scale-b.scale)
118                 if !exact {
119                         return a.AsDec().Cmp(b.AsDec())
120                 }
121                 if result == a.value {
122                         switch {
123                         case remainder == 0:
124                                 return 0
125                         case remainder > 0:
126                                 return -1
127                         default:
128                                 return 1
129                         }
130                 }
131                 b.value = result
132         default:
133                 result, remainder, exact := divideByScaleInt64(a.value, b.scale-a.scale)
134                 if !exact {
135                         return a.AsDec().Cmp(b.AsDec())
136                 }
137                 if result == b.value {
138                         switch {
139                         case remainder == 0:
140                                 return 0
141                         case remainder > 0:
142                                 return 1
143                         default:
144                                 return -1
145                         }
146                 }
147                 a.value = result
148         }
149
150         switch {
151         case a.value == b.value:
152                 return 0
153         case a.value < b.value:
154                 return -1
155         default:
156                 return 1
157         }
158 }
159
160 // Add adds two int64Amounts together, matching scales. It will return false and not mutate
161 // a if overflow or underflow would result.
162 func (a *int64Amount) Add(b int64Amount) bool {
163         switch {
164         case b.value == 0:
165                 return true
166         case a.value == 0:
167                 a.value = b.value
168                 a.scale = b.scale
169                 return true
170         case a.scale == b.scale:
171                 c, ok := int64Add(a.value, b.value)
172                 if !ok {
173                         return false
174                 }
175                 a.value = c
176         case a.scale > b.scale:
177                 c, ok := positiveScaleInt64(a.value, a.scale-b.scale)
178                 if !ok {
179                         return false
180                 }
181                 c, ok = int64Add(c, b.value)
182                 if !ok {
183                         return false
184                 }
185                 a.scale = b.scale
186                 a.value = c
187         default:
188                 c, ok := positiveScaleInt64(b.value, b.scale-a.scale)
189                 if !ok {
190                         return false
191                 }
192                 c, ok = int64Add(a.value, c)
193                 if !ok {
194                         return false
195                 }
196                 a.value = c
197         }
198         return true
199 }
200
201 // Sub removes the value of b from the current amount, or returns false if underflow would result.
202 func (a *int64Amount) Sub(b int64Amount) bool {
203         return a.Add(int64Amount{value: -b.value, scale: b.scale})
204 }
205
206 // AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision
207 // was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6.
208 func (a int64Amount) AsScale(scale Scale) (int64Amount, bool) {
209         if a.scale >= scale {
210                 return a, true
211         }
212         result, exact := negativeScaleInt64(a.value, scale-a.scale)
213         return int64Amount{value: result, scale: scale}, exact
214 }
215
216 // AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns
217 // either that buffer or a larger buffer and the current exponent of the value. The value is adjusted
218 // until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3.
219 func (a int64Amount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
220         mantissa := a.value
221         exponent = int32(a.scale)
222
223         amount, times := removeInt64Factors(mantissa, 10)
224         exponent += int32(times)
225
226         // make sure exponent is a multiple of 3
227         var ok bool
228         switch exponent % 3 {
229         case 1, -2:
230                 amount, ok = int64MultiplyScale10(amount)
231                 if !ok {
232                         return infDecAmount{a.AsDec()}.AsCanonicalBytes(out)
233                 }
234                 exponent = exponent - 1
235         case 2, -1:
236                 amount, ok = int64MultiplyScale100(amount)
237                 if !ok {
238                         return infDecAmount{a.AsDec()}.AsCanonicalBytes(out)
239                 }
240                 exponent = exponent - 2
241         }
242         return strconv.AppendInt(out, amount, 10), exponent
243 }
244
245 // AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns
246 // either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would
247 // return []byte("2048"), 1.
248 func (a int64Amount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) {
249         value, ok := a.AsScaledInt64(0)
250         if !ok {
251                 return infDecAmount{a.AsDec()}.AsCanonicalBase1024Bytes(out)
252         }
253         amount, exponent := removeInt64Factors(value, 1024)
254         return strconv.AppendInt(out, amount, 10), exponent
255 }
256
257 // infDecAmount implements common operations over an inf.Dec that are specific to the quantity
258 // representation.
259 type infDecAmount struct {
260         *inf.Dec
261 }
262
263 // AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision
264 // was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6.
265 func (a infDecAmount) AsScale(scale Scale) (infDecAmount, bool) {
266         tmp := &inf.Dec{}
267         tmp.Round(a.Dec, scale.infScale(), inf.RoundUp)
268         return infDecAmount{tmp}, tmp.Cmp(a.Dec) == 0
269 }
270
271 // AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns
272 // either that buffer or a larger buffer and the current exponent of the value. The value is adjusted
273 // until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3.
274 func (a infDecAmount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
275         mantissa := a.Dec.UnscaledBig()
276         exponent = int32(-a.Dec.Scale())
277         amount := big.NewInt(0).Set(mantissa)
278         // move all factors of 10 into the exponent for easy reasoning
279         amount, times := removeBigIntFactors(amount, bigTen)
280         exponent += times
281
282         // make sure exponent is a multiple of 3
283         for exponent%3 != 0 {
284                 amount.Mul(amount, bigTen)
285                 exponent--
286         }
287
288         return append(out, amount.String()...), exponent
289 }
290
291 // AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns
292 // either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would
293 // return []byte("2048"), 1.
294 func (a infDecAmount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) {
295         tmp := &inf.Dec{}
296         tmp.Round(a.Dec, 0, inf.RoundUp)
297         amount, exponent := removeBigIntFactors(tmp.UnscaledBig(), big1024)
298         return append(out, amount.String()...), exponent
299 }