Edgewall Software

Ticket #429: t429-refactor-r1038.2.patch

File t429-refactor-r1038.2.patch, 5.8 KB (added by cboos, 12 years ago)

second version, more efficient (no speed penalty after the refactoring)

  • genshi/output.py

    # HG changeset patch
    # Parent ceae545e662b5f8e1d7146de255c6e31bce3a30b
    output: refactor code relative to the token serialization cache (introduced in [1038]).
    
    In preparation for fixing #429.
    
    diff -r ceae545e662b genshi/output.py
    a b def get_serializer(method='xml', **kwarg 
    7979    return method(**kwargs)
    8080
    8181
     82def _prepare_cache(use_cache=True):
     83    """Prepare a private token serialization cache.
     84
     85    :param use_cache: boolean indicating whether a real cache should
     86                      be used or not. If not, the returned functions
     87                      are no-ops.
     88
     89    :return: emit and get functions, for storing and retrieving
     90             serialized values from the cache.
     91    """
     92    cache = {}
     93    if use_cache:
     94        def _emit(kind, input, output):
     95            cache[kind, input] = output
     96            return output
     97        _get = cache.get
     98    else:
     99        def _emit(kind, input, output):
     100            return output
     101        def _get(key):
     102            pass
     103    return _emit, _get, cache
     104
     105
    82106class DocType(object):
    83107    """Defines a number of commonly used DOCTYPE declarations as constants."""
    84108
    class XMLSerializer(object): 
    204228            self.filters.append(DocTypeInserter(doctype))
    205229        self.cache = cache
    206230
     231    def _prepare_cache(self):
     232        return _prepare_cache(self.cache)[:2]
     233
    207234    def __call__(self, stream):
    208235        have_decl = have_doctype = False
    209236        in_cdata = False
    210 
    211         cache = {}
    212         cache_get = cache.get
    213         if self.cache:
    214             def _emit(kind, input, output):
    215                 cache[kind, input] = output
    216                 return output
    217         else:
    218             def _emit(kind, input, output):
    219                 return output
     237        _emit, _get = self._prepare_cache()
    220238
    221239        for filter_ in self.filters:
    222240            stream = filter_(stream)
    223241        for kind, data, pos in stream:
    224             cached = cache_get((kind, data))
     242            cached = _get((kind, data))
    225243            if cached is not None:
    226244                yield cached
    227 
    228245            elif kind is START or kind is EMPTY:
    229246                tag, attrib = data
    230247                buf = ['<', tag]
    class XHTMLSerializer(XMLSerializer): 
    323340        drop_xml_decl = self.drop_xml_decl
    324341        have_decl = have_doctype = False
    325342        in_cdata = False
    326 
    327         cache = {}
    328         cache_get = cache.get
    329         if self.cache:
    330             def _emit(kind, input, output):
    331                 cache[kind, input] = output
    332                 return output
    333         else:
    334             def _emit(kind, input, output):
    335                 return output
     343        _emit, _get = self._prepare_cache()
    336344
    337345        for filter_ in self.filters:
    338346            stream = filter_(stream)
    339347        for kind, data, pos in stream:
    340             cached = cache_get((kind, data))
     348            cached = _get((kind, data))
    341349            if cached is not None:
    342350                yield cached
    343351
    class HTMLSerializer(XHTMLSerializer): 
    454462        noescape_elems = self._NOESCAPE_ELEMS
    455463        have_doctype = False
    456464        noescape = False
    457 
    458         cache = {}
    459         cache_get = cache.get
    460         if self.cache:
    461             def _emit(kind, input, output):
    462                 cache[kind, input] = output
    463                 return output
    464         else:
    465             def _emit(kind, input, output):
    466                 return output
     465        _emit, _get = self._prepare_cache()
    467466
    468467        for filter_ in self.filters:
    469468            stream = filter_(stream)
    470469        for kind, data, _ in stream:
    471             output = cache_get((kind, data))
     470            output = _get((kind, data))
    472471            if output is not None:
    473472                yield output
    474473                if (kind is START or kind is EMPTY) \
    class NamespaceFlattener(object): 
    626625        self.cache = cache
    627626
    628627    def __call__(self, stream):
    629         cache = {}
    630         cache_get = cache.get
    631         if self.cache:
    632             def _emit(kind, input, output, pos):
    633                 cache[kind, input] = output
    634                 return kind, output, pos
    635         else:
    636             def _emit(kind, input, output, pos):
    637                 return output
    638 
    639628        prefixes = dict([(v, [k]) for k, v in self.prefixes.items()])
    640629        namespaces = {XML_NAMESPACE.uri: ['xml']}
     630        _emit, _get, cache = _prepare_cache(self.cache)
    641631        def _push_ns(prefix, uri):
    642632            namespaces.setdefault(uri, []).append(prefix)
    643633            prefixes.setdefault(prefix, []).append(uri)
    class NamespaceFlattener(object): 
    668658        _gen_prefix = _gen_prefix().next
    669659
    670660        for kind, data, pos in stream:
    671             output = cache_get((kind, data))
     661            output = _get((kind, data))
    672662            if output is not None:
    673663                yield kind, output, pos
    674664
    class NamespaceFlattener(object): 
    701691                            attrname = '%s:%s' % (prefix, attrname)
    702692                    new_attrs.append((attrname, value))
    703693
    704                 yield _emit(kind, data, (tagname, Attrs(ns_attrs + new_attrs)), pos)
     694                data = _emit(kind, data, (tagname, Attrs(ns_attrs + new_attrs)))
     695                yield kind, data, pos
    705696                del ns_attrs[:]
    706697
    707698            elif kind is END:
    class NamespaceFlattener(object): 
    711702                    prefix = namespaces[tagns][-1]
    712703                    if prefix:
    713704                        tagname = '%s:%s' % (prefix, tagname)
    714                 yield _emit(kind, data, tagname, pos)
     705                yield kind, _emit(kind, data, tagname), pos
    715706
    716707            elif kind is START_NS:
    717708                prefix, uri = data