def irange(self, min_addr: int | None = None, max_addr: int | None = None) -> Iterator[tuple[int, int, int]]:
        """
        Iterate over intervals intersecting [min_addr, max_addr], yielding interval (addr, size, tags) tuples. Implicit
        gap intervals (with tags=0) are also returned.

        :param min_addr: Minimum address (inclusive) to begin iterating from. If None, iterate from start of map.
        :param max_addr: Maximum address (inclusive) to iterate to. If None, iterate to end of map.
        """
        if not self._map:
            return

        start_idx = 0 if min_addr is None else max(0, self._map.bisect_left(min_addr) - 1)
        stop_idx = None if max_addr is None else (self._map.bisect(max_addr) + 1)

        start_addr, tags = self._map.peekitem(start_idx)
        for addr in self._map.islice(start_idx + 1, stop_idx):
            yield (start_addr, addr - start_addr, tags)
            tags = self._map[addr]
            start_addr = addr

        Iterate over intervals intersecting [min_addr, max_addr], yielding interval (addr, size, tags) tuples. Implicit
        gap intervals (with tags=0) are also returned.

        :param min_addr: Minimum address (inclusive) to begin iterating from. If None, iterate from start of map.
        :param max_addr: Maximum address (inclusive) to iterate to. If None, iterate to end of map.
        
angrmanagement/data/tagged_interval_map.py