aboutsummaryrefslogtreecommitdiffstats
path: root/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/resource/quantity.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/resource/quantity.go')
-rw-r--r--src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/resource/quantity.go777
1 files changed, 777 insertions, 0 deletions
diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/resource/quantity.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/resource/quantity.go
new file mode 100644
index 0000000..823dd5e
--- /dev/null
+++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/resource/quantity.go
@@ -0,0 +1,777 @@
+/*
+Copyright 2014 The Kubernetes 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 resource
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "math/big"
+ "regexp"
+ "strconv"
+ "strings"
+
+ flag "github.com/spf13/pflag"
+
+ inf "gopkg.in/inf.v0"
+)
+
+// Quantity is a fixed-point representation of a number.
+// It provides convenient marshaling/unmarshaling in JSON and YAML,
+// in addition to String() and Int64() accessors.
+//
+// The serialization format is:
+//
+// <quantity> ::= <signedNumber><suffix>
+// (Note that <suffix> may be empty, from the "" case in <decimalSI>.)
+// <digit> ::= 0 | 1 | ... | 9
+// <digits> ::= <digit> | <digit><digits>
+// <number> ::= <digits> | <digits>.<digits> | <digits>. | .<digits>
+// <sign> ::= "+" | "-"
+// <signedNumber> ::= <number> | <sign><number>
+// <suffix> ::= <binarySI> | <decimalExponent> | <decimalSI>
+// <binarySI> ::= Ki | Mi | Gi | Ti | Pi | Ei
+// (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)
+// <decimalSI> ::= m | "" | k | M | G | T | P | E
+// (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)
+// <decimalExponent> ::= "e" <signedNumber> | "E" <signedNumber>
+//
+// No matter which of the three exponent forms is used, no quantity may represent
+// a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal
+// places. Numbers larger or more precise will be capped or rounded up.
+// (E.g.: 0.1m will rounded up to 1m.)
+// This may be extended in the future if we require larger or smaller quantities.
+//
+// When a Quantity is parsed from a string, it will remember the type of suffix
+// it had, and will use the same type again when it is serialized.
+//
+// Before serializing, Quantity will be put in "canonical form".
+// This means that Exponent/suffix will be adjusted up or down (with a
+// corresponding increase or decrease in Mantissa) such that:
+// a. No precision is lost
+// b. No fractional digits will be emitted
+// c. The exponent (or suffix) is as large as possible.
+// The sign will be omitted unless the number is negative.
+//
+// Examples:
+// 1.5 will be serialized as "1500m"
+// 1.5Gi will be serialized as "1536Mi"
+//
+// NOTE: We reserve the right to amend this canonical format, perhaps to
+// allow 1.5 to be canonical.
+// TODO: Remove above disclaimer after all bikeshedding about format is over,
+// or after March 2015.
+//
+// Note that the quantity will NEVER be internally represented by a
+// floating point number. That is the whole point of this exercise.
+//
+// Non-canonical values will still parse as long as they are well formed,
+// but will be re-emitted in their canonical form. (So always use canonical
+// form, or don't diff.)
+//
+// This format is intended to make it difficult to use these numbers without
+// writing some sort of special handling code in the hopes that that will
+// cause implementors to also use a fixed point implementation.
+//
+// +protobuf=true
+// +protobuf.embed=string
+// +protobuf.options.marshal=false
+// +protobuf.options.(gogoproto.goproto_stringer)=false
+type Quantity struct {
+ // i is the quantity in int64 scaled form, if d.Dec == nil
+ i int64Amount
+ // d is the quantity in inf.Dec form if d.Dec != nil
+ d infDecAmount
+ // s is the generated value of this quantity to avoid recalculation
+ s string
+
+ // Change Format at will. See the comment for Canonicalize for
+ // more details.
+ Format
+}
+
+// CanonicalValue allows a quantity amount to be converted to a string.
+type CanonicalValue interface {
+ // AsCanonicalBytes returns a byte array representing the string representation
+ // of the value mantissa and an int32 representing its exponent in base-10. Callers may
+ // pass a byte slice to the method to avoid allocations.
+ AsCanonicalBytes(out []byte) ([]byte, int32)
+ // AsCanonicalBase1024Bytes returns a byte array representing the string representation
+ // of the value mantissa and an int32 representing its exponent in base-1024. Callers
+ // may pass a byte slice to the method to avoid allocations.
+ AsCanonicalBase1024Bytes(out []byte) ([]byte, int32)
+}
+
+// Format lists the three possible formattings of a quantity.
+type Format string
+
+const (
+ DecimalExponent = Format("DecimalExponent") // e.g., 12e6
+ BinarySI = Format("BinarySI") // e.g., 12Mi (12 * 2^20)
+ DecimalSI = Format("DecimalSI") // e.g., 12M (12 * 10^6)
+)
+
+// MustParse turns the given string into a quantity or panics; for tests
+// or others cases where you know the string is valid.
+func MustParse(str string) Quantity {
+ q, err := ParseQuantity(str)
+ if err != nil {
+ panic(fmt.Errorf("cannot parse '%v': %v", str, err))
+ }
+ return q
+}
+
+const (
+ // splitREString is used to separate a number from its suffix; as such,
+ // this is overly permissive, but that's OK-- it will be checked later.
+ splitREString = "^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$"
+)
+
+var (
+ // splitRE is used to get the various parts of a number.
+ splitRE = regexp.MustCompile(splitREString)
+
+ // Errors that could happen while parsing a string.
+ ErrFormatWrong = errors.New("quantities must match the regular expression '" + splitREString + "'")
+ ErrNumeric = errors.New("unable to parse numeric part of quantity")
+ ErrSuffix = errors.New("unable to parse quantity's suffix")
+)
+
+// parseQuantityString is a fast scanner for quantity values.
+func parseQuantityString(str string) (positive bool, value, num, denom, suffix string, err error) {
+ positive = true
+ pos := 0
+ end := len(str)
+
+ // handle leading sign
+ if pos < end {
+ switch str[0] {
+ case '-':
+ positive = false
+ pos++
+ case '+':
+ pos++
+ }
+ }
+
+ // strip leading zeros
+Zeroes:
+ for i := pos; ; i++ {
+ if i >= end {
+ num = "0"
+ value = num
+ return
+ }
+ switch str[i] {
+ case '0':
+ pos++
+ default:
+ break Zeroes
+ }
+ }
+
+ // extract the numerator
+Num:
+ for i := pos; ; i++ {
+ if i >= end {
+ num = str[pos:end]
+ value = str[0:end]
+ return
+ }
+ switch str[i] {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ default:
+ num = str[pos:i]
+ pos = i
+ break Num
+ }
+ }
+
+ // if we stripped all numerator positions, always return 0
+ if len(num) == 0 {
+ num = "0"
+ }
+
+ // handle a denominator
+ if pos < end && str[pos] == '.' {
+ pos++
+ Denom:
+ for i := pos; ; i++ {
+ if i >= end {
+ denom = str[pos:end]
+ value = str[0:end]
+ return
+ }
+ switch str[i] {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ default:
+ denom = str[pos:i]
+ pos = i
+ break Denom
+ }
+ }
+ // TODO: we currently allow 1.G, but we may not want to in the future.
+ // if len(denom) == 0 {
+ // err = ErrFormatWrong
+ // return
+ // }
+ }
+ value = str[0:pos]
+
+ // grab the elements of the suffix
+ suffixStart := pos
+ for i := pos; ; i++ {
+ if i >= end {
+ suffix = str[suffixStart:end]
+ return
+ }
+ if !strings.ContainsAny(str[i:i+1], "eEinumkKMGTP") {
+ pos = i
+ break
+ }
+ }
+ if pos < end {
+ switch str[pos] {
+ case '-', '+':
+ pos++
+ }
+ }
+Suffix:
+ for i := pos; ; i++ {
+ if i >= end {
+ suffix = str[suffixStart:end]
+ return
+ }
+ switch str[i] {
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ default:
+ break Suffix
+ }
+ }
+ // we encountered a non decimal in the Suffix loop, but the last character
+ // was not a valid exponent
+ err = ErrFormatWrong
+ return
+}
+
+// ParseQuantity turns str into a Quantity, or returns an error.
+func ParseQuantity(str string) (Quantity, error) {
+ if len(str) == 0 {
+ return Quantity{}, ErrFormatWrong
+ }
+ if str == "0" {
+ return Quantity{Format: DecimalSI, s: str}, nil
+ }
+
+ positive, value, num, denom, suf, err := parseQuantityString(str)
+ if err != nil {
+ return Quantity{}, err
+ }
+
+ base, exponent, format, ok := quantitySuffixer.interpret(suffix(suf))
+ if !ok {
+ return Quantity{}, ErrSuffix
+ }
+
+ precision := int32(0)
+ scale := int32(0)
+ mantissa := int64(1)
+ switch format {
+ case DecimalExponent, DecimalSI:
+ scale = exponent
+ precision = maxInt64Factors - int32(len(num)+len(denom))
+ case BinarySI:
+ scale = 0
+ switch {
+ case exponent >= 0 && len(denom) == 0:
+ // only handle positive binary numbers with the fast path
+ mantissa = int64(int64(mantissa) << uint64(exponent))
+ // 1Mi (2^20) has ~6 digits of decimal precision, so exponent*3/10 -1 is roughly the precision
+ precision = 15 - int32(len(num)) - int32(float32(exponent)*3/10) - 1
+ default:
+ precision = -1
+ }
+ }
+
+ if precision >= 0 {
+ // if we have a denominator, shift the entire value to the left by the number of places in the
+ // denominator
+ scale -= int32(len(denom))
+ if scale >= int32(Nano) {
+ shifted := num + denom
+
+ var value int64
+ value, err := strconv.ParseInt(shifted, 10, 64)
+ if err != nil {
+ return Quantity{}, ErrNumeric
+ }
+ if result, ok := int64Multiply(value, int64(mantissa)); ok {
+ if !positive {
+ result = -result
+ }
+ // if the number is in canonical form, reuse the string
+ switch format {
+ case BinarySI:
+ if exponent%10 == 0 && (value&0x07 != 0) {
+ return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil
+ }
+ default:
+ if scale%3 == 0 && !strings.HasSuffix(shifted, "000") && shifted[0] != '0' {
+ return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format, s: str}, nil
+ }
+ }
+ return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format}, nil
+ }
+ }
+ }
+
+ amount := new(inf.Dec)
+ if _, ok := amount.SetString(value); !ok {
+ return Quantity{}, ErrNumeric
+ }
+
+ // So that no one but us has to think about suffixes, remove it.
+ if base == 10 {
+ amount.SetScale(amount.Scale() + Scale(exponent).infScale())
+ } else if base == 2 {
+ // numericSuffix = 2 ** exponent
+ numericSuffix := big.NewInt(1).Lsh(bigOne, uint(exponent))
+ ub := amount.UnscaledBig()
+ amount.SetUnscaledBig(ub.Mul(ub, numericSuffix))
+ }
+
+ // Cap at min/max bounds.
+ sign := amount.Sign()
+ if sign == -1 {
+ amount.Neg(amount)
+ }
+
+ // This rounds non-zero values up to the minimum representable value, under the theory that
+ // if you want some resources, you should get some resources, even if you asked for way too small
+ // of an amount. Arguably, this should be inf.RoundHalfUp (normal rounding), but that would have
+ // the side effect of rounding values < .5n to zero.
+ if v, ok := amount.Unscaled(); v != int64(0) || !ok {
+ amount.Round(amount, Nano.infScale(), inf.RoundUp)
+ }
+
+ // The max is just a simple cap.
+ // TODO: this prevents accumulating quantities greater than int64, for instance quota across a cluster
+ if format == BinarySI && amount.Cmp(maxAllowed.Dec) > 0 {
+ amount.Set(maxAllowed.Dec)
+ }
+
+ if format == BinarySI && amount.Cmp(decOne) < 0 && amount.Cmp(decZero) > 0 {
+ // This avoids rounding and hopefully confusion, too.
+ format = DecimalSI
+ }
+ if sign == -1 {
+ amount.Neg(amount)
+ }
+
+ return Quantity{d: infDecAmount{amount}, Format: format}, nil
+}
+
+// DeepCopy returns a deep-copy of the Quantity value. Note that the method
+// receiver is a value, so we can mutate it in-place and return it.
+func (q Quantity) DeepCopy() Quantity {
+ if q.d.Dec != nil {
+ tmp := &inf.Dec{}
+ q.d.Dec = tmp.Set(q.d.Dec)
+ }
+ return q
+}
+
+// CanonicalizeBytes returns the canonical form of q and its suffix (see comment on Quantity).
+//
+// Note about BinarySI:
+// * If q.Format is set to BinarySI and q.Amount represents a non-zero value between
+// -1 and +1, it will be emitted as if q.Format were DecimalSI.
+// * Otherwise, if q.Format is set to BinarySI, frational parts of q.Amount will be
+// rounded up. (1.1i becomes 2i.)
+func (q *Quantity) CanonicalizeBytes(out []byte) (result, suffix []byte) {
+ if q.IsZero() {
+ return zeroBytes, nil
+ }
+
+ var rounded CanonicalValue
+ format := q.Format
+ switch format {
+ case DecimalExponent, DecimalSI:
+ case BinarySI:
+ if q.CmpInt64(-1024) > 0 && q.CmpInt64(1024) < 0 {
+ // This avoids rounding and hopefully confusion, too.
+ format = DecimalSI
+ } else {
+ var exact bool
+ if rounded, exact = q.AsScale(0); !exact {
+ // Don't lose precision-- show as DecimalSI
+ format = DecimalSI
+ }
+ }
+ default:
+ format = DecimalExponent
+ }
+
+ // TODO: If BinarySI formatting is requested but would cause rounding, upgrade to
+ // one of the other formats.
+ switch format {
+ case DecimalExponent, DecimalSI:
+ number, exponent := q.AsCanonicalBytes(out)
+ suffix, _ := quantitySuffixer.constructBytes(10, exponent, format)
+ return number, suffix
+ default:
+ // format must be BinarySI
+ number, exponent := rounded.AsCanonicalBase1024Bytes(out)
+ suffix, _ := quantitySuffixer.constructBytes(2, exponent*10, format)
+ return number, suffix
+ }
+}
+
+// AsInt64 returns a representation of the current value as an int64 if a fast conversion
+// is possible. If false is returned, callers must use the inf.Dec form of this quantity.
+func (q *Quantity) AsInt64() (int64, bool) {
+ if q.d.Dec != nil {
+ return 0, false
+ }
+ return q.i.AsInt64()
+}
+
+// ToDec promotes the quantity in place to use an inf.Dec representation and returns itself.
+func (q *Quantity) ToDec() *Quantity {
+ if q.d.Dec == nil {
+ q.d.Dec = q.i.AsDec()
+ q.i = int64Amount{}
+ }
+ return q
+}
+
+// AsDec returns the quantity as represented by a scaled inf.Dec.
+func (q *Quantity) AsDec() *inf.Dec {
+ if q.d.Dec != nil {
+ return q.d.Dec
+ }
+ q.d.Dec = q.i.AsDec()
+ q.i = int64Amount{}
+ return q.d.Dec
+}
+
+// AsCanonicalBytes returns the canonical byte representation of this quantity as a mantissa
+// and base 10 exponent. The out byte slice may be passed to the method to avoid an extra
+// allocation.
+func (q *Quantity) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
+ if q.d.Dec != nil {
+ return q.d.AsCanonicalBytes(out)
+ }
+ return q.i.AsCanonicalBytes(out)
+}
+
+// IsZero returns true if the quantity is equal to zero.
+func (q *Quantity) IsZero() bool {
+ if q.d.Dec != nil {
+ return q.d.Dec.Sign() == 0
+ }
+ return q.i.value == 0
+}
+
+// Sign returns 0 if the quantity is zero, -1 if the quantity is less than zero, or 1 if the
+// quantity is greater than zero.
+func (q *Quantity) Sign() int {
+ if q.d.Dec != nil {
+ return q.d.Dec.Sign()
+ }
+ return q.i.Sign()
+}
+
+// AsScaled returns the current value, rounded up to the provided scale, and returns
+// false if the scale resulted in a loss of precision.
+func (q *Quantity) AsScale(scale Scale) (CanonicalValue, bool) {
+ if q.d.Dec != nil {
+ return q.d.AsScale(scale)
+ }
+ return q.i.AsScale(scale)
+}
+
+// RoundUp updates the quantity to the provided scale, ensuring that the value is at
+// least 1. False is returned if the rounding operation resulted in a loss of precision.
+// Negative numbers are rounded away from zero (-9 scale 1 rounds to -10).
+func (q *Quantity) RoundUp(scale Scale) bool {
+ if q.d.Dec != nil {
+ q.s = ""
+ d, exact := q.d.AsScale(scale)
+ q.d = d
+ return exact
+ }
+ // avoid clearing the string value if we have already calculated it
+ if q.i.scale >= scale {
+ return true
+ }
+ q.s = ""
+ i, exact := q.i.AsScale(scale)
+ q.i = i
+ return exact
+}
+
+// Add adds the provide y quantity to the current value. If the current value is zero,
+// the format of the quantity will be updated to the format of y.
+func (q *Quantity) Add(y Quantity) {
+ q.s = ""
+ if q.d.Dec == nil && y.d.Dec == nil {
+ if q.i.value == 0 {
+ q.Format = y.Format
+ }
+ if q.i.Add(y.i) {
+ return
+ }
+ } else if q.IsZero() {
+ q.Format = y.Format
+ }
+ q.ToDec().d.Dec.Add(q.d.Dec, y.AsDec())
+}
+
+// Sub subtracts the provided quantity from the current value in place. If the current
+// value is zero, the format of the quantity will be updated to the format of y.
+func (q *Quantity) Sub(y Quantity) {
+ q.s = ""
+ if q.IsZero() {
+ q.Format = y.Format
+ }
+ if q.d.Dec == nil && y.d.Dec == nil && q.i.Sub(y.i) {
+ return
+ }
+ q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec())
+}
+
+// Cmp returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
+// quantity is greater than y.
+func (q *Quantity) Cmp(y Quantity) int {
+ if q.d.Dec == nil && y.d.Dec == nil {
+ return q.i.Cmp(y.i)
+ }
+ return q.AsDec().Cmp(y.AsDec())
+}
+
+// CmpInt64 returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
+// quantity is greater than y.
+func (q *Quantity) CmpInt64(y int64) int {
+ if q.d.Dec != nil {
+ return q.d.Dec.Cmp(inf.NewDec(y, inf.Scale(0)))
+ }
+ return q.i.Cmp(int64Amount{value: y})
+}
+
+// Neg sets quantity to be the negative value of itself.
+func (q *Quantity) Neg() {
+ q.s = ""
+ if q.d.Dec == nil {
+ q.i.value = -q.i.value
+ return
+ }
+ q.d.Dec.Neg(q.d.Dec)
+}
+
+// int64QuantityExpectedBytes is the expected width in bytes of the canonical string representation
+// of most Quantity values.
+const int64QuantityExpectedBytes = 18
+
+// String formats the Quantity as a string, caching the result if not calculated.
+// String is an expensive operation and caching this result significantly reduces the cost of
+// normal parse / marshal operations on Quantity.
+func (q *Quantity) String() string {
+ if len(q.s) == 0 {
+ result := make([]byte, 0, int64QuantityExpectedBytes)
+ number, suffix := q.CanonicalizeBytes(result)
+ number = append(number, suffix...)
+ q.s = string(number)
+ }
+ return q.s
+}
+
+// MarshalJSON implements the json.Marshaller interface.
+func (q Quantity) MarshalJSON() ([]byte, error) {
+ if len(q.s) > 0 {
+ out := make([]byte, len(q.s)+2)
+ out[0], out[len(out)-1] = '"', '"'
+ copy(out[1:], q.s)
+ return out, nil
+ }
+ result := make([]byte, int64QuantityExpectedBytes, int64QuantityExpectedBytes)
+ result[0] = '"'
+ number, suffix := q.CanonicalizeBytes(result[1:1])
+ // if the same slice was returned to us that we passed in, avoid another allocation by copying number into
+ // the source slice and returning that
+ if len(number) > 0 && &number[0] == &result[1] && (len(number)+len(suffix)+2) <= int64QuantityExpectedBytes {
+ number = append(number, suffix...)
+ number = append(number, '"')
+ return result[:1+len(number)], nil
+ }
+ // if CanonicalizeBytes needed more space than our slice provided, we may need to allocate again so use
+ // append
+ result = result[:1]
+ result = append(result, number...)
+ result = append(result, suffix...)
+ result = append(result, '"')
+ return result, nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface.
+// TODO: Remove support for leading/trailing whitespace
+func (q *Quantity) UnmarshalJSON(value []byte) error {
+ l := len(value)
+ if l == 4 && bytes.Equal(value, []byte("null")) {
+ q.d.Dec = nil
+ q.i = int64Amount{}
+ return nil
+ }
+ if l >= 2 && value[0] == '"' && value[l-1] == '"' {
+ value = value[1 : l-1]
+ }
+
+ parsed, err := ParseQuantity(strings.TrimSpace(string(value)))
+ if err != nil {
+ return err
+ }
+
+ // This copy is safe because parsed will not be referred to again.
+ *q = parsed
+ return nil
+}
+
+// NewQuantity returns a new Quantity representing the given
+// value in the given format.
+func NewQuantity(value int64, format Format) *Quantity {
+ return &Quantity{
+ i: int64Amount{value: value},
+ Format: format,
+ }
+}
+
+// NewMilliQuantity returns a new Quantity representing the given
+// value * 1/1000 in the given format. Note that BinarySI formatting
+// will round fractional values, and will be changed to DecimalSI for
+// values x where (-1 < x < 1) && (x != 0).
+func NewMilliQuantity(value int64, format Format) *Quantity {
+ return &Quantity{
+ i: int64Amount{value: value, scale: -3},
+ Format: format,
+ }
+}
+
+// NewScaledQuantity returns a new Quantity representing the given
+// value * 10^scale in DecimalSI format.
+func NewScaledQuantity(value int64, scale Scale) *Quantity {
+ return &Quantity{
+ i: int64Amount{value: value, scale: scale},
+ Format: DecimalSI,
+ }
+}
+
+// Value returns the value of q; any fractional part will be lost.
+func (q *Quantity) Value() int64 {
+ return q.ScaledValue(0)
+}
+
+// MilliValue returns the value of ceil(q * 1000); this could overflow an int64;
+// if that's a concern, call Value() first to verify the number is small enough.
+func (q *Quantity) MilliValue() int64 {
+ return q.ScaledValue(Milli)
+}
+
+// ScaledValue returns the value of ceil(q * 10^scale); this could overflow an int64.
+// To detect overflow, call Value() first and verify the expected magnitude.
+func (q *Quantity) ScaledValue(scale Scale) int64 {
+ if q.d.Dec == nil {
+ i, _ := q.i.AsScaledInt64(scale)
+ return i
+ }
+ dec := q.d.Dec
+ return scaledValue(dec.UnscaledBig(), int(dec.Scale()), int(scale.infScale()))
+}
+
+// Set sets q's value to be value.
+func (q *Quantity) Set(value int64) {
+ q.SetScaled(value, 0)
+}
+
+// SetMilli sets q's value to be value * 1/1000.
+func (q *Quantity) SetMilli(value int64) {
+ q.SetScaled(value, Milli)
+}
+
+// SetScaled sets q's value to be value * 10^scale
+func (q *Quantity) SetScaled(value int64, scale Scale) {
+ q.s = ""
+ q.d.Dec = nil
+ q.i = int64Amount{value: value, scale: scale}
+}
+
+// Copy is a convenience function that makes a deep copy for you. Non-deep
+// copies of quantities share pointers and you will regret that.
+func (q *Quantity) Copy() *Quantity {
+ if q.d.Dec == nil {
+ return &Quantity{
+ s: q.s,
+ i: q.i,
+ Format: q.Format,
+ }
+ }
+ tmp := &inf.Dec{}
+ return &Quantity{
+ s: q.s,
+ d: infDecAmount{tmp.Set(q.d.Dec)},
+ Format: q.Format,
+ }
+}
+
+// qFlag is a helper type for the Flag function
+type qFlag struct {
+ dest *Quantity
+}
+
+// Sets the value of the internal Quantity. (used by flag & pflag)
+func (qf qFlag) Set(val string) error {
+ q, err := ParseQuantity(val)
+ if err != nil {
+ return err
+ }
+ // This copy is OK because q will not be referenced again.
+ *qf.dest = q
+ return nil
+}
+
+// Converts the value of the internal Quantity to a string. (used by flag & pflag)
+func (qf qFlag) String() string {
+ return qf.dest.String()
+}
+
+// States the type of flag this is (Quantity). (used by pflag)
+func (qf qFlag) Type() string {
+ return "quantity"
+}
+
+// QuantityFlag is a helper that makes a quantity flag (using standard flag package).
+// Will panic if defaultValue is not a valid quantity.
+func QuantityFlag(flagName, defaultValue, description string) *Quantity {
+ q := MustParse(defaultValue)
+ flag.Var(NewQuantityFlagValue(&q), flagName, description)
+ return &q
+}
+
+// NewQuantityFlagValue returns an object that can be used to back a flag,
+// pointing at the given Quantity variable.
+func NewQuantityFlagValue(q *Quantity) flag.Value {
+ return qFlag{q}
+}