quantity.go 22 KB

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