This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

FYI: update libstdc++ pretty-printers


Barring objections, I will check this in during the next stage 1.

Doug Evans recently added some features to gdb to make it possible for
the user to individually enable or disable pretty-printers.  In order
for this to work, the printers must conform to a certain extended
protocol.

This patch updates the libstdc++ printers to work this way.  The change
is done in a backward-compatible way, so that they will continue to work
properly in older versions of gdb.

This patch also simplifies the printers somewhat, and probably speeds up
printer recognition as well, though I did not try to measure that.

Tom

2011-01-26  Tom Tromey  <tromey@redhat.com>

	* python/libstdcxx/v6/printers.py (_use_gdb_pp): New global.
	Try to import `gdb.printing' module.
	(UniquePointerPrinter.__init__): Add 'typename' argument.
	(StdSlistPrinter.__init__): Likewise.
	(StdSlistIteratorPrinter.__init__): Likewise.
	(StdVectorIteratorPrinter.__init__): Likewise.
	(StdRbtreeIteratorPrinter.__init__): Likewise.
	(StdDebugIteratorPrinter.__init__): Likewise.
	(StdDequeIteratorPrinter.__init__): Likewise.
	(StdStringPrinter.__init__): Likewise.
	(RxPrinter, Printer): New class.
	(libstdcxx_printer): New global.
	(register_libstdcxx_printers): Rewrite.
	(build_libstdcxx_dictionary): Rewrite.
	(pretty_printers_dict): Remove.

Index: python/libstdcxx/v6/printers.py
===================================================================
--- python/libstdcxx/v6/printers.py	(revision 168933)
+++ python/libstdcxx/v6/printers.py	(working copy)
@@ -1,6 +1,6 @@
 # Pretty-printers for libstc++.
 
-# Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+# Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -19,6 +19,13 @@
 import itertools
 import re
 
+# Try to use the new-style pretty-printing if available.
+_use_gdb_pp = True
+try:
+    import gdb.printing
+except ImportError:
+    _use_gdb_pp = False
+
 class StdPointerPrinter:
     "Print a smart pointer of some kind"
 
@@ -36,7 +43,7 @@
 class UniquePointerPrinter:
     "Print a unique_ptr"
 
-    def __init__ (self, val):
+    def __init__ (self, typename, val):
         self.val = val
 
     def to_string (self):
@@ -125,7 +132,7 @@
             self.count = self.count + 1
             return ('[%d]' % count, elt['_M_data'])
 
-    def __init__(self, val):
+    def __init__(self, typename, val):
         self.val = val
 
     def children(self):
@@ -141,7 +148,7 @@
 class StdSlistIteratorPrinter:
     "Print __gnu_cxx::slist::iterator"
 
-    def __init__(self, val):
+    def __init__(self, typename, val):
         self.val = val
 
     def to_string(self):
@@ -228,7 +235,7 @@
 class StdVectorIteratorPrinter:
     "Print std::vector::iterator"
 
-    def __init__(self, val):
+    def __init__(self, typename, val):
         self.val = val
 
     def to_string(self):
@@ -351,7 +358,7 @@
 class StdRbtreeIteratorPrinter:
     "Print std::map::iterator"
 
-    def __init__ (self, val):
+    def __init__ (self, typename, val):
         self.val = val
 
     def to_string (self):
@@ -363,7 +370,7 @@
 class StdDebugIteratorPrinter:
     "Print a debug enabled version of an iterator"
 
-    def __init__ (self, val):
+    def __init__ (self, typename, val):
         self.val = val
 
     # Just strip away the encapsulating __gnu_debug::_Safe_iterator
@@ -557,7 +564,7 @@
 class StdDequeIteratorPrinter:
     "Print std::deque::iterator"
 
-    def __init__(self, val):
+    def __init__(self, typename, val):
         self.val = val
 
     def to_string(self):
@@ -566,7 +573,7 @@
 class StdStringPrinter:
     "Print a std::basic_string of some kind"
 
-    def __init__(self, val):
+    def __init__(self, typename, val):
         self.val = val
 
     def to_string(self):
@@ -678,125 +685,186 @@
     def display_hint (self):
         return 'map'
 
-def register_libstdcxx_printers (obj):
-    "Register libstdc++ pretty-printers with objfile Obj."
+# A "regular expression" printer which conforms to the
+# "SubPrettyPrinter" protocol from gdb.printing.
+class RxPrinter(object):
+    def __init__(self, name, function):
+        super(RxPrinter, self).__init__()
+        self.name = name
+        self.function = function
+        self.enabled = True
 
-    if obj == None:
-        obj = gdb
+    def invoke(self, value):
+        return self.function(self.name, value)
 
-    obj.pretty_printers.append (lookup_function)
+# A pretty-printer that conforms to the "PrettyPrinter" protocol from
+# gdb.printing.  It can also be used directly as an old-style printer.
+class Printer(object):
+    def __init__(self, name):
+        super(Printer, self).__init__()
+        self.name = name
+        self.subprinters = []
+        self.lookup = {}
+        self.enabled = True
+        self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)<.*>$')
 
-def lookup_function (val):
-    "Look-up and return a pretty-printer that can print val."
+    def add(self, name, function):
+        # A small sanity check.
+        # FIXME
+        if not self.compiled_rx.match(name + '<>'):
+            raise ValueError, 'libstdc++ programming error: "%s" does not match' % name
+        printer = RxPrinter(name, function)
+        self.subprinters.append(printer)
+        self.lookup[name] = printer
 
-    # Get the type.
-    type = val.type
+    @staticmethod
+    def get_basic_type(type):
+        # If it points to a reference, get the reference.
+        if type.code == gdb.TYPE_CODE_REF:
+            type = type.target ()
 
-    # If it points to a reference, get the reference.
-    if type.code == gdb.TYPE_CODE_REF:
-        type = type.target ()
+        # Get the unqualified type, stripped of typedefs.
+        type = type.unqualified ().strip_typedefs ()
 
-    # Get the unqualified type, stripped of typedefs.
-    type = type.unqualified ().strip_typedefs ()
+        return type.tag
 
-    # Get the type name.    
-    typename = type.tag
-    if typename == None:
+    def __call__(self, val):
+        typename = self.get_basic_type(val.type)
+        if not typename:
+            return None
+
+        # All the types we match are template types, so we can use a
+        # dictionary.
+        match = self.compiled_rx.match(typename)
+        if not match:
+            return None
+
+        if match.group(1) in self.lookup:
+            return self.lookup[match.group(1)].invoke(val)
+
+        # Cannot find a pretty printer.  Return None.
         return None
 
-    # Iterate over local dictionary of types to determine
-    # if a printer is registered for that type.  Return an
-    # instantiation of the printer if found.
-    for function in pretty_printers_dict:
-        if function.search (typename):
-            return pretty_printers_dict[function] (val)
-        
-    # Cannot find a pretty printer.  Return None.
-    return None
+libstdcxx_printer = None
 
+def register_libstdcxx_printers (obj):
+    "Register libstdc++ pretty-printers with objfile Obj."
+
+    global _use_gdb_pp
+    global libstdcxx_printer
+
+    if _use_gdb_pp:
+        gdb.printing.register_pretty_printer(obj, libstdcxx_printer)
+    else:
+        if obj is None:
+            obj = gdb
+        obj.pretty_printers.append(libstdcxx_printer)
+
 def build_libstdcxx_dictionary ():
+    global libstdcxx_printer
+
+    libstdcxx_printer = Printer("libstdc++-v6")
+
     # libstdc++ objects requiring pretty-printing.
     # In order from:
     # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
-    pretty_printers_dict[re.compile('^std::basic_string<.*>$')] = lambda val: StdStringPrinter(val)
-    pretty_printers_dict[re.compile('^std::bitset<.*>$')] = lambda val: StdBitsetPrinter("std::bitset", val)
-    pretty_printers_dict[re.compile('^std::deque<.*>$')] = lambda val: StdDequePrinter("std::deque", val)
-    pretty_printers_dict[re.compile('^std::list<.*>$')] = lambda val: StdListPrinter("std::list", val)
-    pretty_printers_dict[re.compile('^std::map<.*>$')] = lambda val: StdMapPrinter("std::map", val)
-    pretty_printers_dict[re.compile('^std::multimap<.*>$')] = lambda val: StdMapPrinter("std::multimap", val)
-    pretty_printers_dict[re.compile('^std::multiset<.*>$')] = lambda val: StdSetPrinter("std::multiset", val)
-    pretty_printers_dict[re.compile('^std::priority_queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val)
-    pretty_printers_dict[re.compile('^std::queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::queue", val)
-    pretty_printers_dict[re.compile('^std::tuple<.*>$')] = lambda val: StdTuplePrinter("std::tuple", val)
-    pretty_printers_dict[re.compile('^std::set<.*>$')] = lambda val: StdSetPrinter("std::set", val)
-    pretty_printers_dict[re.compile('^std::stack<.*>$')] = lambda val: StdStackOrQueuePrinter("std::stack", val)
-    pretty_printers_dict[re.compile('^std::unique_ptr<.*>$')] = UniquePointerPrinter
-    pretty_printers_dict[re.compile('^std::vector<.*>$')] = lambda val: StdVectorPrinter("std::vector", val)
+    libstdcxx_printer.add('std::basic_string', StdStringPrinter)
+    libstdcxx_printer.add('std::bitset', StdBitsetPrinter)
+    libstdcxx_printer.add('std::deque', StdDequePrinter)
+    libstdcxx_printer.add('std::list', StdListPrinter)
+    libstdcxx_printer.add('std::map', StdMapPrinter)
+    libstdcxx_printer.add('std::multimap', StdMapPrinter)
+    libstdcxx_printer.add('std::multiset', StdSetPrinter)
+    libstdcxx_printer.add('std::priority_queue', StdStackOrQueuePrinter)
+    libstdcxx_printer.add('std::queue', StdStackOrQueuePrinter)
+    libstdcxx_printer.add('std::tuple', StdTuplePrinter)
+    libstdcxx_printer.add('std::set', StdSetPrinter)
+    libstdcxx_printer.add('std::stack', StdStackOrQueuePrinter)
+    libstdcxx_printer.add('std::unique_ptr', UniquePointerPrinter)
+    libstdcxx_printer.add('std::vector', StdVectorPrinter)
     # vector<bool>
 
     # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG.
-    pretty_printers_dict[re.compile('^std::__debug::bitset<.*>$')] = lambda val: StdBitsetPrinter("std::__debug::bitset", val)
-    pretty_printers_dict[re.compile('^std::__debug::deque<.*>$')] = lambda val: StdDequePrinter("std::__debug::deque", val)
-    pretty_printers_dict[re.compile('^std::__debug::list<.*>$')] = lambda val: StdListPrinter("std::__debug::list", val)
-    pretty_printers_dict[re.compile('^std::__debug::map<.*>$')] = lambda val: StdMapPrinter("std::__debug::map", val)
-    pretty_printers_dict[re.compile('^std::__debug::multimap<.*>$')] = lambda val: StdMapPrinter("std::__debug::multimap", val)
-    pretty_printers_dict[re.compile('^std::__debug::multiset<.*>$')] = lambda val: StdSetPrinter("std::__debug::multiset", val)
-    pretty_printers_dict[re.compile('^std::__debug::priority_queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::__debug::priority_queue", val)
-    pretty_printers_dict[re.compile('^std::__debug::queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::__debug::queue", val)
-    pretty_printers_dict[re.compile('^std::__debug::set<.*>$')] = lambda val: StdSetPrinter("std::__debug::set", val)
-    pretty_printers_dict[re.compile('^std::__debug::stack<.*>$')] = lambda val: StdStackOrQueuePrinter("std::__debug::stack", val)
-    pretty_printers_dict[re.compile('^std::__debug::unique_ptr<.*>$')] = UniquePointerPrinter
-    pretty_printers_dict[re.compile('^std::__debug::vector<.*>$')] = lambda val: StdVectorPrinter("std::__debug::vector", val)
+    libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter)
+    libstdcxx_printer.add('std::__debug::deque', StdDequePrinter)
+    libstdcxx_printer.add('std::__debug::list', StdListPrinter)
+    libstdcxx_printer.add('std::__debug::map', StdMapPrinter)
+    libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter)
+    libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter)
+    libstdcxx_printer.add('std::__debug::priority_queue',
+                          StdStackOrQueuePrinter)
+    libstdcxx_printer.add('std::__debug::queue', StdStackOrQueuePrinter)
+    libstdcxx_printer.add('std::__debug::set', StdSetPrinter)
+    libstdcxx_printer.add('std::__debug::stack', StdStackOrQueuePrinter)
+    libstdcxx_printer.add('std::__debug::unique_ptr', UniquePointerPrinter)
+    libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter)
 
     # These are the TR1 and C++0x printers.
     # For array - the default GDB pretty-printer seems reasonable.
-    pretty_printers_dict[re.compile('^std::shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::shared_ptr', val)
-    pretty_printers_dict[re.compile('^std::weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::weak_ptr', val)
-    pretty_printers_dict[re.compile('^std::unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::unordered_map', val)
-    pretty_printers_dict[re.compile('^std::unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::unordered_set', val)
-    pretty_printers_dict[re.compile('^std::unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::unordered_multimap', val)
-    pretty_printers_dict[re.compile('^std::unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::unordered_multiset', val)
+    libstdcxx_printer.add('std::shared_ptr', StdPointerPrinter)
+    libstdcxx_printer.add('std::weak_ptr', StdPointerPrinter)
+    libstdcxx_printer.add('std::unordered_map', Tr1UnorderedMapPrinter)
+    libstdcxx_printer.add('std::unordered_set', Tr1UnorderedSetPrinter)
+    libstdcxx_printer.add('std::unordered_multimap', Tr1UnorderedMapPrinter)
+    libstdcxx_printer.add('std::unordered_multiset', Tr1UnorderedSetPrinter)
 
-    pretty_printers_dict[re.compile('^std::tr1::shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::tr1::shared_ptr', val)
-    pretty_printers_dict[re.compile('^std::tr1::weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::tr1::weak_ptr', val)
-    pretty_printers_dict[re.compile('^std::tr1::unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_map', val)
-    pretty_printers_dict[re.compile('^std::tr1::unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_set', val)
-    pretty_printers_dict[re.compile('^std::tr1::unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_multimap', val)
-    pretty_printers_dict[re.compile('^std::tr1::unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_multiset', val)
+    libstdcxx_printer.add('std::tr1::shared_ptr', StdPointerPrinter)
+    libstdcxx_printer.add('std::tr1::weak_ptr', StdPointerPrinter)
+    libstdcxx_printer.add('std::tr1::unordered_map', Tr1UnorderedMapPrinter)
+    libstdcxx_printer.add('std::tr1::unordered_set', Tr1UnorderedSetPrinter)
+    libstdcxx_printer.add('std::tr1::unordered_multimap',
+                          Tr1UnorderedMapPrinter)
+    libstdcxx_printer.add('std::tr1::unordered_multiset',
+                          Tr1UnorderedSetPrinter)
 
     # These are the C++0x printer registrations for -D_GLIBCXX_DEBUG cases.
     # The tr1 namespace printers do not seem to have any debug
     # equivalents, so do no register them.
-    pretty_printers_dict[re.compile('^std::__debug::unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::__debug::unordered_map', val)
-    pretty_printers_dict[re.compile('^std::__debug::unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::__debug::unordered_set', val)
-    pretty_printers_dict[re.compile('^std::__debug::unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::__debug::unordered_multimap',  val)
-    pretty_printers_dict[re.compile('^std::__debug::unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::__debug:unordered_multiset', val)
+    libstdcxx_printer.add('std::__debug::unordered_map',
+                          Tr1UnorderedMapPrinter)
+    libstdcxx_printer.add('std::__debug::unordered_set',
+                          Tr1UnorderedSetPrinter)
+    libstdcxx_printer.add('std::__debug::unordered_multimap',
+                          Tr1UnorderedMapPrinter)
+    libstdcxx_printer.add('std::__debug::unordered_multiset',
+                          Tr1UnorderedSetPrinter)
 
 
     # Extensions.
-    pretty_printers_dict[re.compile('^__gnu_cxx::slist<.*>$')] = StdSlistPrinter
+    libstdcxx_printer.add('__gnu_cxx::slist', StdSlistPrinter)
 
     if True:
         # These shouldn't be necessary, if GDB "print *i" worked.
         # But it often doesn't, so here they are.
-        pretty_printers_dict[re.compile('^std::_List_iterator<.*>$')] = lambda val: StdListIteratorPrinter("std::_List_iterator",val)
-        pretty_printers_dict[re.compile('^std::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter("std::_List_const_iterator",val)
-        pretty_printers_dict[re.compile('^std::_Rb_tree_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
-        pretty_printers_dict[re.compile('^std::_Rb_tree_const_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
-        pretty_printers_dict[re.compile('^std::_Deque_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
-        pretty_printers_dict[re.compile('^std::_Deque_const_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
-        pretty_printers_dict[re.compile('^__gnu_cxx::__normal_iterator<.*>$')] = lambda val: StdVectorIteratorPrinter(val)
-        pretty_printers_dict[re.compile('^__gnu_cxx::_Slist_iterator<.*>$')] = lambda val: StdSlistIteratorPrinter(val)
+        libstdcxx_printer.add('std::_List_iterator', StdListIteratorPrinter)
+        libstdcxx_printer.add('std::_List_const_iterator',
+                              StdListIteratorPrinter)
+        libstdcxx_printer.add('std::_Rb_tree_iterator',
+                              StdRbtreeIteratorPrinter)
+        libstdcxx_printer.add('std::_Rb_tree_const_iterator',
+                              StdRbtreeIteratorPrinter)
+        libstdcxx_printer.add('std::_Deque_iterator', StdDequeIteratorPrinter)
+        libstdcxx_printer.add('std::_Deque_const_iterator',
+                              StdDequeIteratorPrinter)
+        libstdcxx_printer.add('__gnu_cxx::__normal_iterator',
+                              StdVectorIteratorPrinter)
+        libstdcxx_printer.add('__gnu_cxx::_Slist_iterator',
+                              StdSlistIteratorPrinter)
 
-        # Debug (compiled with -D_GLIBCXX_DEBUG) printer registrations.
-        # The Rb_tree debug iterator when unwrapped from the encapsulating __gnu_debug::_Safe_iterator
-        # does not have the __norm namespace. Just use the existing printer registration for that.
-        pretty_printers_dict[re.compile('^__gnu_debug::_Safe_iterator<.*>$')] = lambda val: StdDebugIteratorPrinter(val)
-        pretty_printers_dict[re.compile('^std::__norm::_List_iterator<.*>$')] = lambda val: StdListIteratorPrinter ("std::__norm::_List_iterator",val)
-        pretty_printers_dict[re.compile('^std::__norm::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter ("std::__norm::_List_const_iterator",val)
-        pretty_printers_dict[re.compile('^std::__norm::_Deque_const_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
-        pretty_printers_dict[re.compile('^std::__norm::_Deque_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
+        # Debug (compiled with -D_GLIBCXX_DEBUG) printer
+        # registrations.  The Rb_tree debug iterator when unwrapped
+        # from the encapsulating __gnu_debug::_Safe_iterator does not
+        # have the __norm namespace. Just use the existing printer
+        # registration for that.
+        libstdcxx_printer.add('__gnu_debug::_Safe_iterator',
+                              StdDebugIteratorPrinter)
+        libstdcxx_printer.add('std::__norm::_List_iterator',
+                              StdListIteratorPrinter)
+        libstdcxx_printer.add('std::__norm::_List_const_iterator',
+                              StdListIteratorPrinter)
+        libstdcxx_printer.add('std::__norm::_Deque_const_iterator',
+                              StdDequeIteratorPrinter)
+        libstdcxx_printer.add('std::__norm::_Deque_iterator',
+                              StdDequeIteratorPrinter)
 
-pretty_printers_dict = {}
-
 build_libstdcxx_dictionary ()


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]