219 lines
5.7 KiB
Python
219 lines
5.7 KiB
Python
#
|
|
# Copyright(c) 2019-2021 Intel Corporation
|
|
# Copyright(c) 2024 Huawei Technologies Co., Ltd.
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
#
|
|
|
|
import enum
|
|
import math
|
|
import random
|
|
|
|
from multimethod import multimethod
|
|
|
|
|
|
def parse_unit(str_unit: str):
|
|
for u in Unit:
|
|
if str_unit == u.name:
|
|
return u
|
|
|
|
if str_unit == "KiB":
|
|
return Unit.KibiByte
|
|
elif str_unit in ["4KiB blocks", "4KiB Blocks"]:
|
|
return Unit.Blocks4096
|
|
elif str_unit == "MiB":
|
|
return Unit.MebiByte
|
|
elif str_unit == "GiB":
|
|
return Unit.GibiByte
|
|
elif str_unit == "TiB":
|
|
return Unit.TebiByte
|
|
|
|
if str_unit == "B":
|
|
return Unit.Byte
|
|
elif str_unit == "KB":
|
|
return Unit.KiloByte
|
|
elif str_unit == "MB":
|
|
return Unit.MegaByte
|
|
elif str_unit == "GB":
|
|
return Unit.GigaByte
|
|
elif str_unit == "TB":
|
|
return Unit.TeraByte
|
|
|
|
raise ValueError(f"Unable to parse {str_unit}")
|
|
|
|
|
|
class Unit(enum.Enum):
|
|
Byte = 1
|
|
KiloByte = 1000
|
|
KibiByte = 1024
|
|
MegaByte = 1000 * KiloByte
|
|
MebiByte = 1024 * KibiByte
|
|
GigaByte = 1000 * MegaByte
|
|
GibiByte = 1024 * MebiByte
|
|
TeraByte = 1000 * GigaByte
|
|
TebiByte = 1024 * GibiByte
|
|
Blocks512 = 512
|
|
Blocks4096 = 4096
|
|
|
|
KiB = KibiByte
|
|
KB = KiloByte
|
|
MiB = MebiByte
|
|
MB = MegaByte
|
|
GiB = GibiByte
|
|
GB = GigaByte
|
|
TiB = TebiByte
|
|
TB = TeraByte
|
|
|
|
def get_value(self):
|
|
return self.value
|
|
|
|
def __str__(self):
|
|
return self.get_name()
|
|
|
|
def get_name(self):
|
|
return self.name
|
|
|
|
def get_short_name(self):
|
|
if self == Unit.Byte:
|
|
return "B"
|
|
elif self == Unit.KibiByte:
|
|
return "KiB"
|
|
elif self == Unit.KiloByte:
|
|
return "KB"
|
|
elif self == Unit.MebiByte:
|
|
return "MiB"
|
|
elif self == Unit.MegaByte:
|
|
return "MB"
|
|
elif self == Unit.GibiByte:
|
|
return "GiB"
|
|
elif self == Unit.GigaByte:
|
|
return "GB"
|
|
elif self == Unit.TebiByte:
|
|
return "TiB"
|
|
elif self == Unit.TeraByte:
|
|
return "TB"
|
|
raise ValueError(f"Unable to get short unit name for {self}.")
|
|
|
|
|
|
class UnitPerSecond:
|
|
def __init__(self, unit):
|
|
self.value = unit.get_value()
|
|
self.name = unit.name + "/s"
|
|
|
|
def get_value(self):
|
|
return self.value
|
|
|
|
|
|
class Size:
|
|
def __init__(self, value: float, unit: Unit = Unit.Byte):
|
|
if value < 0:
|
|
raise ValueError("Size has to be positive.")
|
|
self.value = value * unit.value
|
|
self.unit = unit
|
|
|
|
def __str__(self):
|
|
return f"{self.get_value(self.unit)} {self.unit}"
|
|
|
|
def __hash__(self):
|
|
return self.value.__hash__()
|
|
|
|
def __int__(self):
|
|
return int(self.get_value())
|
|
|
|
def __add__(self, other):
|
|
return Size(self.get_value() + other.get_value())
|
|
|
|
def __lt__(self, other):
|
|
return self.get_value() < other.get_value()
|
|
|
|
def __le__(self, other):
|
|
return self.get_value() <= other.get_value()
|
|
|
|
def __eq__(self, other):
|
|
return self.get_value() == other.get_value()
|
|
|
|
def __ne__(self, other):
|
|
return self.get_value() != other.get_value()
|
|
|
|
def __gt__(self, other):
|
|
return self.get_value() > other.get_value()
|
|
|
|
def __ge__(self, other):
|
|
return self.get_value() >= other.get_value()
|
|
|
|
def __radd__(self, other):
|
|
return Size(other + self.get_value())
|
|
|
|
def __sub__(self, other):
|
|
if self < other:
|
|
raise ValueError("Subtracted value is too big. Result size cannot be negative.")
|
|
return Size(self.get_value() - other.get_value())
|
|
|
|
@multimethod
|
|
def __mul__(self, other: int):
|
|
return Size(math.ceil(self.get_value() * other))
|
|
|
|
@multimethod
|
|
def __rmul__(self, other: int):
|
|
return Size(math.ceil(self.get_value() * other))
|
|
|
|
@multimethod
|
|
def __mul__(self, other: float):
|
|
return Size(math.ceil(self.get_value() * other))
|
|
|
|
@multimethod
|
|
def __rmul__(self, other: float):
|
|
return Size(math.ceil(self.get_value() * other))
|
|
|
|
@multimethod
|
|
def __truediv__(self, other):
|
|
if other.get_value() == 0:
|
|
raise ValueError("Divisor must not be equal to 0.")
|
|
return self.get_value() / other.get_value()
|
|
|
|
@multimethod
|
|
def __truediv__(self, other: int):
|
|
if other == 0:
|
|
raise ValueError("Divisor must not be equal to 0.")
|
|
return Size(math.ceil(self.get_value() / other))
|
|
|
|
def set_unit(self, new_unit: Unit):
|
|
new_size = Size(self.get_value(target_unit=new_unit), unit=new_unit)
|
|
|
|
if new_size != self:
|
|
raise ValueError(f"{new_unit} is not precise enough for {self}")
|
|
|
|
self.value = new_size.value
|
|
self.unit = new_size.unit
|
|
|
|
return self
|
|
|
|
def get_value(self, target_unit: Unit = Unit.Byte):
|
|
return self.value / target_unit.value
|
|
|
|
def is_zero(self):
|
|
if self.value == 0:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def align_up(self, alignment):
|
|
if self == self.align_down(alignment):
|
|
return Size(int(self))
|
|
return Size(int(self.align_down(alignment)) + alignment)
|
|
|
|
def align_down(self, alignment):
|
|
if alignment <= 0:
|
|
raise ValueError("Alignment must be a positive value!")
|
|
if alignment & (alignment - 1):
|
|
raise ValueError("Alignment must be a power of two!")
|
|
return Size(int(self) & ~(alignment - 1))
|
|
|
|
@staticmethod
|
|
def zero():
|
|
return Size(0)
|
|
|
|
@staticmethod
|
|
def generate_random_size(min_size: int, max_size: int, unit: Unit):
|
|
size = random.randint(min_size, max_size)
|
|
return Size(value=float(size), unit=unit)
|