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