Code to merge W arrays

This commit is contained in:
Kovid Goyal 2019-07-21 11:25:17 +05:30
parent d994cf7895
commit d304e08ec1
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 93 additions and 6 deletions

View File

@ -112,6 +112,8 @@ def find_tests(which_tests=None):
a(find_tests()) a(find_tests())
from calibre.ebooks.metadata.html import find_tests from calibre.ebooks.metadata.html import find_tests
a(find_tests()) a(find_tests())
from calibre.ebooks.pdf.test_html_writer import find_tests
a(find_tests())
if ok('misc'): if ok('misc'):
from calibre.ebooks.metadata.tag_mapper import find_tests from calibre.ebooks.metadata.tag_mapper import find_tests
a(find_tests()) a(find_tests())

View File

@ -520,13 +520,54 @@ def add_pagenum_toc(root, toc, opts, page_number_display_map):
class Range(object): class Range(object):
__slots__ = ('first', 'last', 'width') __slots__ = ('first', 'last', 'widths', 'sort_order')
def __init__(self, first, last, width): def __init__(self, first, last, widths):
self.first, self.last, self.width = first, last, width self.first, self.last, self.widths = first, last, widths
# Sort by first with larger ranges coming before smaller ones # Sort by first with larger ranges coming before smaller ones
self.sort_order = self.first, -self.last self.sort_order = self.first, -self.last
def __repr__(self):
return '({}, {}, {})'.format(self.first, self.last, self.widths)
def merge(self, r):
if r.last <= self.last:
return # is a subset
if r.first > self.last:
if r.first == self.last + 1 and self.has_single_width == r.has_single_width:
if self.has_single_width:
if r.widths[0] == self.widths[0]:
self.last = r.last
return
else:
self.last = r.last
delta = self.last - self.first + 1 - len(self.widths)
self.widths.extend(r.widths[-delta:])
return
return r
if self.has_single_width != r.has_single_width:
# make r disjoint
delta = self.last + 1 - r.first
r.first = self.last + 1
if len(r.widths) > 1:
del r.widths[:delta]
return r if r.widths else None
# subsume r into self
self.last = r.last
if not self.has_single_width:
delta = self.last - self.first + 1 - len(self.widths)
self.widths.extend(r.widths[-delta:])
@property
def as_item(self):
if self.has_single_width:
return self.first, self.last, self.widths[0]
return self.first, self.widths
@property
def has_single_width(self):
return len(self.widths) == 1
def merge_w_arrays(arrays): def merge_w_arrays(arrays):
ranges = [] ranges = []
@ -536,10 +577,10 @@ def merge_w_arrays(arrays):
elem = w[i] elem = w[i]
next_elem = w[i+1] next_elem = w[i+1]
if isinstance(next_elem, list): if isinstance(next_elem, list):
ranges.extend(Range(elem + c, elem + c, w) for c, w in enumerate(next_elem)) ranges.append(Range(elem, elem + len(next_elem) - 1, next_elem))
i += 2 i += 2
elif i + 2 < len(w): elif i + 2 < len(w):
ranges.append(Range(elem, next_elem, w[i+2])) ranges.append(Range(elem, next_elem, [w[i+2]]))
i += 3 i += 3
else: else:
break break
@ -552,7 +593,10 @@ def merge_w_arrays(arrays):
merged_ranges.append(left_over) merged_ranges.append(left_over)
if not merged_ranges: if not merged_ranges:
return [] return []
# combine consecutive single value ranges ans = []
for r in merged_ranges:
ans.extend(r.as_item)
return ans
def merge_font(fonts): def merge_font(fonts):

View File

@ -0,0 +1,41 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
import unittest
from .html_writer import merge_w_arrays
class TestPDFWriter(unittest.TestCase):
def test_merge_w_arrays(self):
self.assertEqual(merge_w_arrays(( # merge neighbor arrays
[1, 3, 0.1], [3, [0.1, 0.2]])), [1, 3, 0.1, 4, 4, 0.2])
self.assertEqual(merge_w_arrays(( # merge neighbor ranges
[1, 5, 0.1], [6, 8, 0.1])), [1, 8, 0.1])
self.assertEqual(merge_w_arrays(( # merge neighbor ranges
[1, 5, 0.1], [6, 8, 0.2])), [1, 5, 0.1, 6, 8, 0.2])
self.assertEqual(merge_w_arrays(( # disjoin overlap
[1, 4, 0.1], [3, [0.1, 0.1, 0.2, 0.3]])), [1, 4, 0.1, 5, [0.2, 0.3]])
self.assertEqual(merge_w_arrays(( # disjoin overlap
[1, [0.1, 0.2]], [2, 4, 0.2])), [1, [0.1, 0.2], 3, 4, 0.2])
self.assertEqual(merge_w_arrays(( # split overlapping arrays
[1, [0.1, 0.2, 0.3]], [3, 5, 0.3])), [1, [0.1, 0.2, 0.3], 4, 5, 0.3])
self.assertEqual(merge_w_arrays(( # merge overlapping ranges, using first width
[1, 5, 0.1], [2, 4, 0.2])), [1, 5, 0.1])
self.assertEqual(merge_w_arrays(( # merge overlapping arrays
[1, [0.1, 0.1]], [3, [0.2, 0.2]])), [1, [0.1, 0.1, 0.2, 0.2]])
self.assertEqual(merge_w_arrays((
[1, 10, 99, 20, [1, 2, 3, 4]],
[3, 10, 99, 11, 13, 77, 19, [77, 1]])),
[1, 10, 99, 11, 13, 77, 19, [77, 1, 2, 3, 4]]
)
def find_tests():
return unittest.defaultTestLoader.loadTestsFromTestCase(TestPDFWriter)