mirror of
				https://github.com/ClusterCockpit/cc-units.git
				synced 2025-10-31 01:05:08 +01:00 
			
		
		
		
	Use maps to store all unit related data
This commit is contained in:
		| @@ -1,9 +1,8 @@ | ||||
| # ccUnits - A unit system for ClusterCockpit | ||||
| # cc-units - A unit system for ClusterCockpit | ||||
|  | ||||
| When working with metrics, the problem comes up that they may use different unit name but have the same unit in fact. There are a lot of real world examples like 'kB' and 'Kbyte'. In CC Metric Collector, the Collectors read data from different sources which may use different units or the programmer specifies a unit for a metric by hand. The ccUnits system is not comparable with the SI unit system. If you are looking for a package for the SI units, see [here](https://pkg.go.dev/github.com/gurre/si). | ||||
| When working with metrics, the problem comes up that they may use different unit name but have the same unit in fact. There are a lot of real world examples like 'kB' and 'Kbyte'. In [cc-metric-collector](https://github.com/ClusterCockpit/cc-metric-collector), the collectors read data from different sources which may use different units or the programmer specifies a unit for a metric by hand. The cc-units system is not comparable with the SI unit system. If you are looking for a package for the SI units, see [here](https://pkg.go.dev/github.com/gurre/si). | ||||
|  | ||||
| In order to enable unit comparison and conversion, the ccUnits package provides some helpers: | ||||
| There are basically two important functions: | ||||
| ```go | ||||
| NewUnit(unit string) Unit // create a new unit from some string like 'GHz', 'Mbyte' or 'kevents/s' | ||||
| func GetUnitUnitFactor(in Unit, out Unit) (func(value float64) float64, error) // Get conversion function between two units | ||||
|   | ||||
							
								
								
									
										248
									
								
								ccUnitMeasure.go
									
									
									
									
									
								
							
							
						
						
									
										248
									
								
								ccUnitMeasure.go
									
									
									
									
									
								
							| @@ -12,7 +12,7 @@ const ( | ||||
| 	TemperatureC | ||||
| 	TemperatureF | ||||
| 	Rotation | ||||
| 	Hertz | ||||
| 	Frequency | ||||
| 	Time | ||||
| 	Watt | ||||
| 	Joule | ||||
| @@ -22,171 +22,113 @@ const ( | ||||
| 	Events | ||||
| ) | ||||
|  | ||||
| type MeasureData struct { | ||||
| 	Long  string | ||||
| 	Short string | ||||
| 	Regex string | ||||
| } | ||||
|  | ||||
| // Different names and regex used for input and output | ||||
| var InvalidMeasureLong string = "Invalid" | ||||
| var InvalidMeasureShort string = "inval" | ||||
| var MeasuresMap map[Measure]MeasureData = map[Measure]MeasureData{ | ||||
| 	Bytes: { | ||||
| 		Long:  "byte", | ||||
| 		Short: "B", | ||||
| 		Regex: "^([bB][yY]?[tT]?[eE]?[sS]?)", | ||||
| 	}, | ||||
| 	Flops: { | ||||
| 		Long:  "Flops", | ||||
| 		Short: "Flops", | ||||
| 		Regex: "^([fF][lL]?[oO]?[pP]?[sS]?)", | ||||
| 	}, | ||||
| 	Percentage: { | ||||
| 		Long:  "Percent", | ||||
| 		Short: "%", | ||||
| 		Regex: "^(%|[pP]ercent)", | ||||
| 	}, | ||||
| 	TemperatureC: { | ||||
| 		Long:  "DegreeC", | ||||
| 		Short: "degC", | ||||
| 		Regex: "^(deg[Cc]|°[cC])", | ||||
| 	}, | ||||
| 	TemperatureF: { | ||||
| 		Long:  "DegreeF", | ||||
| 		Short: "degF", | ||||
| 		Regex: "^(deg[fF]|°[fF])", | ||||
| 	}, | ||||
| 	Rotation: { | ||||
| 		Long:  "RPM", | ||||
| 		Short: "RPM", | ||||
| 		Regex: "^([rR][pP][mM])", | ||||
| 	}, | ||||
| 	Frequency: { | ||||
| 		Long:  "Hertz", | ||||
| 		Short: "Hz", | ||||
| 		Regex: "^([hH][eE]?[rR]?[tT]?[zZ])", | ||||
| 	}, | ||||
| 	Time: { | ||||
| 		Long:  "Seconds", | ||||
| 		Short: "s", | ||||
| 		Regex: "^([sS][eE]?[cC]?[oO]?[nN]?[dD]?[sS]?)", | ||||
| 	}, | ||||
| 	Cycles: { | ||||
| 		Long:  "Cycles", | ||||
| 		Short: "cyc", | ||||
| 		Regex: "^([cC][yY][cC]?[lL]?[eE]?[sS]?)", | ||||
| 	}, | ||||
| 	Watt: { | ||||
| 		Long:  "Watts", | ||||
| 		Short: "W", | ||||
| 		Regex: "^([wW][aA]?[tT]?[tT]?[sS]?)", | ||||
| 	}, | ||||
| 	Joule: { | ||||
| 		Long:  "Joules", | ||||
| 		Short: "J", | ||||
| 		Regex: "^([jJ][oO]?[uU]?[lL]?[eE]?[sS]?)", | ||||
| 	}, | ||||
| 	Requests: { | ||||
| 		Long:  "Requests", | ||||
| 		Short: "requests", | ||||
| 		Regex: "^([rR][eE][qQ][uU]?[eE]?[sS]?[tT]?[sS]?)", | ||||
| 	}, | ||||
| 	Packets: { | ||||
| 		Long:  "Packets", | ||||
| 		Short: "packets", | ||||
| 		Regex: "^([pP][aA]?[cC]?[kK][eE]?[tT][sS]?)", | ||||
| 	}, | ||||
| 	Events: { | ||||
| 		Long:  "Events", | ||||
| 		Short: "events", | ||||
| 		Regex: "^([eE][vV]?[eE]?[nN][tT][sS]?)", | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // String returns the long string for the measure like 'Percent' or 'Seconds' | ||||
| func (m *Measure) String() string { | ||||
| 	switch *m { | ||||
| 	case Bytes: | ||||
| 		return "byte" | ||||
| 	case Flops: | ||||
| 		return "Flops" | ||||
| 	case Percentage: | ||||
| 		return "Percent" | ||||
| 	case TemperatureC: | ||||
| 		return "DegreeC" | ||||
| 	case TemperatureF: | ||||
| 		return "DegreeF" | ||||
| 	case Rotation: | ||||
| 		return "RPM" | ||||
| 	case Hertz: | ||||
| 		return "Hertz" | ||||
| 	case Time: | ||||
| 		return "Seconds" | ||||
| 	case Watt: | ||||
| 		return "Watts" | ||||
| 	case Joule: | ||||
| 		return "Joules" | ||||
| 	case Cycles: | ||||
| 		return "Cycles" | ||||
| 	case Requests: | ||||
| 		return "Requests" | ||||
| 	case Packets: | ||||
| 		return "Packets" | ||||
| 	case Events: | ||||
| 		return "Events" | ||||
| 	case InvalidMeasure: | ||||
| 		return "Invalid" | ||||
| 	default: | ||||
| 		return "Unknown" | ||||
| 	if data, ok := MeasuresMap[*m]; ok { | ||||
| 		return data.Long | ||||
| 	} | ||||
| 	return InvalidMeasureLong | ||||
| } | ||||
|  | ||||
| // Short returns the short string for the measure like 'B' (Bytes), 's' (Time) or 'W' (Watt). Is is recommened to use Short() over String(). | ||||
| func (m *Measure) Short() string { | ||||
| 	switch *m { | ||||
| 	case Bytes: | ||||
| 		return "B" | ||||
| 	case Flops: | ||||
| 		return "Flops" | ||||
| 	case Percentage: | ||||
| 		return "Percent" | ||||
| 	case TemperatureC: | ||||
| 		return "degC" | ||||
| 	case TemperatureF: | ||||
| 		return "degF" | ||||
| 	case Rotation: | ||||
| 		return "RPM" | ||||
| 	case Hertz: | ||||
| 		return "Hz" | ||||
| 	case Time: | ||||
| 		return "s" | ||||
| 	case Watt: | ||||
| 		return "W" | ||||
| 	case Joule: | ||||
| 		return "J" | ||||
| 	case Cycles: | ||||
| 		return "cyc" | ||||
| 	case Requests: | ||||
| 		return "requests" | ||||
| 	case Packets: | ||||
| 		return "packets" | ||||
| 	case Events: | ||||
| 		return "events" | ||||
| 	case InvalidMeasure: | ||||
| 		return "Invalid" | ||||
| 	default: | ||||
| 		return "Unknown" | ||||
| 	if data, ok := MeasuresMap[*m]; ok { | ||||
| 		return data.Short | ||||
| 	} | ||||
| 	return InvalidMeasureShort | ||||
| } | ||||
|  | ||||
| const bytesRegexStr = `^([bB][yY]?[tT]?[eE]?[sS]?)` | ||||
| const flopsRegexStr = `^([fF][lL]?[oO]?[pP]?[sS]?)` | ||||
| const percentRegexStr = `^(%|[pP]ercent)` | ||||
| const degreeCRegexStr = `^(deg[Cc]|°[cC])` | ||||
| const degreeFRegexStr = `^(deg[fF]|°[fF])` | ||||
| const rpmRegexStr = `^([rR][pP][mM])` | ||||
| const hertzRegexStr = `^([hH][eE]?[rR]?[tT]?[zZ])` | ||||
| const timeRegexStr = `^([sS][eE]?[cC]?[oO]?[nN]?[dD]?[sS]?)` | ||||
| const wattRegexStr = `^([wW][aA]?[tT]?[tT]?[sS]?)` | ||||
| const jouleRegexStr = `^([jJ][oO]?[uU]?[lL]?[eE]?[sS]?)` | ||||
| const cyclesRegexStr = `^([cC][yY][cC]?[lL]?[eE]?[sS]?)` | ||||
| const requestsRegexStr = `^([rR][eE][qQ][uU]?[eE]?[sS]?[tT]?[sS]?)` | ||||
| const packetsRegexStr = `^([pP][aA]?[cC]?[kK][eE]?[tT][sS]?)` | ||||
| const eventsRegexStr = `^([eE][vV]?[eE]?[nN][tT][sS]?)` | ||||
|  | ||||
| var bytesRegex = regexp.MustCompile(bytesRegexStr) | ||||
| var flopsRegex = regexp.MustCompile(flopsRegexStr) | ||||
| var percentRegex = regexp.MustCompile(percentRegexStr) | ||||
| var degreeCRegex = regexp.MustCompile(degreeCRegexStr) | ||||
| var degreeFRegex = regexp.MustCompile(degreeFRegexStr) | ||||
| var rpmRegex = regexp.MustCompile(rpmRegexStr) | ||||
| var hertzRegex = regexp.MustCompile(hertzRegexStr) | ||||
| var timeRegex = regexp.MustCompile(timeRegexStr) | ||||
| var wattRegex = regexp.MustCompile(wattRegexStr) | ||||
| var jouleRegex = regexp.MustCompile(jouleRegexStr) | ||||
| var cyclesRegex = regexp.MustCompile(cyclesRegexStr) | ||||
| var requestsRegex = regexp.MustCompile(requestsRegexStr) | ||||
| var packetsRegex = regexp.MustCompile(packetsRegexStr) | ||||
| var eventsRegex = regexp.MustCompile(eventsRegexStr) | ||||
|  | ||||
| // NewMeasure creates a new measure out of a string representing a measure like 'Bytes', 'Flops' and 'precent'. | ||||
| // It uses regular expressions for matching. | ||||
| func NewMeasure(unit string) Measure { | ||||
| 	var match []string | ||||
| 	match = bytesRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Bytes | ||||
| 	} | ||||
| 	match = flopsRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Flops | ||||
| 	} | ||||
| 	match = percentRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Percentage | ||||
| 	} | ||||
| 	match = degreeCRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return TemperatureC | ||||
| 	} | ||||
| 	match = degreeFRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return TemperatureF | ||||
| 	} | ||||
| 	match = rpmRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Rotation | ||||
| 	} | ||||
| 	match = hertzRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Hertz | ||||
| 	} | ||||
| 	match = timeRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Time | ||||
| 	} | ||||
| 	match = cyclesRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Cycles | ||||
| 	} | ||||
| 	match = wattRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Watt | ||||
| 	} | ||||
| 	match = jouleRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Joule | ||||
| 	} | ||||
| 	match = requestsRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Requests | ||||
| 	} | ||||
| 	match = packetsRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Packets | ||||
| 	} | ||||
| 	match = eventsRegex.FindStringSubmatch(unit) | ||||
| 	if match != nil { | ||||
| 		return Events | ||||
| 	for m, data := range MeasuresMap { | ||||
| 		regex := regexp.MustCompile(data.Regex) | ||||
| 		match := regex.FindStringSubmatch(unit) | ||||
| 		if match != nil { | ||||
| 			return m | ||||
| 		} | ||||
| 	} | ||||
| 	return InvalidMeasure | ||||
| } | ||||
|   | ||||
							
								
								
									
										264
									
								
								ccUnitPrefix.go
									
									
									
									
									
								
							
							
						
						
									
										264
									
								
								ccUnitPrefix.go
									
									
									
									
									
								
							| @@ -1,6 +1,8 @@ | ||||
| package ccunits | ||||
|  | ||||
| import "regexp" | ||||
| import ( | ||||
| 	"regexp" | ||||
| ) | ||||
|  | ||||
| type Prefix float64 | ||||
|  | ||||
| @@ -27,148 +29,146 @@ const ( | ||||
| 	Zebi                 = 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 | ||||
| 	Yobi                 = 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 | ||||
| ) | ||||
| const prefixRegexStr = `^([kKmMgGtTpP]?[i]?)(.*)` | ||||
| const PrefixUnitSplitRegexStr = `^([kKmMgGtTpPeEzZyY]?[i]?)(.*)` | ||||
|  | ||||
| var prefixRegex = regexp.MustCompile(prefixRegexStr) | ||||
| var prefixUnitSplitRegex = regexp.MustCompile(PrefixUnitSplitRegexStr) | ||||
|  | ||||
| type PrefixData struct { | ||||
| 	Long  string | ||||
| 	Short string | ||||
| 	Regex string | ||||
| } | ||||
|  | ||||
| // Different names and regex used for input and output | ||||
| var InvalidPrefixLong string = "Invalid" | ||||
| var InvalidPrefixShort string = "inval" | ||||
| var PrefixDataMap map[Prefix]PrefixData = map[Prefix]PrefixData{ | ||||
| 	Base: { | ||||
| 		Long:  "", | ||||
| 		Short: "", | ||||
| 		Regex: "^$", | ||||
| 	}, | ||||
| 	Kilo: { | ||||
| 		Long:  "Kilo", | ||||
| 		Short: "K", | ||||
| 		Regex: "^[kK]$", | ||||
| 	}, | ||||
| 	Mega: { | ||||
| 		Long:  "Mega", | ||||
| 		Short: "M", | ||||
| 		Regex: "^[M]$", | ||||
| 	}, | ||||
| 	Giga: { | ||||
| 		Long:  "Giga", | ||||
| 		Short: "G", | ||||
| 		Regex: "^[gG]$", | ||||
| 	}, | ||||
| 	Tera: { | ||||
| 		Long:  "Tera", | ||||
| 		Short: "T", | ||||
| 		Regex: "^[tT]$", | ||||
| 	}, | ||||
| 	Peta: { | ||||
| 		Long:  "Peta", | ||||
| 		Short: "P", | ||||
| 		Regex: "^[pP]$", | ||||
| 	}, | ||||
| 	Exa: { | ||||
| 		Long:  "Exa", | ||||
| 		Short: "E", | ||||
| 		Regex: "^[eE]$", | ||||
| 	}, | ||||
| 	Zetta: { | ||||
| 		Long:  "Zetta", | ||||
| 		Short: "Z", | ||||
| 		Regex: "^[zZ]$", | ||||
| 	}, | ||||
| 	Yotta: { | ||||
| 		Long:  "Yotta", | ||||
| 		Short: "Y", | ||||
| 		Regex: "^[yY]$", | ||||
| 	}, | ||||
| 	Milli: { | ||||
| 		Long:  "Milli", | ||||
| 		Short: "m", | ||||
| 		Regex: "^[m]$", | ||||
| 	}, | ||||
| 	Micro: { | ||||
| 		Long:  "Micro", | ||||
| 		Short: "u", | ||||
| 		Regex: "^[u]$", | ||||
| 	}, | ||||
| 	Nano: { | ||||
| 		Long:  "Nano", | ||||
| 		Short: "n", | ||||
| 		Regex: "^[n]$", | ||||
| 	}, | ||||
| 	Kibi: { | ||||
| 		Long:  "Kibi", | ||||
| 		Short: "Ki", | ||||
| 		Regex: "^[kK][i]$", | ||||
| 	}, | ||||
| 	Mebi: { | ||||
| 		Long:  "Mebi", | ||||
| 		Short: "Mi", | ||||
| 		Regex: "^[M][i]$", | ||||
| 	}, | ||||
| 	Gibi: { | ||||
| 		Long:  "Gibi", | ||||
| 		Short: "Gi", | ||||
| 		Regex: "^[gG][i]$", | ||||
| 	}, | ||||
| 	Tebi: { | ||||
| 		Long:  "Tebi", | ||||
| 		Short: "Ti", | ||||
| 		Regex: "^[tT][i]$", | ||||
| 	}, | ||||
| 	Pebi: { | ||||
| 		Long:  "Pebi", | ||||
| 		Short: "Pi", | ||||
| 		Regex: "^[pP][i]$", | ||||
| 	}, | ||||
| 	Exbi: { | ||||
| 		Long:  "Exbi", | ||||
| 		Short: "Ei", | ||||
| 		Regex: "^[eE][i]$", | ||||
| 	}, | ||||
| 	Zebi: { | ||||
| 		Long:  "Zebi", | ||||
| 		Short: "Zi", | ||||
| 		Regex: "^[zZ][i]$", | ||||
| 	}, | ||||
| 	Yobi: { | ||||
| 		Long:  "Yobi", | ||||
| 		Short: "Yi", | ||||
| 		Regex: "^[yY][i]$", | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // String returns the long string for the prefix like 'Kilo' or 'Mega' | ||||
| func (s *Prefix) String() string { | ||||
| 	switch *s { | ||||
| 	case InvalidPrefix: | ||||
| 		return "Inval" | ||||
| 	case Base: | ||||
| 		return "" | ||||
| 	case Kilo: | ||||
| 		return "Kilo" | ||||
| 	case Mega: | ||||
| 		return "Mega" | ||||
| 	case Giga: | ||||
| 		return "Giga" | ||||
| 	case Tera: | ||||
| 		return "Tera" | ||||
| 	case Peta: | ||||
| 		return "Peta" | ||||
| 	case Exa: | ||||
| 		return "Exa" | ||||
| 	case Zetta: | ||||
| 		return "Zetta" | ||||
| 	case Yotta: | ||||
| 		return "Yotta" | ||||
| 	case Milli: | ||||
| 		return "Milli" | ||||
| 	case Micro: | ||||
| 		return "Micro" | ||||
| 	case Nano: | ||||
| 		return "Nano" | ||||
| 	case Kibi: | ||||
| 		return "Kibi" | ||||
| 	case Mebi: | ||||
| 		return "Mebi" | ||||
| 	case Gibi: | ||||
| 		return "Gibi" | ||||
| 	case Tebi: | ||||
| 		return "Tebi" | ||||
| 	default: | ||||
| 		return "Unkn" | ||||
| func (p *Prefix) String() string { | ||||
| 	if data, ok := PrefixDataMap[*p]; ok { | ||||
| 		return data.Long | ||||
| 	} | ||||
| 	return InvalidMeasureLong | ||||
| } | ||||
|  | ||||
| // Prefix returns the short string for the prefix like 'K', 'M' or 'G'. Is is recommened to use Prefix() over String(). | ||||
| func (s *Prefix) Prefix() string { | ||||
| 	switch *s { | ||||
| 	case InvalidPrefix: | ||||
| 		return "<inval>" | ||||
| 	case Base: | ||||
| 		return "" | ||||
| 	case Kilo: | ||||
| 		return "K" | ||||
| 	case Mega: | ||||
| 		return "M" | ||||
| 	case Giga: | ||||
| 		return "G" | ||||
| 	case Tera: | ||||
| 		return "T" | ||||
| 	case Peta: | ||||
| 		return "P" | ||||
| 	case Exa: | ||||
| 		return "E" | ||||
| 	case Zetta: | ||||
| 		return "Z" | ||||
| 	case Yotta: | ||||
| 		return "Y" | ||||
| 	case Milli: | ||||
| 		return "m" | ||||
| 	case Micro: | ||||
| 		return "u" | ||||
| 	case Nano: | ||||
| 		return "n" | ||||
| 	case Kibi: | ||||
| 		return "Ki" | ||||
| 	case Mebi: | ||||
| 		return "Mi" | ||||
| 	case Gibi: | ||||
| 		return "Gi" | ||||
| 	case Tebi: | ||||
| 		return "Ti" | ||||
| 	default: | ||||
| 		return "<unkn>" | ||||
| func (p *Prefix) Prefix() string { | ||||
| 	if data, ok := PrefixDataMap[*p]; ok { | ||||
| 		return data.Short | ||||
| 	} | ||||
| 	return InvalidMeasureShort | ||||
| } | ||||
|  | ||||
| // NewPrefix creates a new prefix out of a string representing a unit like 'k', 'K', 'M' or 'G'. | ||||
| func NewPrefix(prefix string) Prefix { | ||||
| 	switch prefix { | ||||
| 	case "k": | ||||
| 		return Kilo | ||||
| 	case "K": | ||||
| 		return Kilo | ||||
| 	case "m": | ||||
| 		return Milli | ||||
| 	case "M": | ||||
| 		return Mega | ||||
| 	case "g": | ||||
| 		return Giga | ||||
| 	case "G": | ||||
| 		return Giga | ||||
| 	case "t": | ||||
| 		return Tera | ||||
| 	case "T": | ||||
| 		return Tera | ||||
| 	case "p": | ||||
| 		return Peta | ||||
| 	case "P": | ||||
| 		return Peta | ||||
| 	case "e": | ||||
| 		return Exa | ||||
| 	case "E": | ||||
| 		return Exa | ||||
| 	case "z": | ||||
| 		return Zetta | ||||
| 	case "Z": | ||||
| 		return Zetta | ||||
| 	case "y": | ||||
| 		return Yotta | ||||
| 	case "Y": | ||||
| 		return Yotta | ||||
| 	case "u": | ||||
| 		return Micro | ||||
| 	case "n": | ||||
| 		return Nano | ||||
| 	case "ki": | ||||
| 		return Kibi | ||||
| 	case "Ki": | ||||
| 		return Kibi | ||||
| 	case "Mi": | ||||
| 		return Mebi | ||||
| 	case "gi": | ||||
| 		return Gibi | ||||
| 	case "Gi": | ||||
| 		return Gibi | ||||
| 	case "Ti": | ||||
| 		return Tebi | ||||
| 	case "": | ||||
| 		return Base | ||||
| 	default: | ||||
| 		return InvalidPrefix | ||||
| 	for p, data := range PrefixDataMap { | ||||
| 		regex := regexp.MustCompile(data.Regex) | ||||
| 		match := regex.FindStringSubmatch(prefix) | ||||
| 		if match != nil { | ||||
| 			return p | ||||
| 		} | ||||
| 	} | ||||
| 	return InvalidPrefix | ||||
| } | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| // Unit system for cluster monitoring metrics like bytes, flops and events | ||||
| package ccunits | ||||
|  | ||||
| import ( | ||||
| @@ -204,7 +205,7 @@ func NewUnit(unitStr string) Unit { | ||||
| 		measure:    InvalidMeasure, | ||||
| 		divMeasure: InvalidMeasure, | ||||
| 	} | ||||
| 	matches := prefixRegex.FindStringSubmatch(unitStr) | ||||
| 	matches := prefixUnitSplitRegex.FindStringSubmatch(unitStr) | ||||
| 	if len(matches) > 2 { | ||||
| 		pre := NewPrefix(matches[1]) | ||||
| 		measures := strings.Split(matches[2], "/") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user