quantity.go 25 KB

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