Skip to content

Commit 6ffce80

Browse files
authored
Merge pull request #654 from boriel/refact/remove_IdentitySet
refact: replace IdentitySet with set
2 parents c385784 + d7105f8 commit 6ffce80

File tree

5 files changed

+51
-102
lines changed

5 files changed

+51
-102
lines changed

src/api/identityset.py

Lines changed: 0 additions & 70 deletions
This file was deleted.

src/api/utils.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,33 @@
66
import shelve
77
import signal
88
from functools import wraps
9-
from typing import IO, Any, Callable, Iterable, List, Optional, Union
9+
from typing import IO, Any, Callable, Iterable, List, Optional, Union, TypeVar
1010

1111
from src.api import constants, errmsg, global_
1212

13-
__all__ = ["flatten_list", "open_file", "read_txt_file", "sanitize_filename", "timeout"]
13+
__all__ = (
14+
"flatten_list",
15+
"open_file",
16+
"read_txt_file",
17+
"sanitize_filename",
18+
"timeout",
19+
"first",
20+
)
1421

1522
__doc__ = """Utils module contains many helpers for several task,
1623
like reading files or path management"""
1724

1825
SHELVE_PATH = os.path.join(constants.ZXBASIC_ROOT, "parsetab", "tabs.dbm")
1926
SHELVE = shelve.open(SHELVE_PATH)
2027

28+
T = TypeVar("T")
29+
30+
31+
def first(iter_: Iterable[T], default: T | None = None) -> T | None:
32+
"""Return the first element of an Iterable, or None if it's empty or
33+
there are no more elements to return."""
34+
return next(iter(iter_), default)
35+
2136

2237
def read_txt_file(fname: str) -> str:
2338
"""Reads a txt file, regardless of its encoding"""

src/arch/z80/optimizer/basicblock.py

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
# -*- coding: utf-8 -*-
2-
2+
from __future__ import annotations
33
from typing import Iterable, Iterator, List
44

55
import src.api.config
6-
import src.api.utils
76
import src.arch.z80.backend.common
87
from src.api.debug import __DEBUG__
9-
from src.api.identityset import IdentitySet
108
from src.arch.z80.optimizer import helpers
119
from src.arch.z80.optimizer.common import JUMP_LABELS, LABELS
1210
from src.arch.z80.optimizer.cpustate import CPUState
@@ -18,6 +16,7 @@
1816
from src.arch.z80.optimizer.labelinfo import LabelInfo
1917
from src.arch.z80.optimizer.memcell import MemCell
2018
from src.arch.z80.optimizer.patterns import RE_ID_OR_NUMBER
19+
from src.api.utils import flatten_list, first
2120
from src.arch.z80.peephole import evaluator
2221

2322

@@ -33,10 +32,10 @@ def __init__(self, memory: Iterable[str]):
3332
self.next = None # Which (if any) basic block follows this one in memory
3433
self.prev = None # Which (if any) basic block precedes to this one in the code
3534
self.lock = False # True if this block is being accessed by other subroutine
36-
self.comes_from = IdentitySet() # A list/tuple containing possible jumps to this block
37-
self.goes_to = IdentitySet() # A list/tuple of possible block to jump from here
35+
self.comes_from: set[BasicBlock] = set() # A list/tuple containing possible jumps to this block
36+
self.goes_to: set[BasicBlock] = set() # A list/tuple of possible block to jump from here
3837
self.modified = False # True if something has been changed during optimization
39-
self.calls = IdentitySet()
38+
self.calls: set[BasicBlock] = set()
4039
self.label_goes = []
4140
self.ignored = False # True if this block can be ignored (it's useless)
4241
self.id = BasicBlock.__UNIQUE_ID
@@ -162,7 +161,7 @@ def update_labels(self):
162161
for l in self.labels:
163162
LABELS[l].basic_block = self
164163

165-
def delete_comes_from(self, basic_block):
164+
def delete_comes_from(self, basic_block: BasicBlock) -> None:
166165
"""Removes the basic_block ptr from the list for "comes_from"
167166
if it exists. It also sets self.prev to None if it is basic_block.
168167
"""
@@ -174,14 +173,14 @@ def delete_comes_from(self, basic_block):
174173

175174
self.lock = True
176175

177-
for i in range(len(self.comes_from)):
178-
if self.comes_from[i] is basic_block:
179-
self.comes_from.pop(i)
176+
for elem in self.comes_from:
177+
if elem.id == basic_block.id:
178+
self.comes_from.remove(elem)
180179
break
181180

182181
self.lock = False
183182

184-
def delete_goes_to(self, basic_block):
183+
def delete_goes_to(self, basic_block: BasicBlock) -> None:
185184
"""Removes the basic_block ptr from the list for "goes_to"
186185
if it exists. It also sets self.next to None if it is basic_block.
187186
"""
@@ -193,15 +192,15 @@ def delete_goes_to(self, basic_block):
193192

194193
self.lock = True
195194

196-
for i in range(len(self.goes_to)):
197-
if self.goes_to[i] is basic_block:
198-
self.goes_to.pop(i)
195+
for elem in self.goes_to:
196+
if elem.id is basic_block.id:
197+
self.goes_to.remove(elem)
199198
basic_block.delete_comes_from(self)
200199
break
201200

202201
self.lock = False
203202

204-
def add_comes_from(self, basic_block):
203+
def add_comes_from(self, basic_block: BasicBlock) -> None:
205204
"""This simulates a set. Adds the basic_block to the comes_from
206205
list if not done already.
207206
"""
@@ -220,12 +219,11 @@ def add_comes_from(self, basic_block):
220219
basic_block.add_goes_to(self)
221220
self.lock = False
222221

223-
def add_goes_to(self, basic_block):
222+
def add_goes_to(self, basic_block: BasicBlock) -> None:
224223
"""This simulates a set. Adds the basic_block to the goes_to
225224
list if not done already.
226225
"""
227-
if basic_block is None:
228-
return
226+
assert basic_block is not None
229227

230228
if self.lock:
231229
return
@@ -326,7 +324,7 @@ def update_goes_and_comes(self):
326324

327325
final_blk = self.next # The block all the final returns should go to
328326
stack = [LABELS[oper[0]].basic_block]
329-
bbset = IdentitySet()
327+
bbset: set[BasicBlock] = set()
330328

331329
while stack:
332330
bb = stack.pop(0)
@@ -514,7 +512,7 @@ def get_first_non_label_instruction(self):
514512

515513
return None
516514

517-
def get_next_exec_instruction(self):
515+
def get_next_exec_instruction(self) -> MemCell | None:
518516
"""Return the first non label instruction to be executed, either
519517
in this block or in the following one. If there are more than one, return None.
520518
Also returns None if there is no instruction to be executed.
@@ -526,22 +524,22 @@ def get_next_exec_instruction(self):
526524
if len(blk.goes_to) != 1:
527525
return None
528526

529-
blk = blk.goes_to[0]
527+
blk = next(iter(blk.goes_to))
530528
result = blk.get_first_non_label_instruction()
531529

532530
return result
533531

534-
def guesses_initial_state_from_origin_blocks(self):
532+
def guesses_initial_state_from_origin_blocks(self) -> tuple[dict[str, str], dict[str, str]]:
535533
"""Returns two dictionaries (regs, memory) that contains the common values
536534
of the cpustates of all comes_from blocks
537535
"""
538536
if not self.comes_from:
539537
return {}, {}
540538

541-
regs = self.comes_from[0].cpu.regs
542-
mems = self.comes_from[0].cpu.mem
539+
regs = first(self.comes_from).cpu.regs
540+
mems = first(self.comes_from).cpu.mem
543541

544-
for blk in self.comes_from[1:]:
542+
for blk in list(self.comes_from)[1:]:
545543
regs = helpers.dict_intersection(regs, blk.cpu.regs)
546544
mems = helpers.dict_intersection(mems, blk.cpu.mem)
547545

src/arch/z80/optimizer/helpers.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# -*- coding: utf-8 -*-
22

3-
from typing import Optional
3+
from typing import Optional, TypeVar
44

55
from . import common, patterns
66

7+
T = TypeVar("T")
8+
K = TypeVar("K")
9+
10+
711
# All 'single' registers (even f FLAG one). SP is not decomposable so it's 'single' already
812
ALL_REGS = {"a", "b", "c", "d", "e", "f", "h", "l", "ixh", "ixl", "iyh", "iyl", "r", "i", "sp"}
913

@@ -410,7 +414,7 @@ def HI16_val(x):
410414
return "0{}{}".format(HL_SEP, x).split(HL_SEP)[-2]
411415

412416

413-
def dict_intersection(dict_a, dict_b):
417+
def dict_intersection(dict_a: dict[K, T], dict_b: dict[K, T]) -> dict[K, T]:
414418
"""Given 2 dictionaries a, b, returns a new one which contains the common key/pair values.
415419
e.g. for {'a': 1, 'b': 'x'}, {'a': 'q', 'b': 'x', 'c': 2} returns {'b': 'x'}
416420

src/arch/z80/optimizer/labelinfo.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# -*- coding: utf-8 -*-
22

3-
from src.api.identityset import IdentitySet
4-
3+
from typing import TYPE_CHECKING
54
from . import common, errors
65

6+
if TYPE_CHECKING:
7+
from .basicblock import BasicBlock
8+
79

810
class LabelInfo(object):
911
"""Class describing label information"""
@@ -16,7 +18,7 @@ def __init__(self, label, addr, basic_block=None, position=0):
1618
self.addr = addr
1719
self.basic_block = basic_block
1820
self.position = position # Position within the block
19-
self.used_by = IdentitySet() # Which BB uses this label, if any
21+
self.used_by: set[BasicBlock] = set() # Which BB uses this label, if any
2022

2123
if label in common.LABELS:
2224
raise errors.DuplicatedLabelError(label)

0 commit comments

Comments
 (0)