Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / k8s.io / apimachinery / pkg / api / resource / quantity.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         "bytes"
21         "errors"
22         "fmt"
23         "math/big"
24         "strconv"
25         "strings"
26
27         inf "gopkg.in/inf.v0"
28 )
29
30 // Quantity is a fixed-point representation of a number.
31 // It provides convenient marshaling/unmarshaling in JSON and YAML,
32 // in addition to String() and Int64() accessors.
33 //
34 // The serialization format is:
35 //
36 // <quantity>        ::= <signedNumber><suffix>
37 //   (Note that <suffix> may be empty, from the "" case in <decimalSI>.)
38 // <digit>           ::= 0 | 1 | ... | 9
39 // <digits>          ::= <digit> | <digit><digits>
40 // <number>          ::= <digits> | <digits>.<digits> | <digits>. | .<digits>
41 // <sign>            ::= "+" | "-"
42 // <signedNumber>    ::= <number> | <sign><number>
43 // <suffix>          ::= <binarySI> | <decimalExponent> | <decimalSI>
44 // <binarySI>        ::= Ki | Mi | Gi | Ti | Pi | Ei
45 //   (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)
46 // <decimalSI>       ::= m | "" | k | M | G | T | P | E
47 //   (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)
48 // <decimalExponent> ::= "e" <signedNumber> | "E" <signedNumber>
49 //
50 // No matter which of the three exponent forms is used, no quantity may represent
51 // a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal
52 // places. Numbers larger or more precise will be capped or rounded up.
53 // (E.g.: 0.1m will rounded up to 1m.)
54 // This may be extended in the future if we require larger or smaller quantities.
55 //
56 // When a Quantity is parsed from a string, it will remember the type of suffix
57 // it had, and will use the same type again when it is serialized.
58 //
59 // Before serializing, Quantity will be put in "canonical form".
60 // This means that Exponent/suffix will be adjusted up or down (with a
61 // corresponding increase or decrease in Mantissa) such that:
62 //   a. No precision is lost
63 //   b. No fractional digits will be emitted
64 //   c. The exponent (or suffix) is as large as possible.
65 // The sign will be omitted unless the number is negative.
66 //
67 // Examples:
68 //   1.5 will be serialized as "1500m"
69 //   1.5Gi will be serialized as "1536Mi"
70 //
71 // Note that the quantity will NEVER be internally represented by a
72 // floating point number. That is the whole point of this exercise.
73 //
74 // Non-canonical values will still parse as long as they are well formed,
75 // but will be re-emitted in their canonical form. (So always use canonical
76 // form, or don't diff.)
77 //
78 // This format is intended to make it difficult to use these numbers without
79 // writing some sort of special handling code in the hopes that that will
80 // cause implementors to also use a fixed point implementation.
81 //
82 // +protobuf=true
83 // +protobuf.embed=string
84 // +protobuf.options.marshal=false
85 // +protobuf.options.(gogoproto.goproto_stringer)=false
86 // +k8s:deepcopy-gen=true
87 // +k8s:openapi-gen=true
88 type Quantity struct {
89         // i is the quantity in int64 scaled form, if d.Dec == nil
90         i int64Amount
91         // d is the quantity in inf.Dec form if d.Dec != nil
92         d infDecAmount
93         // s is the generated value of this quantity to avoid recalculation
94         s string
95
96         // Change Format at will. See the comment for Canonicalize for
97         // more details.
98         Format
99 }
100
101 // CanonicalValue allows a quantity amount to be converted to a string.
102 type CanonicalValue interface {
103         // AsCanonicalBytes returns a byte array representing the string representation
104         // of the value mantissa and an int32 representing its exponent in base-10. Callers may
105         // pass a byte slice to the method to avoid allocations.
106         AsCanonicalBytes(out []byte) ([]byte, int32)
107         // AsCanonicalBase1024Bytes returns a byte array representing the string representation
108         // of the value mantissa and an int32 representing its exponent in base-1024. Callers
109         // may pass a byte slice to the method to avoid allocations.
110         AsCanonicalBase1024Bytes(out []byte) ([]byte, int32)
111 }
112
113 // Format lists the three possible formattings of a quantity.
114 type Format string
115
116 const (
117         DecimalExponent = Format("DecimalExponent") // e.g., 12e6
118         BinarySI        = Format("BinarySI")        // e.g., 12Mi (12 * 2^20)
119         DecimalSI       = Format("DecimalSI")       // e.g., 12M  (12 * 10^6)
120 )
121
122 // MustParse turns the given string into a quantity or panics; for tests
123 // or others cases where you know the string is valid.
124 func MustParse(str string) Quantity {
125         q, err := ParseQuantity(str)
126         if err != nil {
127                 panic(fmt.Errorf("cannot parse '%v': %v", str, err))
128         }
129         return q
130 }
131
132 const (
133         // splitREString is used to separate a number from its suffix; as such,
134         // this is overly permissive, but that's OK-- it will be checked later.
135         splitREString = "^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$"
136 )
137
138 var (
139         // Errors that could happen while parsing a string.
140         ErrFormatWrong = errors.New("quantities must match the regular expression '" + splitREString + "'")
141         ErrNumeric     = errors.New("unable to parse numeric part of quantity")
142         ErrSuffix      = errors.New("unable to parse quantity's suffix")
143 )
144
145 // parseQuantityString is a fast scanner for quantity values.
146 func parseQuantityString(str string) (positive bool, value, num, denom, suffix string, err error) {
147         positive = true
148         pos := 0
149         end := len(str)
150
151         // handle leading sign
152         if pos < end {
153                 switch str[0] {
154                 case '-':
155                         positive = false
156                         pos++
157                 case '+':
158                         pos++
159                 }
160         }
161
162         // strip leading zeros
163 Zeroes:
164         for i := pos; ; i++ {
165                 if i >= end {
166                         num = "0"
167                         value = num
168                         return
169                 }
170                 switch str[i] {
171                 case '0':
172                         pos++
173                 default:
174                         break Zeroes
175                 }
176         }
177
178         // extract the numerator
179 Num:
180         for i := pos; ; i++ {
181                 if i >= end {
182                         num = str[pos:end]
183                         value = str[0:end]
184                         return
185                 }
186                 switch str[i] {
187                 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
188                 default:
189                         num = str[pos:i]
190                         pos = i
191                         break Num
192                 }
193         }
194
195         // if we stripped all numerator positions, always return 0
196         if len(num) == 0 {
197                 num = "0"
198         }
199
200         // handle a denominator
201         if pos < end && str[pos] == '.' {
202                 pos++
203         Denom:
204                 for i := pos; ; i++ {
205                         if i >= end {
206                                 denom = str[pos:end]
207                                 value = str[0:end]
208                                 return
209                         }
210                         switch str[i] {
211                         case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
212                         default:
213                                 denom = str[pos:i]
214                                 pos = i
215                                 break Denom
216                         }
217                 }
218                 // TODO: we currently allow 1.G, but we may not want to in the future.
219                 // if len(denom) == 0 {
220                 //      err = ErrFormatWrong
221                 //      return
222                 // }
223         }
224         value = str[0:pos]
225
226         // grab the elements of the suffix
227         suffixStart := pos
228         for i := pos; ; i++ {
229                 if i >= end {
230                         suffix = str[suffixStart:end]
231                         return
232                 }
233                 if !strings.ContainsAny(str[i:i+1], "eEinumkKMGTP") {
234                         pos = i
235                         break
236                 }
237         }
238         if pos < end {
239                 switch str[pos] {
240                 case '-', '+':
241                         pos++
242                 }
243         }
244 Suffix:
245         for i := pos; ; i++ {
246                 if i >= end {
247                         suffix = str[suffixStart:end]
248                         return
249                 }
250                 switch str[i] {
251                 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
252                 default:
253                         break Suffix
254                 }
255         }
256         // we encountered a non decimal in the Suffix loop, but the last character
257         // was not a valid exponent
258         err = ErrFormatWrong
259         return
260 }
261
262 // ParseQuantity turns str into a Quantity, or returns an error.
263 func ParseQuantity(str string) (Quantity, error) {
264         if len(str) == 0 {
265                 return Quantity{}, ErrFormatWrong
266         }
267         if str == "0" {
268                 return Quantity{Format: DecimalSI, s: str}, nil
269         }
270
271         positive, value, num, denom, suf, err := parseQuantityString(str)
272         if err != nil {
273                 return Quantity{}, err
274         }
275
276         base, exponent, format, ok := quantitySuffixer.interpret(suffix(suf))
277         if !ok {
278                 return Quantity{}, ErrSuffix
279         }
280
281         precision := int32(0)
282         scale := int32(0)
283         mantissa := int64(1)
284         switch format {
285         case DecimalExponent, DecimalSI:
286                 scale = exponent
287                 precision = maxInt64Factors - int32(len(num)+len(denom))
288         case BinarySI:
289                 scale = 0
290                 switch {
291                 case exponent >= 0 && len(denom) == 0:
292                         // only handle positive binary numbers with the fast path
293                         mantissa = int64(int64(mantissa) << uint64(exponent))
294                         // 1Mi (2^20) has ~6 digits of decimal precision, so exponent*3/10 -1 is roughly the precision
295                         precision = 15 - int32(len(num)) - int32(float32(exponent)*3/10) - 1
296                 default:
297                         precision = -1
298                 }
299         }
300
301         if precision >= 0 {
302                 // if we have a denominator, shift the entire value to the left by the number of places in the
303                 // denominator
304                 scale -= int32(len(denom))
305                 if scale >= int32(Nano) {
306                         shifted := num + denom
307
308                         var value int64
309                         value, err := strconv.ParseInt(shifted, 10, 64)
310                         if err != nil {
311                                 return Quantity{}, ErrNumeric
312                         }
313                         if result, ok := int64Multiply(value, int64(mantissa)); ok {
314                                 if !positive {
315                                         result = -result
316                                 }
317                                 // if the number is in canonical form, reuse the string
318                                 switch format {
319                                 case BinarySI:
320                                         if exponent%10 == 0 && (value&0x07 != 0) {
321                                                 return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil
322                                         }
323                                 default:
324                                         if scale%3 == 0 && !strings.HasSuffix(shifted, "000") && shifted[0] != '0' {
325                                                 return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil
326                                         }
327                                 }
328                                 return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format}, nil
329                         }
330                 }
331         }
332
333         amount := new(inf.Dec)
334         if _, ok := amount.SetString(value); !ok {
335                 return Quantity{}, ErrNumeric
336         }
337
338         // So that no one but us has to think about suffixes, remove it.
339         if base == 10 {
340                 amount.SetScale(amount.Scale() + Scale(exponent).infScale())
341         } else if base == 2 {
342                 // numericSuffix = 2 ** exponent
343                 numericSuffix := big.NewInt(1).Lsh(bigOne, uint(exponent))
344                 ub := amount.UnscaledBig()
345                 amount.SetUnscaledBig(ub.Mul(ub, numericSuffix))
346         }
347
348         // Cap at min/max bounds.
349         sign := amount.Sign()
350         if sign == -1 {
351                 amount.Neg(amount)
352         }
353
354         // This rounds non-zero values up to the minimum representable value, under the theory that
355         // if you want some resources, you should get some resources, even if you asked for way too small
356         // of an amount.  Arguably, this should be inf.RoundHalfUp (normal rounding), but that would have
357         // the side effect of rounding values < .5n to zero.
358         if v, ok := amount.Unscaled(); v != int64(0) || !ok {
359                 amount.Round(amount, Nano.infScale(), inf.RoundUp)
360         }
361
362         // The max is just a simple cap.
363         // TODO: this prevents accumulating quantities greater than int64, for instance quota across a cluster
364         if format == BinarySI && amount.Cmp(maxAllowed.Dec) > 0 {
365                 amount.Set(maxAllowed.Dec)
366         }
367
368         if format == BinarySI && amount.Cmp(decOne) < 0 && amount.Cmp(decZero) > 0 {
369                 // This avoids rounding and hopefully confusion, too.
370                 format = DecimalSI
371         }
372         if sign == -1 {
373                 amount.Neg(amount)
374         }
375
376         return Quantity{d: infDecAmount{amount}, Format: format}, nil
377 }
378
379 // DeepCopy returns a deep-copy of the Quantity value.  Note that the method
380 // receiver is a value, so we can mutate it in-place and return it.
381 func (q Quantity) DeepCopy() Quantity {
382         if q.d.Dec != nil {
383                 tmp := &inf.Dec{}
384                 q.d.Dec = tmp.Set(q.d.Dec)
385         }
386         return q
387 }
388
389 // OpenAPISchemaType is used by the kube-openapi generator when constructing
390 // the OpenAPI spec of this type.
391 //
392 // See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
393 func (_ Quantity) OpenAPISchemaType() []string { return []string{"string"} }
394
395 // OpenAPISchemaFormat is used by the kube-openapi generator when constructing
396 // the OpenAPI spec of this type.
397 func (_ Quantity) OpenAPISchemaFormat() string { return "" }
398
399 // CanonicalizeBytes returns the canonical form of q and its suffix (see comment on Quantity).
400 //
401 // Note about BinarySI:
402 // * If q.Format is set to BinarySI and q.Amount represents a non-zero value between
403 //   -1 and +1, it will be emitted as if q.Format were DecimalSI.
404 // * Otherwise, if q.Format is set to BinarySI, fractional parts of q.Amount will be
405 //   rounded up. (1.1i becomes 2i.)
406 func (q *Quantity) CanonicalizeBytes(out []byte) (result, suffix []byte) {
407         if q.IsZero() {
408                 return zeroBytes, nil
409         }
410
411         var rounded CanonicalValue
412         format := q.Format
413         switch format {
414         case DecimalExponent, DecimalSI:
415         case BinarySI:
416                 if q.CmpInt64(-1024) > 0 && q.CmpInt64(1024) < 0 {
417                         // This avoids rounding and hopefully confusion, too.
418                         format = DecimalSI
419                 } else {
420                         var exact bool
421                         if rounded, exact = q.AsScale(0); !exact {
422                                 // Don't lose precision-- show as DecimalSI
423                                 format = DecimalSI
424                         }
425                 }
426         default:
427                 format = DecimalExponent
428         }
429
430         // TODO: If BinarySI formatting is requested but would cause rounding, upgrade to
431         // one of the other formats.
432         switch format {
433         case DecimalExponent, DecimalSI:
434                 number, exponent := q.AsCanonicalBytes(out)
435                 suffix, _ := quantitySuffixer.constructBytes(10, exponent, format)
436                 return number, suffix
437         default:
438                 // format must be BinarySI
439                 number, exponent := rounded.AsCanonicalBase1024Bytes(out)
440                 suffix, _ := quantitySuffixer.constructBytes(2, exponent*10, format)
441                 return number, suffix
442         }
443 }
444
445 // AsInt64 returns a representation of the current value as an int64 if a fast conversion
446 // is possible. If false is returned, callers must use the inf.Dec form of this quantity.
447 func (q *Quantity) AsInt64() (int64, bool) {
448         if q.d.Dec != nil {
449                 return 0, false
450         }
451         return q.i.AsInt64()
452 }
453
454 // ToDec promotes the quantity in place to use an inf.Dec representation and returns itself.
455 func (q *Quantity) ToDec() *Quantity {
456         if q.d.Dec == nil {
457                 q.d.Dec = q.i.AsDec()
458                 q.i = int64Amount{}
459         }
460         return q
461 }
462
463 // AsDec returns the quantity as represented by a scaled inf.Dec.
464 func (q *Quantity) AsDec() *inf.Dec {
465         if q.d.Dec != nil {
466                 return q.d.Dec
467         }
468         q.d.Dec = q.i.AsDec()
469         q.i = int64Amount{}
470         return q.d.Dec
471 }
472
473 // AsCanonicalBytes returns the canonical byte representation of this quantity as a mantissa
474 // and base 10 exponent. The out byte slice may be passed to the method to avoid an extra
475 // allocation.
476 func (q *Quantity) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
477         if q.d.Dec != nil {
478                 return q.d.AsCanonicalBytes(out)
479         }
480         return q.i.AsCanonicalBytes(out)
481 }
482
483 // IsZero returns true if the quantity is equal to zero.
484 func (q *Quantity) IsZero() bool {
485         if q.d.Dec != nil {
486                 return q.d.Dec.Sign() == 0
487         }
488         return q.i.value == 0
489 }
490
491 // Sign returns 0 if the quantity is zero, -1 if the quantity is less than zero, or 1 if the
492 // quantity is greater than zero.
493 func (q *Quantity) Sign() int {
494         if q.d.Dec != nil {
495                 return q.d.Dec.Sign()
496         }
497         return q.i.Sign()
498 }
499
500 // AsScale returns the current value, rounded up to the provided scale, and returns
501 // false if the scale resulted in a loss of precision.
502 func (q *Quantity) AsScale(scale Scale) (CanonicalValue, bool) {
503         if q.d.Dec != nil {
504                 return q.d.AsScale(scale)
505         }
506         return q.i.AsScale(scale)
507 }
508
509 // RoundUp updates the quantity to the provided scale, ensuring that the value is at
510 // least 1. False is returned if the rounding operation resulted in a loss of precision.
511 // Negative numbers are rounded away from zero (-9 scale 1 rounds to -10).
512 func (q *Quantity) RoundUp(scale Scale) bool {
513         if q.d.Dec != nil {
514                 q.s = ""
515                 d, exact := q.d.AsScale(scale)
516                 q.d = d
517                 return exact
518         }
519         // avoid clearing the string value if we have already calculated it
520         if q.i.scale >= scale {
521                 return true
522         }
523         q.s = ""
524         i, exact := q.i.AsScale(scale)
525         q.i = i
526         return exact
527 }
528
529 // Add adds the provide y quantity to the current value. If the current value is zero,
530 // the format of the quantity will be updated to the format of y.
531 func (q *Quantity) Add(y Quantity) {
532         q.s = ""
533         if q.d.Dec == nil && y.d.Dec == nil {
534                 if q.i.value == 0 {
535                         q.Format = y.Format
536                 }
537                 if q.i.Add(y.i) {
538                         return
539                 }
540         } else if q.IsZero() {
541                 q.Format = y.Format
542         }
543         q.ToDec().d.Dec.Add(q.d.Dec, y.AsDec())
544 }
545
546 // Sub subtracts the provided quantity from the current value in place. If the current
547 // value is zero, the format of the quantity will be updated to the format of y.
548 func (q *Quantity) Sub(y Quantity) {
549         q.s = ""
550         if q.IsZero() {
551                 q.Format = y.Format
552         }
553         if q.d.Dec == nil && y.d.Dec == nil && q.i.Sub(y.i) {
554                 return
555         }
556         q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec())
557 }
558
559 // Cmp returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
560 // quantity is greater than y.
561 func (q *Quantity) Cmp(y Quantity) int {
562         if q.d.Dec == nil && y.d.Dec == nil {
563                 return q.i.Cmp(y.i)
564         }
565         return q.AsDec().Cmp(y.AsDec())
566 }
567
568 // CmpInt64 returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
569 // quantity is greater than y.
570 func (q *Quantity) CmpInt64(y int64) int {
571         if q.d.Dec != nil {
572                 return q.d.Dec.Cmp(inf.NewDec(y, inf.Scale(0)))
573         }
574         return q.i.Cmp(int64Amount{value: y})
575 }
576
577 // Neg sets quantity to be the negative value of itself.
578 func (q *Quantity) Neg() {
579         q.s = ""
580         if q.d.Dec == nil {
581                 q.i.value = -q.i.value
582                 return
583         }
584         q.d.Dec.Neg(q.d.Dec)
585 }
586
587 // int64QuantityExpectedBytes is the expected width in bytes of the canonical string representation
588 // of most Quantity values.
589 const int64QuantityExpectedBytes = 18
590
591 // String formats the Quantity as a string, caching the result if not calculated.
592 // String is an expensive operation and caching this result significantly reduces the cost of
593 // normal parse / marshal operations on Quantity.
594 func (q *Quantity) String() string {
595         if len(q.s) == 0 {
596                 result := make([]byte, 0, int64QuantityExpectedBytes)
597                 number, suffix := q.CanonicalizeBytes(result)
598                 number = append(number, suffix...)
599                 q.s = string(number)
600         }
601         return q.s
602 }
603
604 // MarshalJSON implements the json.Marshaller interface.
605 func (q Quantity) MarshalJSON() ([]byte, error) {
606         if len(q.s) > 0 {
607                 out := make([]byte, len(q.s)+2)
608                 out[0], out[len(out)-1] = '"', '"'
609                 copy(out[1:], q.s)
610                 return out, nil
611         }
612         result := make([]byte, int64QuantityExpectedBytes, int64QuantityExpectedBytes)
613         result[0] = '"'
614         number, suffix := q.CanonicalizeBytes(result[1:1])
615         // if the same slice was returned to us that we passed in, avoid another allocation by copying number into
616         // the source slice and returning that
617         if len(number) > 0 && &number[0] == &result[1] && (len(number)+len(suffix)+2) <= int64QuantityExpectedBytes {
618                 number = append(number, suffix...)
619                 number = append(number, '"')
620                 return result[:1+len(number)], nil
621         }
622         // if CanonicalizeBytes needed more space than our slice provided, we may need to allocate again so use
623         // append
624         result = result[:1]
625         result = append(result, number...)
626         result = append(result, suffix...)
627         result = append(result, '"')
628         return result, nil
629 }
630
631 // UnmarshalJSON implements the json.Unmarshaller interface.
632 // TODO: Remove support for leading/trailing whitespace
633 func (q *Quantity) UnmarshalJSON(value []byte) error {
634         l := len(value)
635         if l == 4 && bytes.Equal(value, []byte("null")) {
636                 q.d.Dec = nil
637                 q.i = int64Amount{}
638                 return nil
639         }
640         if l >= 2 && value[0] == '"' && value[l-1] == '"' {
641                 value = value[1 : l-1]
642         }
643
644         parsed, err := ParseQuantity(strings.TrimSpace(string(value)))
645         if err != nil {
646                 return err
647         }
648
649         // This copy is safe because parsed will not be referred to again.
650         *q = parsed
651         return nil
652 }
653
654 // NewQuantity returns a new Quantity representing the given
655 // value in the given format.
656 func NewQuantity(value int64, format Format) *Quantity {
657         return &Quantity{
658                 i:      int64Amount{value: value},
659                 Format: format,
660         }
661 }
662
663 // NewMilliQuantity returns a new Quantity representing the given
664 // value * 1/1000 in the given format. Note that BinarySI formatting
665 // will round fractional values, and will be changed to DecimalSI for
666 // values x where (-1 < x < 1) && (x != 0).
667 func NewMilliQuantity(value int64, format Format) *Quantity {
668         return &Quantity{
669                 i:      int64Amount{value: value, scale: -3},
670                 Format: format,
671         }
672 }
673
674 // NewScaledQuantity returns a new Quantity representing the given
675 // value * 10^scale in DecimalSI format.
676 func NewScaledQuantity(value int64, scale Scale) *Quantity {
677         return &Quantity{
678                 i:      int64Amount{value: value, scale: scale},
679                 Format: DecimalSI,
680         }
681 }
682
683 // Value returns the value of q; any fractional part will be lost.
684 func (q *Quantity) Value() int64 {
685         return q.ScaledValue(0)
686 }
687
688 // MilliValue returns the value of ceil(q * 1000); this could overflow an int64;
689 // if that's a concern, call Value() first to verify the number is small enough.
690 func (q *Quantity) MilliValue() int64 {
691         return q.ScaledValue(Milli)
692 }
693
694 // ScaledValue returns the value of ceil(q * 10^scale); this could overflow an int64.
695 // To detect overflow, call Value() first and verify the expected magnitude.
696 func (q *Quantity) ScaledValue(scale Scale) int64 {
697         if q.d.Dec == nil {
698                 i, _ := q.i.AsScaledInt64(scale)
699                 return i
700         }
701         dec := q.d.Dec
702         return scaledValue(dec.UnscaledBig(), int(dec.Scale()), int(scale.infScale()))
703 }
704
705 // Set sets q's value to be value.
706 func (q *Quantity) Set(value int64) {
707         q.SetScaled(value, 0)
708 }
709
710 // SetMilli sets q's value to be value * 1/1000.
711 func (q *Quantity) SetMilli(value int64) {
712         q.SetScaled(value, Milli)
713 }
714
715 // SetScaled sets q's value to be value * 10^scale
716 func (q *Quantity) SetScaled(value int64, scale Scale) {
717         q.s = ""
718         q.d.Dec = nil
719         q.i = int64Amount{value: value, scale: scale}
720 }
721
722 // Copy is a convenience function that makes a deep copy for you. Non-deep
723 // copies of quantities share pointers and you will regret that.
724 func (q *Quantity) Copy() *Quantity {
725         if q.d.Dec == nil {
726                 return &Quantity{
727                         s:      q.s,
728                         i:      q.i,
729                         Format: q.Format,
730                 }
731         }
732         tmp := &inf.Dec{}
733         return &Quantity{
734                 s:      q.s,
735                 d:      infDecAmount{tmp.Set(q.d.Dec)},
736                 Format: q.Format,
737         }
738 }