From 07455790b1b1369775b86672a41594c565d3698c Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Tue, 16 Nov 2021 12:59:05 +0000 Subject: [PATCH] simplify ranges() generator --- Lib/fontTools/subset/svg.py | 23 ++++++++++++++--------- Tests/subset/svg_test.py | 18 +++++++++++++++++- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Lib/fontTools/subset/svg.py b/Lib/fontTools/subset/svg.py index 169a92ee3..08f552f0f 100644 --- a/Lib/fontTools/subset/svg.py +++ b/Lib/fontTools/subset/svg.py @@ -2,7 +2,7 @@ from __future__ import annotations import re from functools import lru_cache -from itertools import chain, count, groupby +from itertools import chain, count from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple try: @@ -172,14 +172,19 @@ def update_glyph_href_links(svg: etree.Element, id_map: Dict[str, str]) -> None: def ranges(ints: Iterable[int]) -> Iterator[Tuple[int, int]]: - # Yield (min, max) ranges of consecutive integers from the input set - sorted_ints = sorted(set(ints)) - # to group together consecutive ints, we use as 'key' the difference - # between their index in the (sorted) list and themselves, which stays - # the same for consecutive numbers - for _key, group in groupby(enumerate(sorted_ints), lambda i: i[0] - i[1]): - consecutive_ints = [v for _i, v in group] - yield (consecutive_ints[0], consecutive_ints[-1]) + # Yield sorted, non-overlapping (min, max) ranges of consecutive integers + sorted_ints = iter(sorted(set(ints))) + try: + start = end = next(sorted_ints) + except StopIteration: + return + for v in sorted_ints: + if v - 1 == end: + end = v + else: + yield (start, end) + start = end = v + yield (start, end) @_add_method(ttLib.getTableClass("SVG ")) diff --git a/Tests/subset/svg_test.py b/Tests/subset/svg_test.py index bdfc4d68c..919570139 100644 --- a/Tests/subset/svg_test.py +++ b/Tests/subset/svg_test.py @@ -6,7 +6,7 @@ from fontTools import subset from fontTools.fontBuilder import FontBuilder from fontTools.pens.ttGlyphPen import TTGlyphPen from fontTools.ttLib import TTFont, newTable -from fontTools.subset.svg import NAMESPACES +from fontTools.subset.svg import NAMESPACES, ranges import pytest @@ -453,3 +453,19 @@ def test_subset_svg_missing_glyph(empty_svg_font, tmp_path): subset.main([str(svg_font_path), f"--output-file={subset_path}", f"--gids=2"]) assert "SVG " not in TTFont(subset_path) + + +@pytest.mark.parametrize( + "ints, expected_ranges", + [ + ((), []), + ((0,), [(0, 0)]), + ((0, 1), [(0, 1)]), + ((1, 1, 1, 1), [(1, 1)]), + ((1, 3), [(1, 1), (3, 3)]), + ((4, 2, 1, 3), [(1, 4)]), + ((1, 2, 4, 5, 6, 9, 13, 14, 15), [(1, 2), (4, 6), (9, 9), (13, 15)]), + ], +) +def test_ranges(ints, expected_ranges): + assert list(ranges(ints)) == expected_ranges