• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
17def equal(lst):
18	lst = list(lst)
19	t = iter(lst)
20	first = next(t)
21	assert all(item == first for item in t), "Expected all items to be equal: %s" % lst
22	return first
23
24def first(lst):
25	return next(iter(lst))
26
27def recalculate(lst):
28	return NotImplemented
29
30def current_time(lst):
31	return timestampNow()
32
33def bitwise_and(lst):
34	return reduce(operator.and_, lst)
35
36def bitwise_or(lst):
37	return reduce(operator.or_, lst)
38
39def avg_int(lst):
40	lst = list(lst)
41	return sum(lst) // len(lst)
42
43def onlyExisting(func):
44	"""Returns a filter func that when called with a list,
45	only calls func on the non-NotImplemented items of the list,
46	and only so if there's at least one item remaining.
47	Otherwise returns NotImplemented."""
48
49	def wrapper(lst):
50		items = [item for item in lst if item is not NotImplemented]
51		return func(items) if items else NotImplemented
52
53	return wrapper
54
55def sumLists(lst):
56	l = []
57	for item in lst:
58		l.extend(item)
59	return l
60
61def sumDicts(lst):
62	d = {}
63	for item in lst:
64		d.update(item)
65	return d
66
67def mergeBits(bitmap):
68
69	def wrapper(lst):
70		lst = list(lst)
71		returnValue = 0
72		for bitNumber in range(bitmap['size']):
73			try:
74				mergeLogic = bitmap[bitNumber]
75			except KeyError:
76				try:
77					mergeLogic = bitmap['*']
78				except KeyError:
79					raise Exception("Don't know how to merge bit %s" % bitNumber)
80			shiftedBit = 1 << bitNumber
81			mergedValue = mergeLogic(bool(item & shiftedBit) for item in lst)
82			returnValue |= mergedValue << bitNumber
83		return returnValue
84
85	return wrapper
86
87
88class AttendanceRecordingIdentityDict(object):
89	"""A dictionary-like object that records indices of items actually accessed
90	from a list."""
91
92	def __init__(self, lst):
93		self.l = lst
94		self.d = {id(v):i for i,v in enumerate(lst)}
95		self.s = set()
96
97	def __getitem__(self, v):
98		self.s.add(self.d[id(v)])
99		return v
100
101class GregariousIdentityDict(object):
102	"""A dictionary-like object that welcomes guests without reservations and
103	adds them to the end of the guest list."""
104
105	def __init__(self, lst):
106		self.l = lst
107		self.s = set(id(v) for v in lst)
108
109	def __getitem__(self, v):
110		if id(v) not in self.s:
111			self.s.add(id(v))
112			self.l.append(v)
113		return v
114
115class NonhashableDict(object):
116	"""A dictionary-like object mapping objects to values."""
117
118	def __init__(self, keys, values=None):
119		if values is None:
120			self.d = {id(v):i for i,v in enumerate(keys)}
121		else:
122			self.d = {id(k):v for k,v in zip(keys, values)}
123
124	def __getitem__(self, k):
125		return self.d[id(k)]
126
127	def __setitem__(self, k, v):
128		self.d[id(k)] = v
129
130	def __delitem__(self, k):
131		del self.d[id(k)]
132