xref: /aosp_15_r20/external/fonttools/Lib/fontTools/merge/util.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1*e1fe3e4aSElliott Hughes# Copyright 2013 Google, Inc. All Rights Reserved.
2*e1fe3e4aSElliott Hughes#
3*e1fe3e4aSElliott Hughes# Google Author(s): Behdad Esfahbod, Roozbeh Pournader
4*e1fe3e4aSElliott Hughes
5*e1fe3e4aSElliott Hughesfrom fontTools.misc.timeTools import timestampNow
6*e1fe3e4aSElliott Hughesfrom fontTools.ttLib.tables.DefaultTable import DefaultTable
7*e1fe3e4aSElliott Hughesfrom functools import reduce
8*e1fe3e4aSElliott Hughesimport operator
9*e1fe3e4aSElliott Hughesimport logging
10*e1fe3e4aSElliott Hughes
11*e1fe3e4aSElliott Hughes
12*e1fe3e4aSElliott Hugheslog = logging.getLogger("fontTools.merge")
13*e1fe3e4aSElliott Hughes
14*e1fe3e4aSElliott Hughes
15*e1fe3e4aSElliott Hughes# General utility functions for merging values from different fonts
16*e1fe3e4aSElliott Hughes
17*e1fe3e4aSElliott Hughes
18*e1fe3e4aSElliott Hughesdef equal(lst):
19*e1fe3e4aSElliott Hughes    lst = list(lst)
20*e1fe3e4aSElliott Hughes    t = iter(lst)
21*e1fe3e4aSElliott Hughes    first = next(t)
22*e1fe3e4aSElliott Hughes    assert all(item == first for item in t), "Expected all items to be equal: %s" % lst
23*e1fe3e4aSElliott Hughes    return first
24*e1fe3e4aSElliott Hughes
25*e1fe3e4aSElliott Hughes
26*e1fe3e4aSElliott Hughesdef first(lst):
27*e1fe3e4aSElliott Hughes    return next(iter(lst))
28*e1fe3e4aSElliott Hughes
29*e1fe3e4aSElliott Hughes
30*e1fe3e4aSElliott Hughesdef recalculate(lst):
31*e1fe3e4aSElliott Hughes    return NotImplemented
32*e1fe3e4aSElliott Hughes
33*e1fe3e4aSElliott Hughes
34*e1fe3e4aSElliott Hughesdef current_time(lst):
35*e1fe3e4aSElliott Hughes    return timestampNow()
36*e1fe3e4aSElliott Hughes
37*e1fe3e4aSElliott Hughes
38*e1fe3e4aSElliott Hughesdef bitwise_and(lst):
39*e1fe3e4aSElliott Hughes    return reduce(operator.and_, lst)
40*e1fe3e4aSElliott Hughes
41*e1fe3e4aSElliott Hughes
42*e1fe3e4aSElliott Hughesdef bitwise_or(lst):
43*e1fe3e4aSElliott Hughes    return reduce(operator.or_, lst)
44*e1fe3e4aSElliott Hughes
45*e1fe3e4aSElliott Hughes
46*e1fe3e4aSElliott Hughesdef avg_int(lst):
47*e1fe3e4aSElliott Hughes    lst = list(lst)
48*e1fe3e4aSElliott Hughes    return sum(lst) // len(lst)
49*e1fe3e4aSElliott Hughes
50*e1fe3e4aSElliott Hughes
51*e1fe3e4aSElliott Hughesdef onlyExisting(func):
52*e1fe3e4aSElliott Hughes    """Returns a filter func that when called with a list,
53*e1fe3e4aSElliott Hughes    only calls func on the non-NotImplemented items of the list,
54*e1fe3e4aSElliott Hughes    and only so if there's at least one item remaining.
55*e1fe3e4aSElliott Hughes    Otherwise returns NotImplemented."""
56*e1fe3e4aSElliott Hughes
57*e1fe3e4aSElliott Hughes    def wrapper(lst):
58*e1fe3e4aSElliott Hughes        items = [item for item in lst if item is not NotImplemented]
59*e1fe3e4aSElliott Hughes        return func(items) if items else NotImplemented
60*e1fe3e4aSElliott Hughes
61*e1fe3e4aSElliott Hughes    return wrapper
62*e1fe3e4aSElliott Hughes
63*e1fe3e4aSElliott Hughes
64*e1fe3e4aSElliott Hughesdef sumLists(lst):
65*e1fe3e4aSElliott Hughes    l = []
66*e1fe3e4aSElliott Hughes    for item in lst:
67*e1fe3e4aSElliott Hughes        l.extend(item)
68*e1fe3e4aSElliott Hughes    return l
69*e1fe3e4aSElliott Hughes
70*e1fe3e4aSElliott Hughes
71*e1fe3e4aSElliott Hughesdef sumDicts(lst):
72*e1fe3e4aSElliott Hughes    d = {}
73*e1fe3e4aSElliott Hughes    for item in lst:
74*e1fe3e4aSElliott Hughes        d.update(item)
75*e1fe3e4aSElliott Hughes    return d
76*e1fe3e4aSElliott Hughes
77*e1fe3e4aSElliott Hughes
78*e1fe3e4aSElliott Hughesdef mergeBits(bitmap):
79*e1fe3e4aSElliott Hughes    def wrapper(lst):
80*e1fe3e4aSElliott Hughes        lst = list(lst)
81*e1fe3e4aSElliott Hughes        returnValue = 0
82*e1fe3e4aSElliott Hughes        for bitNumber in range(bitmap["size"]):
83*e1fe3e4aSElliott Hughes            try:
84*e1fe3e4aSElliott Hughes                mergeLogic = bitmap[bitNumber]
85*e1fe3e4aSElliott Hughes            except KeyError:
86*e1fe3e4aSElliott Hughes                try:
87*e1fe3e4aSElliott Hughes                    mergeLogic = bitmap["*"]
88*e1fe3e4aSElliott Hughes                except KeyError:
89*e1fe3e4aSElliott Hughes                    raise Exception("Don't know how to merge bit %s" % bitNumber)
90*e1fe3e4aSElliott Hughes            shiftedBit = 1 << bitNumber
91*e1fe3e4aSElliott Hughes            mergedValue = mergeLogic(bool(item & shiftedBit) for item in lst)
92*e1fe3e4aSElliott Hughes            returnValue |= mergedValue << bitNumber
93*e1fe3e4aSElliott Hughes        return returnValue
94*e1fe3e4aSElliott Hughes
95*e1fe3e4aSElliott Hughes    return wrapper
96*e1fe3e4aSElliott Hughes
97*e1fe3e4aSElliott Hughes
98*e1fe3e4aSElliott Hughesclass AttendanceRecordingIdentityDict(object):
99*e1fe3e4aSElliott Hughes    """A dictionary-like object that records indices of items actually accessed
100*e1fe3e4aSElliott Hughes    from a list."""
101*e1fe3e4aSElliott Hughes
102*e1fe3e4aSElliott Hughes    def __init__(self, lst):
103*e1fe3e4aSElliott Hughes        self.l = lst
104*e1fe3e4aSElliott Hughes        self.d = {id(v): i for i, v in enumerate(lst)}
105*e1fe3e4aSElliott Hughes        self.s = set()
106*e1fe3e4aSElliott Hughes
107*e1fe3e4aSElliott Hughes    def __getitem__(self, v):
108*e1fe3e4aSElliott Hughes        self.s.add(self.d[id(v)])
109*e1fe3e4aSElliott Hughes        return v
110*e1fe3e4aSElliott Hughes
111*e1fe3e4aSElliott Hughes
112*e1fe3e4aSElliott Hughesclass GregariousIdentityDict(object):
113*e1fe3e4aSElliott Hughes    """A dictionary-like object that welcomes guests without reservations and
114*e1fe3e4aSElliott Hughes    adds them to the end of the guest list."""
115*e1fe3e4aSElliott Hughes
116*e1fe3e4aSElliott Hughes    def __init__(self, lst):
117*e1fe3e4aSElliott Hughes        self.l = lst
118*e1fe3e4aSElliott Hughes        self.s = set(id(v) for v in lst)
119*e1fe3e4aSElliott Hughes
120*e1fe3e4aSElliott Hughes    def __getitem__(self, v):
121*e1fe3e4aSElliott Hughes        if id(v) not in self.s:
122*e1fe3e4aSElliott Hughes            self.s.add(id(v))
123*e1fe3e4aSElliott Hughes            self.l.append(v)
124*e1fe3e4aSElliott Hughes        return v
125*e1fe3e4aSElliott Hughes
126*e1fe3e4aSElliott Hughes
127*e1fe3e4aSElliott Hughesclass NonhashableDict(object):
128*e1fe3e4aSElliott Hughes    """A dictionary-like object mapping objects to values."""
129*e1fe3e4aSElliott Hughes
130*e1fe3e4aSElliott Hughes    def __init__(self, keys, values=None):
131*e1fe3e4aSElliott Hughes        if values is None:
132*e1fe3e4aSElliott Hughes            self.d = {id(v): i for i, v in enumerate(keys)}
133*e1fe3e4aSElliott Hughes        else:
134*e1fe3e4aSElliott Hughes            self.d = {id(k): v for k, v in zip(keys, values)}
135*e1fe3e4aSElliott Hughes
136*e1fe3e4aSElliott Hughes    def __getitem__(self, k):
137*e1fe3e4aSElliott Hughes        return self.d[id(k)]
138*e1fe3e4aSElliott Hughes
139*e1fe3e4aSElliott Hughes    def __setitem__(self, k, v):
140*e1fe3e4aSElliott Hughes        self.d[id(k)] = v
141*e1fe3e4aSElliott Hughes
142*e1fe3e4aSElliott Hughes    def __delitem__(self, k):
143*e1fe3e4aSElliott Hughes        del self.d[id(k)]
144