diff --git a/hdk/common/__init__.py b/hdk/common/__init__.py new file mode 100644 index 000000000..ace1dd1c6 --- /dev/null +++ b/hdk/common/__init__.py @@ -0,0 +1,2 @@ +"""HDK's module for shared data structures and code""" +from . import data_types diff --git a/hdk/common/data_types/__init__.py b/hdk/common/data_types/__init__.py new file mode 100644 index 000000000..256544a3c --- /dev/null +++ b/hdk/common/data_types/__init__.py @@ -0,0 +1,2 @@ +"""HDK's module for data types code and data structures""" +from . import integers diff --git a/hdk/common/data_types/base.py b/hdk/common/data_types/base.py new file mode 100644 index 000000000..47090800d --- /dev/null +++ b/hdk/common/data_types/base.py @@ -0,0 +1,7 @@ +"""File holding code to represent data types in a program""" + +from abc import ABC + + +class BaseDataType(ABC): + """Base class to represent a data type""" diff --git a/hdk/common/data_types/integers.py b/hdk/common/data_types/integers.py new file mode 100644 index 000000000..765b84e8d --- /dev/null +++ b/hdk/common/data_types/integers.py @@ -0,0 +1,70 @@ +"""This file holds the definitions for integer types""" + +from . import base + + +class Integer(base.BaseDataType): + """Class representing an integer""" + + bit_width: int + is_signed: bool + + def __init__(self, bit_width: int, is_signed: bool) -> None: + self.bit_width = bit_width + self.is_signed = is_signed + + def min_value(self) -> int: + """Minimum value representable by the Integer""" + if self.is_signed: + return -(2 ** (self.bit_width - 1)) + + return 0 + + def max_value(self) -> int: + """Maximum value representable by the Integer""" + if self.is_signed: + return 2 ** (self.bit_width - 1) - 1 + + return 2 ** self.bit_width - 1 + + def can_represent_value(self, value_to_represent: int) -> bool: + """A helper function to check if a value is representable by the Integer + + Args: + value_to_represent (int): Value to check + + Returns: + bool: True if the value can be represented by this integer + """ + return self.min_value() <= value_to_represent <= self.max_value() + + +def create_signed_integer(bit_width: int) -> Integer: + """Convenience function to create a signed integer + + Args: + bit_width (int): width of the integer + + Returns: + Integer: A signed integer with the requested bit_width + """ + return Integer(bit_width, is_signed=True) + + +SignedInteger = create_signed_integer + + +def create_unsigned_integer(bit_width: int) -> Integer: + """Convenience function to create an unsigned integer + + Args: + bit_width (int): width of the integer + + Returns: + Integer: An unsigned integer with the requested bit_width + """ + + return Integer(bit_width, is_signed=False) + + +UnsignedInteger = create_unsigned_integer diff --git a/tests/common/data_types/test_integers.py b/tests/common/data_types/test_integers.py new file mode 100644 index 000000000..8e1d12efd --- /dev/null +++ b/tests/common/data_types/test_integers.py @@ -0,0 +1,40 @@ +"""Test file for HDK's common/data_types/integers.py""" + +import random + +import pytest + +from hdk.common.data_types.integers import Integer, SignedInteger, UnsignedInteger + + +@pytest.mark.parametrize( + "integer,expected_min,expected_max", + [ + pytest.param(Integer(8, is_signed=False), 0, 255, id="8 bits unsigned Integer"), + pytest.param(UnsignedInteger(8), 0, 255, id="8 bits UnsignedInteger"), + pytest.param(Integer(8, is_signed=True), -128, 127, id="8 bits signed Integer"), + pytest.param(SignedInteger(8), -128, 127, id="8 bits SignedInteger"), + pytest.param(Integer(32, is_signed=False), 0, 4_294_967_295, id="32 bits unsigned Integer"), + pytest.param(UnsignedInteger(32), 0, 4_294_967_295, id="32 bits UnsignedInteger"), + pytest.param( + Integer(32, is_signed=True), + -2_147_483_648, + 2_147_483_647, + id="32 bits signed Integer", + ), + pytest.param( + SignedInteger(32), + -2_147_483_648, + 2_147_483_647, + id="32 bits SignedInteger", + ), + ], +) +def test_basic_integers(integer: Integer, expected_min: int, expected_max: int): + """Test integer class basic functions""" + assert integer.min_value() == expected_min + assert integer.max_value() == expected_max + + assert integer.can_represent_value(random.randint(expected_min, expected_max)) + assert not integer.can_represent_value(expected_min - 1) + assert not integer.can_represent_value(expected_max + 1)