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