printers.py (SingleObjContainerPrinter): New base class for experimental::any and...
authorJonathan Wakely <jwakely@redhat.com>
Tue, 15 Jul 2014 12:00:18 +0000 (13:00 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 15 Jul 2014 12:00:18 +0000 (13:00 +0100)
* python/libstdcxx/v6/printers.py (SingleObjContainerPrinter): New
base class for experimental::any and experimental::optional printers.
(StdExpAnyPrinter, StdExpOptionalPrinter, StdExpStringViewPrinter):
New printers for Fundamentals TS types.
* testsuite/libstdc++-prettyprinters/libfundts.cc: New.

From-SVN: r212556

libstdc++-v3/ChangeLog
libstdc++-v3/python/libstdcxx/v6/printers.py
libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc [new file with mode: 0644]

index c59c25453e1467130ea7788477278e61a571dd4e..32de8825ae546fd9e46491eb749683b320c28914 100644 (file)
@@ -6,6 +6,12 @@
        and other class templates with default template arguments.
        * testsuite/libstdc++-prettyprinters/whatis.cc: Test new recognizers.
 
+       * python/libstdcxx/v6/printers.py (SingleObjContainerPrinter): New
+       base class for experimental::any and experimental::optional printers.
+       (StdExpAnyPrinter, StdExpOptionalPrinter, StdExpStringViewPrinter):
+       New printers for Fundamentals TS types.
+       * testsuite/libstdc++-prettyprinters/libfundts.cc: New.
+
 2014-07-15  Tim Shen  <timshen@google.com>
 
        PR libstdc++/61720
index ea34f222cdfeb4122e0d5cc0888b6af9da1be244..af41f1ffaeb443b357e05414c7772955a2fa51d9 100644 (file)
@@ -836,6 +836,126 @@ class StdForwardListPrinter:
             return 'empty %s' % (self.typename)
         return '%s' % (self.typename)
 
+class SingleObjContainerPrinter(object):
+    "Base class for printers of containers of single objects"
+
+    def __init__ (self, val, viz):
+        self.contained_value = val
+        self.visualizer = viz
+
+    def _recognize(self, type):
+        """Return TYPE as a string after applying type printers"""
+        return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(),
+                                                type) or str(type)
+
+    class _contained:
+        def __init__ (self, val):
+            self.val = val
+
+        def __iter__ (self):
+            return self
+
+        def next (self):
+            if self.val is None:
+                raise StopIteration
+            retval = self.val
+            self.val = None
+            return ('[contained value]', retval)
+
+    def children (self):
+        if self.contained_value is None:
+            return self._contained (None)
+        if hasattr (self.visualizer, 'children'):
+            return self.visualizer.children ()
+        return self._contained (self.contained_value)
+
+    def display_hint (self):
+        # if contained value is a map we want to display in the same way
+        if hasattr (self.visualizer, 'children') and hasattr (self.visualizer, 'display_hint'):
+            return self.visualizer.display_hint ()
+        return None
+
+
+class StdExpAnyPrinter(SingleObjContainerPrinter):
+    "Print a std::experimental::any"
+
+    def __init__ (self, typename, val):
+        self.typename = 'std::experimental::any'
+        self.val = val
+        self.contained_type = None
+        contained_value = None
+        visualizer = None
+        mgr = self.val['_M_manager']
+        if mgr != 0:
+            func = gdb.block_for_pc(int(mgr.cast(gdb.lookup_type('intptr_t'))))
+            if not func:
+                raise ValueError("Invalid function pointer in std::experimental::any")
+            rx = r"""({0}::_Manager_\w+<.*>)::_S_manage\({0}::_Op, {0} const\*, {0}::_Arg\*\)""".format(typename)
+            m = re.match(rx, func.function.name)
+            if not m:
+                raise ValueError("Unknown manager function in std::experimental::any")
+
+            # FIXME need to expand 'std::string' so that gdb.lookup_type works
+            mgrname = re.sub("std::string(?!\w)", gdb.lookup_type('std::string').strip_typedefs().name, m.group(1))
+            mgrtype = gdb.lookup_type(mgrname)
+            self.contained_type = mgrtype.template_argument(0)
+            valptr = None
+            if '::_Manager_internal' in mgrname:
+                valptr = self.val['_M_storage']['_M_buffer'].address
+            elif '::_Manager_external' in mgrname:
+                valptr = self.val['_M_storage']['_M_ptr']
+            elif '::_Manager_alloc' in mgrname:
+                datatype = gdb.lookup_type(mgrname + '::_Data')
+                valptr = self.val['_M_storage']['_M_ptr'].cast(datatype.pointer())
+                valptr = valptr.dereference()['_M_data'].address
+            else:
+                raise ValueError("Unknown manager function in std::experimental::any")
+            contained_value = valptr.cast(self.contained_type.pointer()).dereference()
+            visualizer = gdb.default_visualizer(contained_value)
+        super(StdExpAnyPrinter, self).__init__ (contained_value, visualizer)
+
+    def to_string (self):
+        if self.contained_type is None:
+            return '%s [no contained value]' % self.typename
+        desc = "%s containing " % self.typename
+        if hasattr (self.visualizer, 'children'):
+            return desc + self.visualizer.to_string ()
+        valtype = self._recognize (self.contained_type)
+        return desc + valtype
+
+class StdExpOptionalPrinter(SingleObjContainerPrinter):
+    "Print a std::experimental::optional"
+
+    def __init__ (self, typename, val):
+        valtype = self._recognize (val.type.template_argument(0))
+        self.typename = "std::experimental::optional<%s>" % valtype
+        self.val = val
+        contained_value = val['_M_payload'] if self.val['_M_engaged'] else None
+        visualizer = gdb.default_visualizer (val['_M_payload'])
+        super (StdExpOptionalPrinter, self).__init__ (contained_value, visualizer)
+
+    def to_string (self):
+        if self.contained_value is None:
+            return self.typename + " [no contained value]"
+        if hasattr (self.visualizer, 'children'):
+            return self.typename + " containing " + self.visualizer.to_string ()
+        return self.typename
+
+class StdExpStringViewPrinter:
+    "Print a std::experimental::basic_string_view"
+
+    def __init__ (self, typename, val):
+        self.val = val
+
+    def to_string (self):
+        ptr = self.val['_M_str']
+        len = self.val['_M_len']
+        if hasattr (ptr, "lazy_string"):
+            return ptr.lazy_string (length = len)
+        return ptr.string (length = len)
+
+    def display_hint (self):
+        return 'string'
 
 # A "regular expression" printer which conforms to the
 # "SubPrettyPrinter" protocol from gdb.printing.
@@ -865,12 +985,12 @@ class Printer(object):
         self.subprinters = []
         self.lookup = {}
         self.enabled = True
-        self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)<.*>$')
+        self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
 
     def add(self, name, function):
         # A small sanity check.
         # FIXME
-        if not self.compiled_rx.match(name + '<>'):
+        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)
@@ -1214,6 +1334,13 @@ def build_libstdcxx_dictionary ():
     libstdcxx_printer.add('std::__debug::forward_list',
                           StdForwardListPrinter)
 
+    # Library Fundamentals TS components
+    libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
+                                  'any', StdExpAnyPrinter)
+    libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
+                                  'optional', StdExpOptionalPrinter)
+    libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
+                                  'basic_string_view', StdExpStringViewPrinter)
 
     # Extensions.
     libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter)
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc
new file mode 100644 (file)
index 0000000..e2f99a1
--- /dev/null
@@ -0,0 +1,69 @@
+// { dg-do run }
+// { dg-options "-g -O0 -std=gnu++14" }
+
+// Copyright (C) 2014 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <experimental/any>
+#include <experimental/optional>
+#include <experimental/string_view>
+#include <string>
+#include <map>
+
+using std::experimental::any;
+using std::experimental::optional;
+using std::experimental::string_view;
+
+int
+main()
+{
+  string_view str = "string";
+// { dg-final { note-test str "\"string\"" } }
+
+  optional<int> o;
+// { dg-final { note-test o {std::experimental::optional<int> [no contained value]} } }
+  optional<bool> ob{false};
+// { dg-final { note-test ob {std::experimental::optional<bool> = {[contained value] = false}} } }
+  optional<int> oi{5};
+// { dg-final { note-test oi {std::experimental::optional<int> = {[contained value] = 5}} } }
+  optional<void*> op{nullptr};
+// { dg-final { note-test op {std::experimental::optional<void *> = {[contained value] = 0x0}} } }
+  optional<std::map<int, double>> om;
+  om = std::map<int, double>{ {1, 2.}, {3, 4.}, {5, 6.} };
+// { dg-final { note-test om {std::experimental::optional<std::map<int, double>> containing std::map with 3 elements = {[1] = 2, [3] = 4, [5] = 6}} } }
+  optional<std::string> os{ "stringy" };
+// { dg-final { note-test os {std::experimental::optional<std::string> = {[contained value] = "stringy"}} } }
+
+  any a;
+// { dg-final { note-test a {std::experimental::any [no contained value]} } }
+  any ab(false);
+// { dg-final { note-test ab {std::experimental::any containing bool = {[contained value] = false}} } }
+  any ai(6);
+// { dg-final { note-test ai {std::experimental::any containing int = {[contained value] = 6}} } }
+  any ap = (void*)nullptr;
+// { dg-final { note-test ap {std::experimental::any containing void * = {[contained value] = 0x0}} } }
+  any as = *os;
+// { dg-final { note-test as {std::experimental::any containing std::string = {[contained value] = "stringy"}} } }
+  any as2("stringiest");
+// { dg-final { regexp-test as2 {std::experimental::any containing const char \* = {\[contained value\] = 0x[[:xdigit:]]+ "stringiest"}} } }
+  any am = *om;
+// { dg-final { note-test am {std::experimental::any containing std::map with 3 elements = {[1] = 2, [3] = 4, [5] = 6}} } }
+
+  return 0;                    // Mark SPOT
+}
+
+// { dg-final { gdb-test SPOT } }