util.py 3.3 KB

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