Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pyvex/utils.py: 73%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

41 statements  

1import struct 

2from collections.abc import Callable 

3from typing import Any 

4 

5try: 

6 import _md5 as md5lib 

7except ImportError: 

8 import hashlib as md5lib 

9 

10 

11md5_unpacker = struct.Struct("4I") 

12 

13 

14def stable_hash(t: tuple) -> int: 

15 cnt = _dump_tuple(t) 

16 hd = md5lib.md5(cnt).digest() 

17 return md5_unpacker.unpack(hd)[0] # 32 bits 

18 

19 

20def _dump_tuple(t: tuple) -> bytes: 

21 cnt = b"" 

22 for item in t: 

23 if item is not None: 

24 type_ = type(item) 

25 if type_ in _DUMP_BY_TYPE: 

26 cnt += _DUMP_BY_TYPE[type_](item) 

27 else: 

28 cnt += struct.pack("<Q", hash(item) & 0xFFFF_FFFF_FFFF_FFFF) 

29 cnt += b"\xf0" 

30 return cnt 

31 

32 

33def _dump_str(t: str) -> bytes: 

34 return t.encode("ascii") 

35 

36 

37def _dump_int(t: int) -> bytes: 

38 prefix = b"" if t >= 0 else b"-" 

39 t = abs(t) 

40 if t <= 0xFFFF: 

41 return prefix + struct.pack("<H", t) 

42 elif t <= 0xFFFF_FFFF: 

43 return prefix + struct.pack("<I", t) 

44 elif t <= 0xFFFF_FFFF_FFFF_FFFF: 

45 return prefix + struct.pack("<Q", t) 

46 else: 

47 cnt = b"" 

48 while t > 0: 

49 cnt += _dump_int(t & 0xFFFF_FFFF_FFFF_FFFF) 

50 t >>= 64 

51 return prefix + cnt 

52 

53 

54def _dump_type(t: type) -> bytes: 

55 return t.__name__.encode("ascii") 

56 

57 

58_DUMP_BY_TYPE: dict[type, Callable[[Any], bytes]] = { 

59 tuple: _dump_tuple, 

60 str: _dump_str, 

61 int: _dump_int, 

62 type: _dump_type, 

63}