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
394c9452
Commit
394c9452
authored
Sep 04, 2014
by
Daniel Smith
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Start numeric type for resources
parent
9b8c5d08
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
608 additions
and
0 deletions
+608
-0
quantity.go
pkg/api/resource/quantity.go
+255
-0
quantity_test.go
pkg/api/resource/quantity_test.go
+221
-0
suffix.go
pkg/api/resource/suffix.go
+132
-0
No files found.
pkg/api/resource/quantity.go
0 → 100644
View file @
394c9452
/*
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
import
(
"errors"
"math/big"
"regexp"
"strings"
"speter.net/go/exp/math/dec/inf"
)
// Format lists the three possible formattings of a quantity.
type
Format
string
const
(
DecimalExponent
=
Format
(
"DecExponent"
)
BinarySI
=
Format
(
"BinSI"
)
DecimalSI
=
Format
(
"DecSI"
)
)
// 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:
//
// <serialized> ::= <sign><numeric> | <numeric>
// <numeric> ::= <digits><exponent> | <digits>.<digits><exponent>
// <sign> ::= "+" | "-"
// <digits> ::= <digit> | <digit><digits>
// <digit> ::= 0 | 1 | ... | 9
// <exponent> ::= <binarySuffix> | <decimalExponent> | <decimalSuffix>
// <binarySuffix> ::= i | Ki | Mi | Gi | Ti | Pi | Ei
// <decimalSuffix> ::= m | "" | k | M | G | T | P | E
// <decimalExponent> ::= "e" <digits> | "E" <digits>
// (Where digits is always a multiple of 3)
// (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)
//
// No matter which of the three exponent forms is used, no quantity may represent
// a number less than .001m or greater than 2^63-1 in magnitude. Numbers that exceed
// a bound will be capped at that bound. (E.g.: 0.0001m will be treated as 0.001m.)
// This may be extended in the future if we require larger or smaller quantities.
//
// Numbers with binary suffixes may not have any fractional part.
//
// Quantities will be serialized in the same format that they were parsed from.
// Before serializing, Quantity will be put in "canonical form".
// This means that Exponent will be adjusted up or down (with a
// corresponding increase or decrease in Mantissa) until one of the
// following is true:
// a. Binary SI mode: Mantissa mod 1024 is nonzero.
// Examples: 1Gi 300Mi 6Ki 1001Gi
// Non-canonical: 1024Gi (Should be 1Ti)
// b. Decimal SI mode: exponent is greater than 3 and one of Mantissa's three least
// significant digits is nonzero.
// Examples: 1G 300M 3K 1001G
// Non-canonical: 1000G (Should be 1T)
// c. Decimal SI mode: exponent is less than or equal to zero, and Mantissa has no more
// than three nonzero decimals. If any decimals are nonzero, three
// decimals will be emitted.
// Examples: 5 123.450 1.001 0.045
// Non-canonical: 1m (should be 0.001)
// d. Decimal exponent mode: as for decimal SI mode, but using the corresponding
// "e6" or "E6" form.
//
// The sign will be omitted unless the number is negative.
//
// Note that the quantity will NEVER be 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.
type
Quantity
struct
{
Amount
*
inf
.
Dec
Format
}
const
(
splitREString
=
"^([+-]?[0123456789.]+)([eEimkKMGTP]*[-+]?[0123456789]*)$"
)
var
(
// splitRE is used to get the various parts of a number.
splitRE
=
regexp
.
MustCompile
(
splitREString
)
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"
)
ErrFractionalBinary
=
errors
.
New
(
"numbers with binary-style SI suffixes can't have fractional parts"
)
)
// ParseQuantity turns str into a Quantity, or returns an error.
func
ParseQuantity
(
str
string
)
(
*
Quantity
,
error
)
{
parts
:=
splitRE
.
FindStringSubmatch
(
strings
.
TrimSpace
(
str
))
if
len
(
parts
)
!=
3
{
return
nil
,
ErrFormatWrong
}
amount
:=
new
(
inf
.
Dec
)
if
_
,
ok
:=
amount
.
SetString
(
parts
[
1
]);
!
ok
{
return
nil
,
ErrNumeric
}
base
,
exponent
,
format
,
ok
:=
quantitySuffixer
.
interpret
(
suffix
(
parts
[
2
]))
if
!
ok
{
return
nil
,
ErrSuffix
}
// So that no one but us has to think about suffixes, remove it.
if
base
==
10
{
amount
.
SetScale
(
amount
.
Scale
()
+
inf
.
Scale
(
-
exponent
))
}
else
if
base
==
2
{
// Detect fractional parts by rounding. There's probably
// a better way to do this.
if
rounded
:=
new
(
inf
.
Dec
)
.
Round
(
amount
,
0
,
inf
.
RoundFloor
);
rounded
.
Cmp
(
amount
)
!=
0
{
return
nil
,
ErrFractionalBinary
}
if
exponent
<
0
{
return
nil
,
ErrFractionalBinary
}
// exponent will always be a multiple of 10.
dec1024
:=
inf
.
NewDec
(
1024
,
0
)
for
exponent
>
0
{
amount
.
Mul
(
amount
,
dec1024
)
exponent
-=
10
}
}
return
&
Quantity
{
amount
,
format
},
nil
}
var
(
// Commonly needed big.Ints-- treat as read only!
ten
=
big
.
NewInt
(
10
)
zero
=
big
.
NewInt
(
0
)
thousand
=
big
.
NewInt
(
1000
)
ten24
=
big
.
NewInt
(
1024
)
minAllowed
=
inf
.
NewDec
(
1
,
6
)
maxAllowed
=
inf
.
NewDec
(
999
,
-
18
)
)
// removeFactors divides in a loop; the return values have the property that
// d == result * factor ^ times
// d may be modified in place.
// If d == 0, then the return values will be (0, 0)
func
removeFactors
(
d
,
factor
*
big
.
Int
)
(
result
*
big
.
Int
,
times
int
)
{
q
:=
big
.
NewInt
(
0
)
m
:=
big
.
NewInt
(
0
)
for
d
.
Cmp
(
zero
)
!=
0
{
q
.
DivMod
(
d
,
factor
,
m
)
if
m
.
Cmp
(
zero
)
!=
0
{
break
}
times
++
d
,
q
=
q
,
d
}
return
d
,
times
}
// Canonicalize returns the canonical form of q and its suffix (see comment on Quantity).
func
(
q
*
Quantity
)
Canonicalize
()
(
string
,
suffix
)
{
mantissa
:=
q
.
Amount
.
UnscaledBig
()
exponent
:=
int
(
-
q
.
Amount
.
Scale
())
amount
:=
big
.
NewInt
(
0
)
.
Set
(
mantissa
)
switch
q
.
Format
{
case
DecimalExponent
,
DecimalSI
:
// move all factors of 10 into the exponent for easy reasoning
amount
,
times
:=
removeFactors
(
amount
,
ten
)
exponent
+=
times
// make sure exponent is a multiple of 3
for
exponent
%
3
!=
0
{
amount
.
Mul
(
amount
,
ten
)
exponent
--
}
absAmount
:=
big
.
NewInt
(
0
)
.
Abs
(
amount
)
// Canonical form has three decimal digits.
if
absAmount
.
Cmp
(
thousand
)
>=
0
{
// Unless that would cause an exponent of 3-- 111.111e3 is silly.
if
exponent
!=
0
{
suffix
,
_
:=
quantitySuffixer
.
construct
(
10
,
exponent
+
3
,
q
.
Format
)
number
:=
inf
.
NewDecBig
(
amount
,
3
)
.
String
()
return
number
,
suffix
}
}
suffix
,
_
:=
quantitySuffixer
.
construct
(
10
,
exponent
,
q
.
Format
)
number
:=
amount
.
String
()
return
number
,
suffix
case
BinarySI
:
// Apply the (base-10) shift. This will lose any fractional
// part, which is intentional.
for
exponent
<
0
{
amount
.
Mul
(
amount
,
ten
)
exponent
++
}
for
exponent
>
0
{
amount
.
Mul
(
amount
,
ten
)
exponent
--
}
amount
,
exponent
:=
removeFactors
(
amount
,
ten24
)
suffix
,
_
:=
quantitySuffixer
.
construct
(
2
,
exponent
*
10
,
q
.
Format
)
number
:=
amount
.
String
()
return
number
,
suffix
}
return
"0"
,
""
}
// String formats the Quantity as a string.
func
(
q
*
Quantity
)
String
()
string
{
number
,
suffix
:=
q
.
Canonicalize
()
return
number
+
string
(
suffix
)
}
// MarshalJSON implements the json.Marshaller interface.
func
(
q
Quantity
)
MarshalJSON
()
([]
byte
,
error
)
{
return
[]
byte
(
`"`
+
q
.
String
()
+
`"`
),
nil
}
// UnmarshalJSON implements the json.Unmarshaller interface.
func
(
q
*
Quantity
)
UnmarshalJSON
(
value
[]
byte
)
error
{
str
:=
string
(
value
)
parsed
,
err
:=
ParseQuantity
(
strings
.
Trim
(
str
,
`"`
))
if
err
!=
nil
{
return
err
}
// This copy is safe because parsed will not be referred to again.
*
q
=
*
parsed
return
nil
}
pkg/api/resource/quantity_test.go
0 → 100644
View file @
394c9452
/*
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
import
(
//"reflect"
"testing"
"speter.net/go/exp/math/dec/inf"
)
func
dec
(
i
int64
,
exponent
int
)
*
inf
.
Dec
{
// See the below test-- scale is the negative of an exponent.
return
inf
.
NewDec
(
i
,
inf
.
Scale
(
-
exponent
))
}
func
TestDec
(
t
*
testing
.
T
)
{
table
:=
[]
struct
{
got
*
inf
.
Dec
expect
string
}{
{
dec
(
1
,
0
),
"1"
},
{
dec
(
1
,
1
),
"10"
},
{
dec
(
5
,
2
),
"500"
},
{
dec
(
8
,
3
),
"8000"
},
{
dec
(
2
,
0
),
"2"
},
{
dec
(
1
,
-
1
),
"0.1"
},
{
dec
(
3
,
-
2
),
"0.03"
},
{
dec
(
4
,
-
3
),
"0.004"
},
}
for
_
,
item
:=
range
table
{
if
e
,
a
:=
item
.
expect
,
item
.
got
.
String
();
e
!=
a
{
t
.
Errorf
(
"expected %v, got %v"
,
e
,
a
)
}
}
}
func
TestQuantityParse
(
t
*
testing
.
T
)
{
table
:=
[]
struct
{
input
string
expect
Quantity
}{
{
"0"
,
Quantity
{
dec
(
0
,
0
),
DecimalSI
}},
// Binary suffixes
{
"9i"
,
Quantity
{
dec
(
9
,
0
),
BinarySI
}},
{
"8Ki"
,
Quantity
{
dec
(
8
*
1024
,
0
),
BinarySI
}},
{
"7Mi"
,
Quantity
{
dec
(
7
*
1024
*
1024
,
0
),
BinarySI
}},
{
"6Gi"
,
Quantity
{
dec
(
6
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"5Ti"
,
Quantity
{
dec
(
5
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"4Pi"
,
Quantity
{
dec
(
4
*
1024
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"3Ei"
,
Quantity
{
dec
(
3
*
1024
*
1024
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"10Ti"
,
Quantity
{
dec
(
10
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"100Ti"
,
Quantity
{
dec
(
100
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
// Decimal suffixes
{
"3m"
,
Quantity
{
dec
(
3
,
-
3
),
DecimalSI
}},
{
"9"
,
Quantity
{
dec
(
9
,
0
),
DecimalSI
}},
{
"8k"
,
Quantity
{
dec
(
8
,
3
),
DecimalSI
}},
{
"7M"
,
Quantity
{
dec
(
7
,
6
),
DecimalSI
}},
{
"6G"
,
Quantity
{
dec
(
6
,
9
),
DecimalSI
}},
{
"5T"
,
Quantity
{
dec
(
5
,
12
),
DecimalSI
}},
{
"40T"
,
Quantity
{
dec
(
4
,
13
),
DecimalSI
}},
{
"300T"
,
Quantity
{
dec
(
3
,
14
),
DecimalSI
}},
{
"2P"
,
Quantity
{
dec
(
2
,
15
),
DecimalSI
}},
{
"1E"
,
Quantity
{
dec
(
1
,
18
),
DecimalSI
}},
// Decimal exponents
{
"1E-3"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalExponent
}},
{
"1e3"
,
Quantity
{
dec
(
1
,
3
),
DecimalExponent
}},
{
"1E6"
,
Quantity
{
dec
(
1
,
6
),
DecimalExponent
}},
{
"1e9"
,
Quantity
{
dec
(
1
,
9
),
DecimalExponent
}},
{
"1E12"
,
Quantity
{
dec
(
1
,
12
),
DecimalExponent
}},
{
"1e15"
,
Quantity
{
dec
(
1
,
15
),
DecimalExponent
}},
{
"1E18"
,
Quantity
{
dec
(
1
,
18
),
DecimalExponent
}},
// Nonstandard but still parsable
{
"1e14"
,
Quantity
{
dec
(
1
,
14
),
DecimalExponent
}},
{
"1e13"
,
Quantity
{
dec
(
1
,
13
),
DecimalExponent
}},
{
"1e3"
,
Quantity
{
dec
(
1
,
3
),
DecimalExponent
}},
{
"100.035k"
,
Quantity
{
dec
(
100035
,
0
),
DecimalSI
}},
// Things that look like floating point
{
"0.001"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
}},
{
"0.0005"
,
Quantity
{
dec
(
5
,
-
4
),
DecimalSI
}},
{
"0.005"
,
Quantity
{
dec
(
5
,
-
3
),
DecimalSI
}},
{
"0.05"
,
Quantity
{
dec
(
5
,
-
2
),
DecimalSI
}},
{
"0.5"
,
Quantity
{
dec
(
5
,
-
1
),
DecimalSI
}},
{
"0.00050"
,
Quantity
{
dec
(
5
,
-
4
),
DecimalSI
}},
{
"0.00500"
,
Quantity
{
dec
(
5
,
-
3
),
DecimalSI
}},
{
"0.05000"
,
Quantity
{
dec
(
5
,
-
2
),
DecimalSI
}},
{
"0.50000"
,
Quantity
{
dec
(
5
,
-
1
),
DecimalSI
}},
{
"0.5e-3"
,
Quantity
{
dec
(
5
,
-
4
),
DecimalExponent
}},
{
"0.5e-2"
,
Quantity
{
dec
(
5
,
-
3
),
DecimalExponent
}},
{
"0.5e-1"
,
Quantity
{
dec
(
5
,
-
2
),
DecimalExponent
}},
{
"0.5e0"
,
Quantity
{
dec
(
5
,
-
1
),
DecimalExponent
}},
{
"10.035M"
,
Quantity
{
dec
(
10035
,
3
),
DecimalSI
}},
{
"1.1E-3"
,
Quantity
{
dec
(
11
,
-
4
),
DecimalExponent
}},
{
"1.2e3"
,
Quantity
{
dec
(
12
,
2
),
DecimalExponent
}},
{
"1.3E6"
,
Quantity
{
dec
(
13
,
5
),
DecimalExponent
}},
{
"1.40e9"
,
Quantity
{
dec
(
14
,
8
),
DecimalExponent
}},
{
"1.53E12"
,
Quantity
{
dec
(
153
,
10
),
DecimalExponent
}},
{
"1.6e15"
,
Quantity
{
dec
(
16
,
14
),
DecimalExponent
}},
{
"1.7E18"
,
Quantity
{
dec
(
17
,
17
),
DecimalExponent
}},
{
"3.001m"
,
Quantity
{
dec
(
3001
,
-
6
),
DecimalSI
}},
{
"9.01"
,
Quantity
{
dec
(
901
,
-
2
),
DecimalSI
}},
{
"8.1k"
,
Quantity
{
dec
(
81
,
2
),
DecimalSI
}},
{
"7.123456M"
,
Quantity
{
dec
(
7123456
,
0
),
DecimalSI
}},
{
"6.987654321G"
,
Quantity
{
dec
(
6987654321
,
0
),
DecimalSI
}},
{
"5.444T"
,
Quantity
{
dec
(
5444
,
9
),
DecimalSI
}},
{
"40.1T"
,
Quantity
{
dec
(
401
,
11
),
DecimalSI
}},
{
"300.2T"
,
Quantity
{
dec
(
3002
,
11
),
DecimalSI
}},
{
"2.5P"
,
Quantity
{
dec
(
25
,
14
),
DecimalSI
}},
{
"1.01E"
,
Quantity
{
dec
(
101
,
16
),
DecimalSI
}},
// Things that saturate
//{"0.1m",
//{"9Ei",
//{"9223372036854775807Ki",
//{"12E",
}
for
_
,
item
:=
range
table
{
got
,
err
:=
ParseQuantity
(
item
.
input
)
if
err
!=
nil
{
t
.
Errorf
(
"%v: unexpected error: %v"
,
item
.
input
,
err
)
continue
}
if
e
,
a
:=
item
.
expect
.
Amount
,
got
.
Amount
;
e
.
Cmp
(
a
)
!=
0
{
t
.
Errorf
(
"%v: expected %v, got %v"
,
item
.
input
,
e
,
a
)
}
if
e
,
a
:=
item
.
expect
.
Format
,
got
.
Format
;
e
!=
a
{
t
.
Errorf
(
"%v: expected %#v, got %#v"
,
item
.
input
,
e
,
a
)
}
}
invalid
:=
[]
string
{
"1.1.M"
,
"1+1.0M"
,
"0.1mi"
,
"0.1am"
,
"0.0001i"
,
"100.035Ki"
,
"0.5Mi"
,
"0.05Gi"
,
"0.5Ti"
,
"0.005i"
,
"0.05i"
,
"0.5i"
,
"aoeu"
,
}
for
_
,
item
:=
range
invalid
{
_
,
err
:=
ParseQuantity
(
item
)
if
err
==
nil
{
t
.
Errorf
(
"%v parsed unexpectedly"
,
item
)
}
}
}
func
TestQuantityString
(
t
*
testing
.
T
)
{
table
:=
[]
struct
{
in
Quantity
expect
string
}{
{
Quantity
{
dec
(
1024
*
1024
*
1024
,
0
),
BinarySI
},
"1Gi"
},
{
Quantity
{
dec
(
300
*
1024
*
1024
,
0
),
BinarySI
},
"300Mi"
},
{
Quantity
{
dec
(
6
*
1024
,
0
),
BinarySI
},
"6Ki"
},
{
Quantity
{
dec
(
1001
*
1024
*
1024
*
1024
,
0
),
BinarySI
},
"1001Gi"
},
{
Quantity
{
dec
(
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
},
"1Ti"
},
{
Quantity
{
dec
(
5
,
0
),
BinarySI
},
"5i"
},
{
Quantity
{
dec
(
1
,
9
),
DecimalSI
},
"1G"
},
{
Quantity
{
dec
(
1000
,
6
),
DecimalSI
},
"1G"
},
{
Quantity
{
dec
(
1000000
,
3
),
DecimalSI
},
"1G"
},
{
Quantity
{
dec
(
1000000000
,
0
),
DecimalSI
},
"1G"
},
{
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
},
"1m"
},
{
Quantity
{
dec
(
80
,
-
3
),
DecimalSI
},
"80m"
},
{
Quantity
{
dec
(
1080
,
-
3
),
DecimalSI
},
"1.080"
},
{
Quantity
{
dec
(
108
,
-
2
),
DecimalSI
},
"1.080"
},
{
Quantity
{
dec
(
10800
,
-
4
),
DecimalSI
},
"1.080"
},
{
Quantity
{
dec
(
300
,
6
),
DecimalSI
},
"300M"
},
{
Quantity
{
dec
(
1
,
12
),
DecimalSI
},
"1T"
},
{
Quantity
{
dec
(
3
,
3
),
DecimalSI
},
"3k"
},
{
Quantity
{
dec
(
0
,
0
),
DecimalSI
},
"0"
},
{
Quantity
{
dec
(
0
,
0
),
BinarySI
},
"0i"
},
{
Quantity
{
dec
(
1
,
9
),
DecimalExponent
},
"1e9"
},
{
Quantity
{
dec
(
1
,
-
3
),
DecimalExponent
},
"1e-3"
},
{
Quantity
{
dec
(
80
,
-
3
),
DecimalExponent
},
"80e-3"
},
{
Quantity
{
dec
(
300
,
6
),
DecimalExponent
},
"300e6"
},
{
Quantity
{
dec
(
1
,
12
),
DecimalExponent
},
"1e12"
},
{
Quantity
{
dec
(
1
,
3
),
DecimalExponent
},
"1e3"
},
{
Quantity
{
dec
(
3
,
3
),
DecimalExponent
},
"3e3"
},
{
Quantity
{
dec
(
3
,
3
),
DecimalSI
},
"3k"
},
{
Quantity
{
dec
(
0
,
0
),
DecimalExponent
},
"0"
},
{
Quantity
{
dec
(
-
1080
,
-
3
),
DecimalSI
},
"-1.080"
},
{
Quantity
{
dec
(
-
80
*
1024
,
0
),
BinarySI
},
"-80Ki"
},
}
for
_
,
item
:=
range
table
{
got
:=
item
.
in
.
String
()
if
e
,
a
:=
item
.
expect
,
got
;
e
!=
a
{
t
.
Errorf
(
"%#v: expected %v, got %v"
,
item
.
in
,
e
,
a
)
}
}
}
pkg/api/resource/suffix.go
0 → 100644
View file @
394c9452
/*
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
import
(
"strconv"
)
type
suffix
string
// suffixer can interpret and construct suffixes.
type
suffixer
interface
{
interpret
(
suffix
)
(
base
,
exponent
int
,
fmt
Format
,
ok
bool
)
construct
(
base
,
exponent
int
,
fmt
Format
)
(
s
suffix
,
ok
bool
)
}
// quantitySuffixer handles suffixes for all three formats that quantity
// can handle.
var
quantitySuffixer
=
newSuffixer
()
type
bePair
struct
{
base
,
exponent
int
}
type
listSuffixer
struct
{
suffixToBE
map
[
suffix
]
bePair
beToSuffix
map
[
bePair
]
suffix
}
func
(
ls
*
listSuffixer
)
addSuffix
(
s
suffix
,
pair
bePair
)
{
if
ls
.
suffixToBE
==
nil
{
ls
.
suffixToBE
=
map
[
suffix
]
bePair
{}
}
if
ls
.
beToSuffix
==
nil
{
ls
.
beToSuffix
=
map
[
bePair
]
suffix
{}
}
ls
.
suffixToBE
[
s
]
=
pair
ls
.
beToSuffix
[
pair
]
=
s
}
func
(
ls
*
listSuffixer
)
lookup
(
s
suffix
)
(
base
,
exponent
int
,
ok
bool
)
{
pair
,
ok
:=
ls
.
suffixToBE
[
s
]
if
!
ok
{
return
0
,
0
,
false
}
return
pair
.
base
,
pair
.
exponent
,
true
}
func
(
ls
*
listSuffixer
)
construct
(
base
,
exponent
int
)
(
s
suffix
,
ok
bool
)
{
s
,
ok
=
ls
.
beToSuffix
[
bePair
{
base
,
exponent
}]
return
}
type
suffixHandler
struct
{
decSuffixes
listSuffixer
binSuffixes
listSuffixer
}
func
newSuffixer
()
suffixer
{
sh
:=
&
suffixHandler
{}
sh
.
binSuffixes
.
addSuffix
(
"i"
,
bePair
{
2
,
0
})
sh
.
binSuffixes
.
addSuffix
(
"Ki"
,
bePair
{
2
,
10
})
sh
.
binSuffixes
.
addSuffix
(
"Mi"
,
bePair
{
2
,
20
})
sh
.
binSuffixes
.
addSuffix
(
"Gi"
,
bePair
{
2
,
30
})
sh
.
binSuffixes
.
addSuffix
(
"Ti"
,
bePair
{
2
,
40
})
sh
.
binSuffixes
.
addSuffix
(
"Pi"
,
bePair
{
2
,
50
})
sh
.
binSuffixes
.
addSuffix
(
"Ei"
,
bePair
{
2
,
60
})
sh
.
decSuffixes
.
addSuffix
(
"m"
,
bePair
{
10
,
-
3
})
sh
.
decSuffixes
.
addSuffix
(
""
,
bePair
{
10
,
0
})
sh
.
decSuffixes
.
addSuffix
(
"k"
,
bePair
{
10
,
3
})
sh
.
decSuffixes
.
addSuffix
(
"M"
,
bePair
{
10
,
6
})
sh
.
decSuffixes
.
addSuffix
(
"G"
,
bePair
{
10
,
9
})
sh
.
decSuffixes
.
addSuffix
(
"T"
,
bePair
{
10
,
12
})
sh
.
decSuffixes
.
addSuffix
(
"P"
,
bePair
{
10
,
15
})
sh
.
decSuffixes
.
addSuffix
(
"E"
,
bePair
{
10
,
18
})
return
sh
}
func
(
sh
*
suffixHandler
)
construct
(
base
,
exponent
int
,
fmt
Format
)
(
s
suffix
,
ok
bool
)
{
switch
fmt
{
case
DecimalSI
:
return
sh
.
decSuffixes
.
construct
(
base
,
exponent
)
case
BinarySI
:
return
sh
.
binSuffixes
.
construct
(
base
,
exponent
)
case
DecimalExponent
:
if
base
!=
10
{
return
""
,
false
}
if
exponent
==
0
{
return
""
,
true
}
return
suffix
(
"e"
+
strconv
.
FormatInt
(
int64
(
exponent
),
10
)),
true
}
return
""
,
false
}
func
(
sh
*
suffixHandler
)
interpret
(
suffix
suffix
)
(
base
,
exponent
int
,
fmt
Format
,
ok
bool
)
{
// Try lookup tables first
if
b
,
e
,
ok
:=
sh
.
decSuffixes
.
lookup
(
suffix
);
ok
{
return
b
,
e
,
DecimalSI
,
true
}
if
b
,
e
,
ok
:=
sh
.
binSuffixes
.
lookup
(
suffix
);
ok
{
return
b
,
e
,
BinarySI
,
true
}
if
len
(
suffix
)
>
1
&&
suffix
[
0
]
==
'E'
||
suffix
[
0
]
==
'e'
{
parsed
,
err
:=
strconv
.
ParseInt
(
string
(
suffix
[
1
:
]),
10
,
64
)
if
err
!=
nil
{
return
0
,
0
,
DecimalExponent
,
false
}
return
10
,
int
(
parsed
),
DecimalExponent
,
true
}
return
0
,
0
,
DecimalExponent
,
false
}
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