about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/fixedint
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/fixedint')
-rw-r--r--.venv/lib/python3.12/site-packages/fixedint/__init__.py9
-rw-r--r--.venv/lib/python3.12/site-packages/fixedint/aliases.py11
-rw-r--r--.venv/lib/python3.12/site-packages/fixedint/base.py468
-rw-r--r--.venv/lib/python3.12/site-packages/fixedint/compat.py20
-rw-r--r--.venv/lib/python3.12/site-packages/fixedint/test_fixedint.py319
-rw-r--r--.venv/lib/python3.12/site-packages/fixedint/util.py8
6 files changed, 835 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/fixedint/__init__.py b/.venv/lib/python3.12/site-packages/fixedint/__init__.py
new file mode 100644
index 00000000..c9c575a8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fixedint/__init__.py
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from fixedint.base import FixedInt, MutableFixedInt
+from fixedint.aliases import *
+
+def test(verbosity=1, repeat=1):
+    from fixedint import test_fixedint
+    return test_fixedint.run(verbosity, repeat)
diff --git a/.venv/lib/python3.12/site-packages/fixedint/aliases.py b/.venv/lib/python3.12/site-packages/fixedint/aliases.py
new file mode 100644
index 00000000..66c379a9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fixedint/aliases.py
@@ -0,0 +1,11 @@
+from fixedint.base import FixedInt, MutableFixedInt
+
+__all__ = []
+
+for i in [8,16,32,64]:
+    for s in [True, False]:
+        for m in [True, False]:
+            cls = FixedInt(i, signed=s, mutable=m)
+            cls.__module__ = __name__
+            __all__ += [cls.__name__]
+            globals()[cls.__name__] = cls
diff --git a/.venv/lib/python3.12/site-packages/fixedint/base.py b/.venv/lib/python3.12/site-packages/fixedint/base.py
new file mode 100644
index 00000000..ff93d43b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fixedint/base.py
@@ -0,0 +1,468 @@
+# -*- coding: utf-8 -*-
+
+import sys
+from fixedint.compat import *
+from weakref import WeakValueDictionary
+
+class FixedProperty(object):
+    def __init__(self, val, doc):
+        self.val = val
+        self.__doc__ = doc
+    def __get__(self, obj, type=None):
+        return self.val
+    def __set__(self, obj, value):
+        raise AttributeError("property is read-only")
+
+class FixedMetaProperty(object):
+    def __init__(self, name, doc):
+        self.name = name
+        self.__doc__ = doc
+    def __get__(self, obj, type=None):
+        if self.name not in obj.__dict__:
+            # this should only happen when trying to access FixedInt.prop, which help() does
+            raise AttributeError("Attribute %s not defined on base class" % self.name)
+        prop = obj.__dict__[self.name]
+        return prop.__get__(obj)
+    def __set__(self, obj, value):
+        raise AttributeError("property %s is read-only" % self.name)
+
+if not PY3K:
+    # While it'd be nice to put machine-sized integers into Python 2.x "int"s,
+    # it turns out that the int methods occasionally freak out when given longs.
+    # So, we use arbitrary-precision ints for all Pythons.
+    int = long
+
+_class_cache = WeakValueDictionary()
+
+_doc_width = "Bit width of this integer, including the sign bit."
+_doc_signed = "True if this integer is a twos-complement signed type."
+_doc_mutable = "True if this integer is mutable (modifiable in-place)."
+_doc_minval = "Minimum representable value of this integer type"
+_doc_maxval = "Maximum representable value of this integer type"
+
+_subclass_token = object()
+class _FixedIntBaseMeta(type):
+    def __new__(cls, name, bases, dict):
+        if dict.get('_subclass_enable', None) == _subclass_token:
+            del dict['_subclass_enable']
+            return type.__new__(cls, name, bases, dict)
+
+        for base in bases:
+            if issubclass(base, FixedInt):
+                basename = base.__name__
+                raise Exception("Cannot subclass %s; use the %s constructor to produce new subclasses." % (basename, basename))
+        raise Exception("Cannot subclass this class.")
+
+    def __call__(self, width, signed=True, mutable=None):
+        signed = bool(signed)
+        if mutable is None:
+            # Take mutable from constructor used (FixedInt or MutableFixedInt)
+            mutable = (self == MutableFixedInt)
+
+        cachekey = (width, signed, mutable)
+        try:
+            return _class_cache[cachekey]
+        except KeyError:
+            pass
+            
+        if signed:
+            min = -1<<(width-1)
+            max = (1<<(width-1))-1
+        else:
+            min = 0
+            max = (1<<width)-1
+
+        if mutable:
+            bases = (MutableFixedInt,)
+        else:
+            bases = (FixedInt, int)
+
+        dict = {}
+        dict['width'] = FixedProperty(width, doc=_doc_width)
+        dict['signed'] = FixedProperty(signed, doc=_doc_signed)
+        dict['mutable'] = FixedProperty(mutable, doc=_doc_mutable)
+        dict['minval'] = FixedProperty(min, doc=_doc_minval)
+        dict['maxval'] = FixedProperty(max, doc=_doc_maxval)
+
+        if signed:
+            _mask1 = (1<<(width-1)) - 1
+            _mask2 = 1<<(width-1)
+            def _rectify(val):
+                return (val & _mask1) - (val & _mask2)
+        else:
+            _mask = (1<<width) - 1
+            def _rectify(val):
+                return val & _mask
+        dict['_rectify'] = staticmethod(_rectify)
+
+        if not mutable:
+            intbase = bases[1]
+            def _newfunc(cls, val=0):
+                ''' Convert an integer into a fixed-width integer. '''
+                return intbase.__new__(cls, _rectify(int(val)))
+            _newfunc.__name__ = '__new__'
+            dict['__new__'] = _newfunc
+
+        name = ''.join(['Mutable'*mutable, 'U'*(not signed), 'Int', str(width)])
+
+        cls = _FixedIntMeta(name, bases, dict)
+        _class_cache[cachekey] = cls
+        return cls
+
+    width = FixedMetaProperty('width', doc=_doc_width)
+    signed = FixedMetaProperty('signed', doc=_doc_signed)
+    mutable = FixedMetaProperty('mutable', doc=_doc_mutable)
+    minval = FixedMetaProperty('minval', doc=_doc_minval)
+    maxval = FixedMetaProperty('maxval', doc=_doc_maxval)
+
+class _FixedIntMeta(_FixedIntBaseMeta):
+    __new__ = type.__new__
+    __call__ = type.__call__
+
+
+def int_method(f):
+    if isinstance(f, str):
+        def wrapper(f2):
+            f2.__name__ = f
+            return int_method(f2)
+        return wrapper
+    else:
+        f.__doc__ = getattr(int, f.__name__).__doc__
+        return f
+
+class FixedInt:
+    __slots__ = ()
+    _subclass_enable = _subclass_token
+
+    # width, signed, mutable, minval, maxval defined in metaclass
+    # _rectify defined in metaclass
+    # __new__ defined in metaclass
+
+    if not PY3K:
+        @int_method
+        def __hex__(self):
+            return '%#x' % int(self)
+        def __oct__(self):
+            return '%#o' % int(self)
+
+    @int_method
+    def __pow__(self, other, modulo=None):
+        # Jython can't handle int.__pow__(x, y, None)
+        if modulo is None:
+            return type(self)(int.__pow__(int(self), int(other)))
+        return type(self)(int.__pow__(int(self), int(other), modulo))
+
+    @int_method
+    def __rpow__(self, other):
+        return type(other)(int.__rpow__(int(self), int(other)))
+
+    @int_method
+    def __repr__(self):
+        return '%s(%s)' % (type(self).__name__, self)
+
+    @int_method
+    def __str__(self):
+        return str(int(self))
+
+    @classmethod
+    def _canonicalize_index(cls, idx):
+        if idx < 0:
+            idx += cls.width
+        return idx
+
+    @classmethod
+    def _canonicalize_slice(cls, slice):
+        start = slice.start
+        stop = slice.stop
+
+        if slice.step is not None:
+            raise ValueError("slice step unsupported")
+
+        if start is None:
+            start = 0
+        else:
+            start = cls._canonicalize_index(start)
+
+        if stop is None:
+            stop = cls.width
+        elif isinstance(stop, complex):
+            if stop.real:
+                raise ValueError("invalid slice stop: must be integer or pure-imaginary complex number")
+            stop = int(stop.imag) + start
+        else:
+            stop = cls._canonicalize_index(stop)
+
+        if 0 <= start < stop <= cls.width:
+            return (start, stop)
+        else:
+            raise IndexError("invalid slice %d:%d" % (start, stop))
+
+    def __getitem__(self, item):
+        ''' Slice the bits of an integer.
+
+        x[a] gets a single bit at position a, returning a bool.
+        x[a:b] gets a range of bits as a FixedInt.
+
+        For slice notation, b may be of the form 'bj' (a complex number) to treat it
+        as a length rather than a stop index.
+        The result will be of the type UIntX, where X is the number of bits in the range.
+
+        Examples:
+        x[0]: equal to (x & 1)
+        x[1:5] or x[1:4j]: equal to (x & 31) >> 1
+        x[:5]: equal to (x & 31)
+        '''
+
+        if isinstance(item, slice):
+            start, stop = self._canonicalize_slice(item)
+            return FixedInt(stop - start, signed=False)(int(self) >> start)
+        else:
+            item = self._canonicalize_index(item)
+            if 0 <= item < self.width:
+                return bool(int(self) & (1 << item))
+            else:
+                raise IndexError("index %d out of range" % item)
+
+    def to_bytes(self, length=None, byteorder=sys.byteorder):
+        if length is None:
+            length = (self.width + 7) // 8
+        try:
+            return int(self).to_bytes(length, byteorder=byteorder, signed=self.signed)
+        except (OverflowError, AttributeError):
+            pass
+
+        val = int(self) & ((1 << (length * 8)) - 1)
+        out = []
+        while length > 0:
+            out.append(val & 0xff)
+            val >>= 8
+            length -= 1
+        if byteorder == 'big':
+            out = reversed(out)
+        if PY3K:
+            return bytes(out)
+        else:
+            return ''.join(map(chr, out))
+
+    @classmethod
+    def from_bytes(cls, bytes, byteorder=sys.byteorder, signed=None):
+        if cls in (FixedInt, MutableFixedInt):
+            if signed is None:
+                signed = False
+        elif signed is None:
+                signed = cls.signed
+        else:
+            raise ValueError("can't set signed with a concrete FixedInt")
+
+        blen = len(bytes)
+        try:
+            val = int.from_bytes(bytes, byteorder=byteorder, signed=signed)
+        except AttributeError:
+            val = 0
+            if byteorder == 'big':
+                bytes = reversed(bytes)
+            if PY3K:
+                for i,c in enumerate(bytes):
+                    val |= c << (8 * i)
+            else:
+                for i,c in enumerate(bytes):
+                    val |= ord(c) << (8 * i)
+
+        if cls in (FixedInt, MutableFixedInt):
+            return cls(blen*8, signed=signed)(val)
+        else:
+            return cls(val)
+
+    if PY3K:
+        @int_method
+        def __round__(self, n=0):
+            return int(self)
+
+    # Inherited methods which are fine as-is:
+    # complex, int, long, float, index
+    # truediv, rtruediv, divmod, rdivmod, rlshift, rrshift
+    # format
+
+FixedInt = add_metaclass(_FixedIntBaseMeta)(FixedInt)
+
+
+class MutableFixedInt(FixedInt):
+    _subclass_enable = _subclass_token
+
+    def __init__(self, val=0, base=None):
+        ''' Convert an integer into a fixed-width integer. '''
+        if base is None:
+            val = int(val)
+        else:
+            val = int(val, base)
+
+        self._val = self._rectify(val)
+
+    if PY3K:
+        @int_method
+        def __format__(self, format_spec):
+            return format(self._val, format_spec)
+
+    def __ipow__(self, other, modulo=None):
+        if modulo is None:
+            self._val = self._rectify(int.__pow__(int(self), int(other)))
+        else:
+            self._val = self._rectify(int.__pow__(int(self), int(other), modulo))
+        return self
+
+    def __setitem__(self, item, value):
+        ''' Modify a slice of an integer.
+
+        x[a]=y sets a single bit at position a.
+        x[a:b]=y sets a range of bits from an integer.
+
+        See __getitem__ for more details on the slice notation.
+        '''
+
+        value = int(value)
+        if isinstance(item, slice):
+            start, stop = self._canonicalize_slice(item)
+            mask = (1 << (stop - start)) - 1
+            self._val = (self._val & ~(mask << start)) | ((value & mask) << start)
+        else:
+            item = self._canonicalize_index(item)
+            if 0 <= item < self.width:
+                if value:
+                    self._val |= (1 << item)
+                else:
+                    self._val &= ~(1 << item)
+                return bool(int(self) & (1 << item))
+            else:
+                raise IndexError("index %d out of range" % item)
+
+## Arithmetic methods
+def _arith_unary_factory(name, mutable):
+    ''' Factory function producing methods for unary operations. '''
+    intfunc = getattr(int, name)
+    if mutable:
+        @int_method(name)
+        def _f(self):
+            return type(self)(intfunc(self._val))
+    else:
+        @int_method(name)
+        def _f(self):
+            return type(self)(intfunc(self))
+    return _f
+
+_arith_unary = 'neg pos abs invert'.split()
+for f in _arith_unary:
+    s = '__%s__' % f
+    setattr(FixedInt, s, _arith_unary_factory(s, mutable=False))
+    setattr(MutableFixedInt, s, _arith_unary_factory(s, mutable=True))
+
+
+def _arith_convert(t1, t2):
+    if not issubclass(t2, FixedInt):
+        return t1
+
+    # Follow C conversion rules (ISO/IEC 9899:TC3 ยง6.3.1.8)
+    if t1.signed == t2.signed:
+        # If both are signed or both are unsigned, return the larger type.
+        if t1.width >= t2.width:
+            return t1
+        return t2
+
+    if not t1.signed:
+        ut, st = t1, t2
+    else:
+        ut, st = t2, t1
+
+    if ut.width >= st.width:
+        # If the unsigned type has rank >= the signed type, convert the signed type to the unsigned type.
+        return ut
+    else:
+        return st
+
+def _arith_binfunc_factory(name):
+    ''' Factory function producing methods for arithmetic operators '''
+    intfunc = getattr(int, name)
+    @int_method(name)
+    def _f(self, other):
+        nt = _arith_convert(type(self), type(other))
+        return nt(intfunc(int(self), int(other)))
+    return _f
+
+# divmod, rdivmod, truediv, rtruediv are considered non-arithmetic since they don't return ints
+# pow, rpow, rlshift, and rrshift are special since the LHS and RHS are very different
+_arith_binfunc = 'add sub mul floordiv mod lshift rshift and xor or'.split()
+_arith_binfunc += 'radd rsub rmul rfloordiv rmod rand rxor ror'.split()
+if not PY3K:
+    _arith_binfunc += 'div rdiv'.split()
+
+for f in _arith_binfunc:
+    s = '__%s__' % f
+    setattr(FixedInt, s, _arith_binfunc_factory(s))
+
+
+## Non-arithmetic methods (Mutable only)
+def _nonarith_unary_factory_mutable(name):
+    ''' Factory function producing methods for unary operations. '''
+    intfunc = getattr(int, name)
+    @int_method(name)
+    def _f(self):
+        return intfunc(self._val)
+    return _f
+
+_mutable_unary = 'int float'.split()
+if sys.version_info[:2] >= (2,5):
+    _mutable_unary += ['index']
+if sys.version_info[:2] >= (2,6):
+    _mutable_unary += ['trunc']
+if PY3K:
+    _mutable_unary += 'bool'.split()
+else:
+    _mutable_unary += 'nonzero long'.split()
+
+for f in _mutable_unary:
+    s = '__%s__' % f
+    setattr(MutableFixedInt, s, _nonarith_unary_factory_mutable(s))
+
+
+def _nonarith_binfunc_factory_mutable(name):
+    ''' Factory function producing methods for non-arithmetic binary operators on Mutable instances. '''
+    intfunc = getattr(int, name)
+    @int_method(name)
+    def _f(self, other):
+        return intfunc(self._val, int(other))
+    return _f
+
+_mutable_binfunc = 'truediv rtruediv divmod rdivmod rlshift rrshift'.split()
+if hasattr(int, '__cmp__'):
+    _mutable_binfunc += ['cmp']
+else:
+    _mutable_binfunc += 'lt le eq ne gt ge'.split()
+for f in _mutable_binfunc:
+    s = '__%s__' % f
+    setattr(MutableFixedInt, s, _nonarith_binfunc_factory_mutable(s))
+
+
+## In-place operators
+def _inplace_factory_mutable(iname, name, op):
+    ''' Factory function producing methods for augmented assignments on Mutable instances. '''
+    # This uses compiled operators instead of an int.__X__ function call for speed.
+    # Measured improvement is about 15% speed increase.
+    exec("""
+def _f(self, other):
+    self._val = self._rectify(self._val %s int(other))
+    return self
+globals()['_f'] = _f""" % op)
+    _f.__name__ = iname
+    doc = list.__iadd__.__doc__
+    if doc:
+        _f.__doc__ = doc.replace('__iadd__', name).replace('+=', op+'=')
+    return _f
+
+# pow is special because it takes three arguments.
+_inplace_func = 'add,+ sub,- mul,* truediv,/ floordiv,// mod,% lshift,<< rshift,<< and,& or,| xor,^'.split()
+if not PY3K:
+    _inplace_func += ['div,/']
+for f in _inplace_func:
+    fn, op = f.split(',')
+    si = '__i%s__' % fn
+    so = '__%s__' % fn
+    setattr(MutableFixedInt, si, _inplace_factory_mutable(si, so, op))
diff --git a/.venv/lib/python3.12/site-packages/fixedint/compat.py b/.venv/lib/python3.12/site-packages/fixedint/compat.py
new file mode 100644
index 00000000..4dcc240c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fixedint/compat.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+import sys
+
+PY3K = sys.version_info[0] >= 3
+
+# add_metaclass from six.py, (c) 2010-2014 Benjamin Peterson
+def add_metaclass(metaclass):
+    """Class decorator for creating a class with a metaclass."""
+    def wrapper(cls):
+        orig_vars = cls.__dict__.copy()
+        orig_vars.pop('__dict__', None)
+        orig_vars.pop('__weakref__', None)
+        slots = orig_vars.get('__slots__')
+        if slots is not None:
+            if isinstance(slots, str):
+                slots = [slots]
+            for slots_var in slots:
+                orig_vars.pop(slots_var)
+        return metaclass(cls.__name__, cls.__bases__, orig_vars)
+    return wrapper
diff --git a/.venv/lib/python3.12/site-packages/fixedint/test_fixedint.py b/.venv/lib/python3.12/site-packages/fixedint/test_fixedint.py
new file mode 100644
index 00000000..721f6742
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fixedint/test_fixedint.py
@@ -0,0 +1,319 @@
+import unittest
+import sys
+
+PY3K = sys.version_info[0] >= 3
+
+from fixedint import *
+
+tests = []
+
+# ----------------------------------------------------------------------------
+class ClassTests(unittest.TestCase):
+    def test_subclass_base(self):
+        self.assertRaises(Exception, type, 'TestClass', (FixedInt,), {})
+        self.assertRaises(Exception, type, 'TestClass', (MutableFixedInt,), {})
+
+    def test_class_cache(self):
+        self.assertEqual(FixedInt(99), FixedInt(99))
+        self.assertEqual(MutableFixedInt(42), MutableFixedInt(42))
+
+    def test_aliases(self):
+        self.assertEqual(FixedInt(8), Int8)
+        self.assertEqual(FixedInt(16), Int16)
+        self.assertEqual(FixedInt(32), Int32)
+        self.assertEqual(FixedInt(64), Int64)
+        self.assertEqual(FixedInt(8, signed=False), UInt8)
+        self.assertEqual(FixedInt(16, signed=False), UInt16)
+        self.assertEqual(FixedInt(32, signed=False), UInt32)
+        self.assertEqual(FixedInt(64, signed=False), UInt64)
+
+    def test_subclassing(self):
+        from fixedint.util import HexFormattingMixin
+        class MyUInt32(HexFormattingMixin, UInt32):
+            pass
+        self.assertEqual(str(MyUInt32(32)), '0x00000020')
+
+tests.append(ClassTests)
+
+# ----------------------------------------------------------------------------
+class BasicTests(unittest.TestCase):
+    def test_properties(self):
+        f3 = FixedInt(3)
+        self.assertEqual(f3.width, 3)
+        self.assertEqual(f3.mutable, False)
+        self.assertEqual(f3.signed, True)
+        self.assertEqual(f3.minval, -4)
+        self.assertEqual(f3.maxval, 3)
+
+        f3 = MutableFixedInt(3)
+        self.assertEqual(f3.width, 3)
+        self.assertEqual(f3.mutable, True)
+        self.assertEqual(f3.signed, True)
+        self.assertEqual(f3.minval, -4)
+        self.assertEqual(f3.maxval, 3)
+
+        f3 = FixedInt(3, signed=False)
+        self.assertEqual(f3.width, 3)
+        self.assertEqual(f3.mutable, False)
+        self.assertEqual(f3.signed, False)
+        self.assertEqual(f3.minval, 0)
+        self.assertEqual(f3.maxval, 7)
+
+        f3 = MutableFixedInt(3, signed=False)
+        self.assertEqual(f3.width, 3)
+        self.assertEqual(f3.mutable, True)
+        self.assertEqual(f3.signed, False)
+        self.assertEqual(f3.minval, 0)
+        self.assertEqual(f3.maxval, 7)
+
+    def test_rectify(self):
+        for f10 in [FixedInt(10), MutableFixedInt(10)]:
+            self.assertEqual(int(f10(1024)), 0)
+            self.assertEqual(int(f10(1025)), 1)
+            self.assertEqual(int(f10(511)), 511)
+            self.assertEqual(int(f10(512)), -512)
+
+        for f10 in [FixedInt(10, signed=False), MutableFixedInt(10, signed=False)]:
+            self.assertEqual(int(f10(1024)), 0)
+            self.assertEqual(int(f10(1025)), 1)
+            self.assertEqual(int(f10(511)), 511)
+            self.assertEqual(int(f10(512)), 512)
+
+    def test_simple_arith(self):
+        for f8 in [Int8, MutableInt8]:
+            a = f8(15)
+            b = f8(10)
+            self.assertEqual(int(a+b), 25)
+            self.assertEqual(int(a-b), 5)
+            self.assertEqual(int(a*b), (150-256))
+            self.assertEqual(a.__truediv__(b), 1.5)
+            self.assertEqual(int(a // b), 1)
+            self.assertEqual(divmod(a, b), (1, 5))
+            self.assertEqual(divmod(15, b), (1, 5))
+            self.assertEqual(divmod(a, 10), (1, 5))
+            self.assertEqual(int(a)**b, 15**10)
+            self.assertEqual(int(a<<8), 0)
+            self.assertEqual(8<<a, 8<<15)
+            self.assertEqual(int(~a), ~15)
+            self.assertEqual(int(-a), -15)
+            self.assertEqual(int((~a) & 0xff), ~15)
+        for f64 in [Int64, MutableInt64]:
+            a = f64(15)
+            b = f64(10)
+            self.assertEqual(int(a+b), 25)
+            self.assertEqual(int(a-b), 5)
+            self.assertEqual(int(a*b), 150)
+            self.assertEqual(a.__truediv__(b), 1.5)
+            self.assertEqual(int(a // b), 1)
+            self.assertEqual(divmod(a, b), (1, 5))
+            self.assertEqual(divmod(15, b), (1, 5))
+            self.assertEqual(divmod(a, 10), (1, 5))
+            self.assertEqual(int(a)**b, 15**10)
+            self.assertEqual(int(a<<8), 15<<8)
+            self.assertEqual(8<<a, 8<<15)
+            self.assertEqual(int(~a), ~15)
+            self.assertEqual(int(-a), -15)
+
+    def test_typecast(self):
+        import math
+        for f16 in [Int16, MutableInt16]:
+            x = f16(42)
+            self.assertEqual(int(x), 42)
+            self.assertEqual(float(x), 42)
+            self.assertEqual(complex(x), 42)
+            self.assertEqual(round(x), 42)
+            if not PY3K:
+                self.assertEqual(long(x), 42)
+            self.assertEqual(bool(x), True)
+            if sys.version_info[:2] >= (2,5):
+                self.assertEqual(list(range(100))[x], 42)
+            if sys.version_info[:2] >= (2,6):
+                self.assertEqual(math.trunc(x), 42)
+
+            x = f16(0)
+            self.assertEqual(bool(x), False)
+
+    def test_compare(self):
+        for f32 in [Int32, MutableInt32]:
+            x = f32(1000000)
+            self.assertEqual(x, 1000000)
+            self.assertNotEqual(x, 1000000 + (1<<32))
+            self.assertEqual(x, f32(1000000 + (1<<32)))
+            self.assertNotEqual(x, 1000001)
+            self.assertTrue(x <= 1000000)
+            self.assertTrue(x >= 1000000)
+            self.assertTrue(x < 1000001)
+            self.assertTrue(x > 999999)
+            if not PY3K:
+                self.assertTrue(cmp(x, 999999) > 0)
+
+    def test_implicit_conversion(self):
+        f = FixedInt(72)
+        x = f(32767)
+        y = x
+        self.assertEqual(x, y)
+        x += 100
+        self.assertNotEqual(x, y)
+        x += FixedInt(80)(1<<79)
+        self.assertEqual(x.width, 80)
+
+    def test_inplace_operators(self):
+        mf = MutableFixedInt(72)
+        x = mf(32767)
+        y = x
+        self.assertEqual(x, y)
+        x += 100
+        self.assertEqual(x, y)
+        x += MutableFixedInt(80)(1<<79)
+        self.assertEqual(x.width, 72)
+        x >>= 100
+        self.assertEqual(x, 0)
+        x += 2
+        self.assertEqual(y, 2)
+        x **= 70
+        self.assertEqual(y, 2**70)
+
+    def test_str(self):
+        for ff in [FixedInt(12), MutableFixedInt(12), FixedInt(91), MutableFixedInt(91)]:
+            self.assertEqual(str(ff(1)), '1')
+            self.assertEqual(repr(ff(1)), '%s(1)' % ff.__name__)
+            self.assertEqual(str(ff(-1)), '-1')
+            self.assertEqual(hex(ff(1)), '0x1')
+
+tests.append(BasicTests)
+
+# ----------------------------------------------------------------------------
+class ExtraFunctionTests(unittest.TestCase):
+    def test_bytes(self):
+        for ff in [FixedInt(96), MutableFixedInt(96)]:
+            val = ff(-1)
+            if PY3K:
+                byte = lambda c: bytes([c])
+            else:
+                byte = lambda c: chr(c)
+            self.assertEqual(val.to_bytes(), byte(255) * 12)
+            self.assertEqual(val.to_bytes(8), byte(255) * 8)
+            self.assertEqual(ff.from_bytes(byte(255) * 12), val)
+
+        for ff in [FixedInt(32), MutableFixedInt(32)]:
+            for v in [0xdeadbeef, 0xfeedface, 0x0badf00d, 0x12345678, 0x87654321]:
+                for endian in ['big', 'little']:
+                    val = ff(v)
+                    data = val.to_bytes(byteorder=endian)
+                    self.assertEqual(len(data), 4)
+                    val2 = ff.from_bytes(data, byteorder=endian)
+                    self.assertEqual(val, val2)
+
+        for ff in [UInt32, MutableUInt32]:
+            for v in [0xdeadbeef, 0xfeedface, 0x0badf00d, 0x12345678, 0x87654321]:
+                for endian in ['big', 'little']:
+                    val = ff(v)
+                    data = val.to_bytes(byteorder=endian)
+                    self.assertEqual(len(data), 4)
+                    val2 = FixedInt.from_bytes(data, byteorder=endian, signed=False)
+                    self.assertTrue(type(val2).__name__.endswith('UInt32'))
+                    self.assertEqual(val, val2)
+
+        t = UInt32(32).to_bytes()
+        self.assertRaises(ValueError, UInt32.from_bytes, t, signed=True)
+
+    def test_slice_errors(self):
+        ff = FixedInt(24)
+        val = ff(1024)
+        # Steps unsupported
+        self.assertRaises(ValueError, lambda:val[::-1])
+        self.assertRaises(ValueError, lambda:val[::1])
+        # Mixed complex numbers unsupported
+        self.assertRaises(ValueError, lambda:val[:2+4j])
+        # Invalid indices
+        self.assertRaises(IndexError, lambda:val[100:200])
+        self.assertRaises(IndexError, lambda:val[5:0])
+        self.assertRaises(IndexError, lambda:val[1024])
+
+    def test_getslice(self):
+        for ff in [FixedInt(48), MutableFixedInt(48)]:
+            testval = 0xfedcba123456
+            fixed = ff(testval)
+
+            x = testval
+            for i in range(48):
+                self.assertEqual(fixed[i], x & 1)
+                x >>= 1
+
+            x = testval
+            for i in range(12):
+                r = fixed[i*4:i*4+4]
+                self.assertEqual(r, x & 0xf)
+                self.assertEqual(r.width, 4)
+                self.assertEqual(r.signed, False)
+                x >>= 4
+
+            x = testval
+            for i in range(12):
+                r = fixed[i*4:4j]
+                self.assertEqual(r, x & 0xf)
+                self.assertEqual(r.width, 4)
+                self.assertEqual(r.signed, False)
+                x >>= 4
+
+    def test_setslice(self):
+        ff = MutableFixedInt(28, signed=False)
+        testval = 0xbadf00d
+        val = ff(0)
+        for i in range(28):
+            val[i] = testval & (1<<i)
+        self.assertEqual(val, testval)
+
+        val = ff(0)
+        x = testval
+        for i in range(7):
+            val[i*4:i*4+4] = x & 0xf
+            x >>= 4
+        self.assertEqual(val, testval)
+
+        val = ff(0)
+        x = testval
+        for i in range(7):
+            val[i*4:4j] = x & 0xf
+            x >>= 4
+        self.assertEqual(val, testval)
+
+        val = ff(0)
+        val2 = val
+        val[:] = testval
+        self.assertEqual(val2, testval)
+
+    def test_setslice_fixedint(self):
+        # Regression test for GitHub issue #3
+        f16 = FixedInt(16, signed=False, mutable=True)
+        f8 = FixedInt(8, signed=False, mutable=True)
+        x = f16(0x0FFF)
+        y = f8(3)
+        x[0:8] = int(y)
+        assert repr(x) == 'MutableUInt16(3843)'
+        x[0:8] = y
+        assert repr(x) == 'MutableUInt16(3843)'
+
+        f95 = FixedInt(95, signed=False, mutable=True)
+        f40 = FixedInt(40, signed=False, mutable=True)
+        x = f95(0x0FFFFFFFFFFFFFFF)
+        y = f40(0xF)[0:40]
+        x[0:40] = int(y)
+        assert bin(x) == '0b111111111111111111110000000000000000000000000000000000001111'
+        x[0:40] = y
+        assert bin(x) == '0b111111111111111111110000000000000000000000000000000000001111'
+
+tests.append(ExtraFunctionTests)
+
+# ----------------------------------------------------------------------------
+def run(verbosity=1, repeat=1):
+    suite = unittest.TestSuite()
+    for cls in tests:
+        for _ in range(repeat):
+            suite.addTest(unittest.makeSuite(cls))
+
+    runner = unittest.TextTestRunner(verbosity=verbosity)
+    return runner.run(suite)
+
+if __name__ == '__main__':
+    run()
diff --git a/.venv/lib/python3.12/site-packages/fixedint/util.py b/.venv/lib/python3.12/site-packages/fixedint/util.py
new file mode 100644
index 00000000..8c638a93
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/fixedint/util.py
@@ -0,0 +1,8 @@
+class HexFormattingMixin(object):
+    def __str__(self):
+        n = int(self)
+        width = (self.width + 3) // 4
+        if n < 0:
+            return '-0x%0*x' % (width, -n)
+        else:
+            return '0x%0*x' % (width, n)