Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
2d2df559
Commit
2d2df559
authored
Jan 06, 2015
by
Daniel Smith
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add examples & clarify comments further
parent
b7b2ee34
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
118 additions
and
39 deletions
+118
-39
quantity.go
pkg/api/resource/quantity.go
+55
-39
quantity_example_test.go
pkg/api/resource/quantity_example_test.go
+59
-0
quantity_test.go
pkg/api/resource/quantity_test.go
+4
-0
No files found.
pkg/api/resource/quantity.go
View file @
2d2df559
...
@@ -33,18 +33,19 @@ import (
...
@@ -33,18 +33,19 @@ import (
//
//
// The serialization format is:
// The serialization format is:
//
//
// <serialized> ::= <sign><numeric> | <numeric>
// <quantity> ::= <signedNumber><suffix>
// <numeric> ::= <digits><suffix> | <digits>.<digits><suffix>
// (Note that <suffix> may be empty, from the "" case in <decimalSI>.)
// (Note that <suffix> may be ""!)
// <sign> ::= "+" | "-"
// <digits> ::= <digit> | <digit><digits>
// <signedDigits> ::= <digits> | <sign><digits>
// <digit> ::= 0 | 1 | ... | 9
// <digit> ::= 0 | 1 | ... | 9
// <suffix> ::= <binarySuffix> | <decimalExponent> | <decimalSuffix>
// <digits> ::= <digit> | <digit><digits>
// <binarySuffix> ::= i | Ki | Mi | Gi | Ti | Pi | Ei
// <number> ::= <digits> | <digits>.<digits> | <digits>. | .<digits>
// <decimalSuffix> ::= m | "" | k | M | G | T | P | E
// <sign> ::= "+" | "-"
// <decimalExponent> ::= "e" <signedDigits> | "E" <signedDigits>
// <signedNumber> ::= <number> | <sign><number>
// <suffix> ::= <binarySI> | <decimalExponent> | <decimalSI>
// <binarySI> ::= i | 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.)
// (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
// 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 digits
// a number greater than 2^63-1 in magnitude, nor may it have more than 3 digits
...
@@ -54,7 +55,7 @@ import (
...
@@ -54,7 +55,7 @@ import (
//
//
// When a Quantity is parsed from a string, it will remember the type of suffix
// 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.
// it had, and will use the same type again when it is serialized.
// One exception: numbers with a Binary SI suffix less than
o
ne will be changed
// One exception: numbers with a Binary SI suffix less than
bigO
ne will be changed
// to Decimal SI suffix. E.g., .5i becomes 500m. [NOT 512m!]
// to Decimal SI suffix. E.g., .5i becomes 500m. [NOT 512m!]
//
//
// Before serializing, Quantity will be put in "canonical form".
// Before serializing, Quantity will be put in "canonical form".
...
@@ -67,7 +68,12 @@ import (
...
@@ -67,7 +68,12 @@ import (
//
//
// Examples:
// Examples:
// 1.5 will be serialized as "1500m"
// 1.5 will be serialized as "1500m"
// 1.5Gi will be serialized as "1576Mi"
// 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
// Note that the quantity will NEVER be internally represented by a
// floating point number. That is the whole point of this exercise.
// floating point number. That is the whole point of this exercise.
...
@@ -93,16 +99,25 @@ type Quantity struct {
...
@@ -93,16 +99,25 @@ type Quantity struct {
type
Format
string
type
Format
string
const
(
const
(
DecimalExponent
=
Format
(
"DecExponent"
)
DecimalExponent
=
Format
(
"DecimalExponent"
)
// e.g., 12e6
// SI = International System of units.
BinarySI
=
Format
(
"BinarySI"
)
// e.g., 12Mi (12 * 2^20)
BinarySI
=
Format
(
"BinSI"
)
DecimalSI
=
Format
(
"DecimalSI"
)
// e.g., 12M (12 * 10^6)
DecimalSI
=
Format
(
"DecSI"
)
)
)
// ParseOrDie turns the given string into a quantity or panics; for tests
// or others cases where you know the string is valid.
func
ParseOrDie
(
str
string
)
*
Quantity
{
q
,
err
:=
ParseQuantity
(
str
)
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"cannot parse '%v': %v"
,
str
,
err
))
}
return
q
}
const
(
const
(
// splitREString is used to separate a number from its suffix; as such,
// 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.
// this is overly permissive, but that's OK-- it will be checked later.
splitREString
=
"^([+-]?[0
123456789.]+)([eEimkKMGTP]*[-+]?[012345678
9]*)$"
splitREString
=
"^([+-]?[0
-9.]+)([eEimkKMGTP]*[-+]?[0-
9]*)$"
)
)
var
(
var
(
...
@@ -115,11 +130,11 @@ var (
...
@@ -115,11 +130,11 @@ var (
ErrSuffix
=
errors
.
New
(
"unable to parse quantity's suffix"
)
ErrSuffix
=
errors
.
New
(
"unable to parse quantity's suffix"
)
// Commonly needed big.Int values-- treat as read only!
// Commonly needed big.Int values-- treat as read only!
t
en
=
big
.
NewInt
(
10
)
bigT
en
=
big
.
NewInt
(
10
)
z
ero
=
big
.
NewInt
(
0
)
bigZ
ero
=
big
.
NewInt
(
0
)
o
ne
=
big
.
NewInt
(
1
)
bigO
ne
=
big
.
NewInt
(
1
)
t
housand
=
big
.
NewInt
(
1000
)
bigT
housand
=
big
.
NewInt
(
1000
)
ten24
=
big
.
NewInt
(
1024
)
big1024
=
big
.
NewInt
(
1024
)
// Commonly needed inf.Dec values-- treat as read only!
// Commonly needed inf.Dec values-- treat as read only!
decZero
=
inf
.
NewDec
(
0
,
0
)
decZero
=
inf
.
NewDec
(
0
,
0
)
...
@@ -127,8 +142,7 @@ var (
...
@@ -127,8 +142,7 @@ var (
decMinusOne
=
inf
.
NewDec
(
-
1
,
0
)
decMinusOne
=
inf
.
NewDec
(
-
1
,
0
)
decThousand
=
inf
.
NewDec
(
1000
,
0
)
decThousand
=
inf
.
NewDec
(
1000
,
0
)
// Smallest and largest (in magnitude) numbers allowed.
// Largest (in magnitude) number allowed.
minAllowed
=
inf
.
NewDec
(
1
,
3
)
// == 1/1000
maxAllowed
=
inf
.
NewDec
((
1
<<
63
)
-
1
,
0
)
// == max int64
maxAllowed
=
inf
.
NewDec
((
1
<<
63
)
-
1
,
0
)
// == max int64
// The maximum value we can represent milli-units for.
// The maximum value we can represent milli-units for.
...
@@ -140,6 +154,7 @@ var (
...
@@ -140,6 +154,7 @@ var (
// ParseQuantity turns str into a Quantity, or returns an error.
// ParseQuantity turns str into a Quantity, or returns an error.
func
ParseQuantity
(
str
string
)
(
*
Quantity
,
error
)
{
func
ParseQuantity
(
str
string
)
(
*
Quantity
,
error
)
{
parts
:=
splitRE
.
FindStringSubmatch
(
strings
.
TrimSpace
(
str
))
parts
:=
splitRE
.
FindStringSubmatch
(
strings
.
TrimSpace
(
str
))
// regexp returns are entire match, followed by an entry for each () section.
if
len
(
parts
)
!=
3
{
if
len
(
parts
)
!=
3
{
return
nil
,
ErrFormatWrong
return
nil
,
ErrFormatWrong
}
}
...
@@ -154,13 +169,14 @@ func ParseQuantity(str string) (*Quantity, error) {
...
@@ -154,13 +169,14 @@ func ParseQuantity(str string) (*Quantity, error) {
return
nil
,
ErrSuffix
return
nil
,
ErrSuffix
}
}
// So that no
o
ne but us has to think about suffixes, remove it.
// So that no
bigO
ne but us has to think about suffixes, remove it.
if
base
==
10
{
if
base
==
10
{
amount
.
SetScale
(
amount
.
Scale
()
+
inf
.
Scale
(
-
exponent
))
amount
.
SetScale
(
amount
.
Scale
()
+
inf
.
Scale
(
-
exponent
))
}
else
if
base
==
2
{
}
else
if
base
==
2
{
// numericSuffix = 2 ** exponent
// numericSuffix = 2 ** exponent
numericSuffix
:=
big
.
NewInt
(
1
)
.
Lsh
(
one
,
uint
(
exponent
))
numericSuffix
:=
big
.
NewInt
(
1
)
.
Lsh
(
bigOne
,
uint
(
exponent
))
amount
.
UnscaledBig
()
.
Mul
(
amount
.
UnscaledBig
(),
numericSuffix
)
ub
:=
amount
.
UnscaledBig
()
amount
.
SetUnscaledBig
(
ub
.
Mul
(
ub
,
numericSuffix
))
}
}
// Cap at min/max bounds.
// Cap at min/max bounds.
...
@@ -168,12 +184,12 @@ func ParseQuantity(str string) (*Quantity, error) {
...
@@ -168,12 +184,12 @@ func ParseQuantity(str string) (*Quantity, error) {
if
sign
==
-
1
{
if
sign
==
-
1
{
amount
.
Neg
(
amount
)
amount
.
Neg
(
amount
)
}
}
// This rounds non-
z
ero values up to the minimum representable
// This rounds non-
bigZ
ero values up to the minimum representable
// value, under the theory that if you want some resources, you
// value, under the theory that if you want some resources, you
// should get some resources, even if you asked for way too small
// should get some resources, even if you asked for way too small
// of an amount.
// of an amount.
// Arguably, this should be inf.RoundHalfUp (normal rounding), but
// Arguably, this should be inf.RoundHalfUp (normal rounding), but
// that would have the side effect of rounding values < .5m to
z
ero.
// that would have the side effect of rounding values < .5m to
bigZ
ero.
amount
.
Round
(
amount
,
3
,
inf
.
RoundUp
)
amount
.
Round
(
amount
,
3
,
inf
.
RoundUp
)
// The max is just a simple cap.
// The max is just a simple cap.
...
@@ -198,9 +214,9 @@ func ParseQuantity(str string) (*Quantity, error) {
...
@@ -198,9 +214,9 @@ func ParseQuantity(str string) (*Quantity, error) {
func
removeFactors
(
d
,
factor
*
big
.
Int
)
(
result
*
big
.
Int
,
times
int
)
{
func
removeFactors
(
d
,
factor
*
big
.
Int
)
(
result
*
big
.
Int
,
times
int
)
{
q
:=
big
.
NewInt
(
0
)
q
:=
big
.
NewInt
(
0
)
m
:=
big
.
NewInt
(
0
)
m
:=
big
.
NewInt
(
0
)
for
d
.
Cmp
(
z
ero
)
!=
0
{
for
d
.
Cmp
(
bigZ
ero
)
!=
0
{
q
.
DivMod
(
d
,
factor
,
m
)
q
.
DivMod
(
d
,
factor
,
m
)
if
m
.
Cmp
(
z
ero
)
!=
0
{
if
m
.
Cmp
(
bigZ
ero
)
!=
0
{
break
break
}
}
times
++
times
++
...
@@ -212,7 +228,7 @@ func removeFactors(d, factor *big.Int) (result *big.Int, times int) {
...
@@ -212,7 +228,7 @@ func removeFactors(d, factor *big.Int) (result *big.Int, times int) {
// Canonicalize returns the canonical form of q and its suffix (see comment on Quantity).
// Canonicalize returns the canonical form of q and its suffix (see comment on Quantity).
//
//
// Note about BinarySI:
// Note about BinarySI:
// * If q.Format is set to BinarySI and q.Amount represents a non-
z
ero value between
// * If q.Format is set to BinarySI and q.Amount represents a non-
bigZ
ero value between
// -1 and +1, it will be emitted as if q.Format were DecimalSI.
// -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
// * Otherwise, if q.Format is set to BinarySI, frational parts of q.Amount will be
// rounded up. (1.1i becomes 2i.)
// rounded up. (1.1i becomes 2i.)
...
@@ -243,19 +259,19 @@ func (q *Quantity) Canonicalize() (string, suffix) {
...
@@ -243,19 +259,19 @@ func (q *Quantity) Canonicalize() (string, suffix) {
}
}
// TODO: If BinarySI formatting is requested but would cause rounding, upgrade to
// TODO: If BinarySI formatting is requested but would cause rounding, upgrade to
//
o
ne of the other formats.
//
bigO
ne of the other formats.
switch
format
{
switch
format
{
case
DecimalExponent
,
DecimalSI
:
case
DecimalExponent
,
DecimalSI
:
mantissa
:=
q
.
Amount
.
UnscaledBig
()
mantissa
:=
q
.
Amount
.
UnscaledBig
()
exponent
:=
int
(
-
q
.
Amount
.
Scale
())
exponent
:=
int
(
-
q
.
Amount
.
Scale
())
amount
:=
big
.
NewInt
(
0
)
.
Set
(
mantissa
)
amount
:=
big
.
NewInt
(
0
)
.
Set
(
mantissa
)
// move all factors of 10 into the exponent for easy reasoning
// move all factors of 10 into the exponent for easy reasoning
amount
,
times
:=
removeFactors
(
amount
,
t
en
)
amount
,
times
:=
removeFactors
(
amount
,
bigT
en
)
exponent
+=
times
exponent
+=
times
// make sure exponent is a multiple of 3
// make sure exponent is a multiple of 3
for
exponent
%
3
!=
0
{
for
exponent
%
3
!=
0
{
amount
.
Mul
(
amount
,
t
en
)
amount
.
Mul
(
amount
,
bigT
en
)
exponent
--
exponent
--
}
}
...
@@ -264,18 +280,17 @@ func (q *Quantity) Canonicalize() (string, suffix) {
...
@@ -264,18 +280,17 @@ func (q *Quantity) Canonicalize() (string, suffix) {
return
number
,
suffix
return
number
,
suffix
case
BinarySI
:
case
BinarySI
:
tmp
:=
&
inf
.
Dec
{}
tmp
:=
&
inf
.
Dec
{}
//tmp.Set(q.Amount)
tmp
.
Round
(
q
.
Amount
,
0
,
inf
.
RoundUp
)
tmp
.
Round
(
q
.
Amount
,
0
,
inf
.
RoundUp
)
amount
:=
tmp
.
UnscaledBig
()
amount
:=
tmp
.
UnscaledBig
()
exponent
:=
int
(
-
q
.
Amount
.
Scale
())
exponent
:=
int
(
-
q
.
Amount
.
Scale
())
// Apply the (base-10) shift. This will lose any fractional
// Apply the (base-10) shift. This will lose any fractional
// part, which is intentional.
// part, which is intentional.
for
exponent
>
0
{
for
exponent
>
0
{
amount
.
Mul
(
amount
,
t
en
)
amount
.
Mul
(
amount
,
bigT
en
)
exponent
--
exponent
--
}
}
amount
,
exponent
=
removeFactors
(
amount
,
ten
24
)
amount
,
exponent
=
removeFactors
(
amount
,
big10
24
)
suffix
,
_
:=
quantitySuffixer
.
construct
(
2
,
exponent
*
10
,
format
)
suffix
,
_
:=
quantitySuffixer
.
construct
(
2
,
exponent
*
10
,
format
)
number
:=
amount
.
String
()
number
:=
amount
.
String
()
return
number
,
suffix
return
number
,
suffix
...
@@ -317,7 +332,8 @@ func NewQuantity(value int64, format Format) *Quantity {
...
@@ -317,7 +332,8 @@ func NewQuantity(value int64, format Format) *Quantity {
// NewMilliQuantity returns a new Quantity representing the given
// NewMilliQuantity returns a new Quantity representing the given
// value * 1/1000 in the given format. Note that BinarySI formatting
// value * 1/1000 in the given format. Note that BinarySI formatting
// will cause rounding for fractional values.
// 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
{
func
NewMilliQuantity
(
value
int64
,
format
Format
)
*
Quantity
{
return
&
Quantity
{
return
&
Quantity
{
Amount
:
inf
.
NewDec
(
value
,
3
),
Amount
:
inf
.
NewDec
(
value
,
3
),
...
...
pkg/api/resource/quantity_example_test.go
0 → 100644
View file @
2d2df559
/*
Copyright 2014 Google Inc. All rights reserved.
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_test
import
(
"fmt"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
)
func
ExampleFormat
()
{
memorySize
:=
resource
.
NewQuantity
(
5
*
1024
*
1024
*
1024
,
resource
.
BinarySI
)
fmt
.
Printf
(
"memorySize = %v
\n
"
,
memorySize
)
diskSize
:=
resource
.
NewQuantity
(
5
*
1000
*
1000
*
1000
,
resource
.
DecimalSI
)
fmt
.
Printf
(
"diskSize = %v
\n
"
,
diskSize
)
cores
:=
resource
.
NewMilliQuantity
(
5300
,
resource
.
DecimalSI
)
fmt
.
Printf
(
"cores = %v
\n
"
,
cores
)
// Output:
// memorySize = 5Gi
// diskSize = 5G
// cores = 5300m
}
func
ExampleParseOrDie
()
{
memorySize
:=
resource
.
ParseOrDie
(
"5Gi"
)
fmt
.
Printf
(
"memorySize = %v (%v)
\n
"
,
memorySize
.
Value
(),
memorySize
.
Format
)
diskSize
:=
resource
.
ParseOrDie
(
"5G"
)
fmt
.
Printf
(
"diskSize = %v (%v)
\n
"
,
diskSize
.
Value
(),
diskSize
.
Format
)
cores
:=
resource
.
ParseOrDie
(
"5300m"
)
fmt
.
Printf
(
"milliCores = %v (%v)
\n
"
,
cores
.
MilliValue
(),
cores
.
Format
)
cores2
:=
resource
.
ParseOrDie
(
"5.4"
)
fmt
.
Printf
(
"milliCores = %v (%v)
\n
"
,
cores2
.
MilliValue
(),
cores2
.
Format
)
// Output:
// memorySize = 5368709120 (BinarySI)
// diskSize = 5000000000 (DecimalSI)
// milliCores = 5300 (DecimalSI)
// milliCores = 5400 (DecimalSI)
}
pkg/api/resource/quantity_test.go
View file @
2d2df559
...
@@ -162,6 +162,10 @@ func TestQuantityParse(t *testing.T) {
...
@@ -162,6 +162,10 @@ func TestQuantityParse(t *testing.T) {
// Even if it were, 500 * 1/1024 = .48828125, NOT .512
// Even if it were, 500 * 1/1024 = .48828125, NOT .512
// I cannot recommend using this feature, it is confusing.
// I cannot recommend using this feature, it is confusing.
{
"0.5i"
,
Quantity
{
dec
(
500
,
-
3
),
DecimalSI
}},
{
"0.5i"
,
Quantity
{
dec
(
500
,
-
3
),
DecimalSI
}},
// Things written by trolls
{
".001"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
}},
{
"1."
,
Quantity
{
dec
(
1
,
0
),
DecimalSI
}},
}
}
for
_
,
item
:=
range
table
{
for
_
,
item
:=
range
table
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment