144 lines
3.3 KiB
Python
144 lines
3.3 KiB
Python
# Copyright 2013 Google, Inc. All Rights Reserved.
|
|
#
|
|
# Google Author(s): Behdad Esfahbod, Roozbeh Pournader
|
|
|
|
from fontTools.misc.timeTools import timestampNow
|
|
from fontTools.ttLib.tables.DefaultTable import DefaultTable
|
|
from functools import reduce
|
|
import operator
|
|
import logging
|
|
|
|
|
|
log = logging.getLogger("fontTools.merge")
|
|
|
|
|
|
# General utility functions for merging values from different fonts
|
|
|
|
|
|
def equal(lst):
|
|
lst = list(lst)
|
|
t = iter(lst)
|
|
first = next(t)
|
|
assert all(item == first for item in t), "Expected all items to be equal: %s" % lst
|
|
return first
|
|
|
|
|
|
def first(lst):
|
|
return next(iter(lst))
|
|
|
|
|
|
def recalculate(lst):
|
|
return NotImplemented
|
|
|
|
|
|
def current_time(lst):
|
|
return timestampNow()
|
|
|
|
|
|
def bitwise_and(lst):
|
|
return reduce(operator.and_, lst)
|
|
|
|
|
|
def bitwise_or(lst):
|
|
return reduce(operator.or_, lst)
|
|
|
|
|
|
def avg_int(lst):
|
|
lst = list(lst)
|
|
return sum(lst) // len(lst)
|
|
|
|
|
|
def onlyExisting(func):
|
|
"""Returns a filter func that when called with a list,
|
|
only calls func on the non-NotImplemented items of the list,
|
|
and only so if there's at least one item remaining.
|
|
Otherwise returns NotImplemented."""
|
|
|
|
def wrapper(lst):
|
|
items = [item for item in lst if item is not NotImplemented]
|
|
return func(items) if items else NotImplemented
|
|
|
|
return wrapper
|
|
|
|
|
|
def sumLists(lst):
|
|
l = []
|
|
for item in lst:
|
|
l.extend(item)
|
|
return l
|
|
|
|
|
|
def sumDicts(lst):
|
|
d = {}
|
|
for item in lst:
|
|
d.update(item)
|
|
return d
|
|
|
|
|
|
def mergeBits(bitmap):
|
|
def wrapper(lst):
|
|
lst = list(lst)
|
|
returnValue = 0
|
|
for bitNumber in range(bitmap["size"]):
|
|
try:
|
|
mergeLogic = bitmap[bitNumber]
|
|
except KeyError:
|
|
try:
|
|
mergeLogic = bitmap["*"]
|
|
except KeyError:
|
|
raise Exception("Don't know how to merge bit %s" % bitNumber)
|
|
shiftedBit = 1 << bitNumber
|
|
mergedValue = mergeLogic(bool(item & shiftedBit) for item in lst)
|
|
returnValue |= mergedValue << bitNumber
|
|
return returnValue
|
|
|
|
return wrapper
|
|
|
|
|
|
class AttendanceRecordingIdentityDict(object):
|
|
"""A dictionary-like object that records indices of items actually accessed
|
|
from a list."""
|
|
|
|
def __init__(self, lst):
|
|
self.l = lst
|
|
self.d = {id(v): i for i, v in enumerate(lst)}
|
|
self.s = set()
|
|
|
|
def __getitem__(self, v):
|
|
self.s.add(self.d[id(v)])
|
|
return v
|
|
|
|
|
|
class GregariousIdentityDict(object):
|
|
"""A dictionary-like object that welcomes guests without reservations and
|
|
adds them to the end of the guest list."""
|
|
|
|
def __init__(self, lst):
|
|
self.l = lst
|
|
self.s = set(id(v) for v in lst)
|
|
|
|
def __getitem__(self, v):
|
|
if id(v) not in self.s:
|
|
self.s.add(id(v))
|
|
self.l.append(v)
|
|
return v
|
|
|
|
|
|
class NonhashableDict(object):
|
|
"""A dictionary-like object mapping objects to values."""
|
|
|
|
def __init__(self, keys, values=None):
|
|
if values is None:
|
|
self.d = {id(v): i for i, v in enumerate(keys)}
|
|
else:
|
|
self.d = {id(k): v for k, v in zip(keys, values)}
|
|
|
|
def __getitem__(self, k):
|
|
return self.d[id(k)]
|
|
|
|
def __setitem__(self, k, v):
|
|
self.d[id(k)] = v
|
|
|
|
def __delitem__(self, k):
|
|
del self.d[id(k)]
|