mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-29 19:07:15 +02:00
Merge pull request #274 from k3DW/gdb
Write GDB pretty-printers for all containers and iterators
This commit is contained in:
@ -12,6 +12,7 @@
|
||||
`boost::concurrent_flat_set` operations to allow for safe mutable modification of elements
|
||||
({github-pr-url}/265[PR#265^]).
|
||||
* In Visual Studio Natvis, supported any container with an allocator that uses fancy pointers. This applies to any fancy pointer type, as long as the proper Natvis customization point "Intrinsic" functions are written for the fancy pointer type.
|
||||
* Added GDB pretty-printers for all containers and iterators. For a container with an allocator that uses fancy pointers, these only work if the proper pretty-printer is written for the fancy pointer type itself.
|
||||
|
||||
== Release 1.86.0
|
||||
|
||||
|
@ -24,3 +24,67 @@ Iterators are displayed similarly to their standard counterparts. An iterator is
|
||||
=== Fancy pointers
|
||||
|
||||
The container visualizations also work if you are using fancy pointers in your allocator, such as `boost::interprocess::offset_ptr`. While this is rare, Boost.Unordered has natvis customization points to support any type of fancy pointer. `boost::interprocess::offset_ptr` has support already defined in the Boost.Interprocess library, and you can add support to your own type by following the instructions contained in a comment near the end of the file link:https://github.com/boostorg/unordered/blob/develop/extra/boost_unordered.natvis[/extra/boost_unordered.natvis].
|
||||
|
||||
== GDB Pretty-Printers
|
||||
|
||||
All containers and iterators have a custom GDB pretty-printer.
|
||||
|
||||
=== Using in your project
|
||||
|
||||
Always, when using pretty-printers, you must enable pretty-printing like below. This is typically a one-time setup.
|
||||
|
||||
```plaintext
|
||||
(gdb) set print pretty on
|
||||
```
|
||||
|
||||
By default, if you compile into an ELF binary format, your binary will contain the Boost.Unordered pretty-printers. To use the embedded pretty-printers, ensure you allow auto-loading like below. This must be done every time you load GDB, or add it to a ".gdbinit" file.
|
||||
|
||||
```plaintext
|
||||
(gdb) add-auto-load-safe-path [/path/to/executable]
|
||||
```
|
||||
|
||||
You can choose to compile your binary _without_ embedding the pretty-printers by defining `BOOST_ALL_NO_EMBEDDED_GDB_PRINTERS`, which disables the embedded GDB pretty-printers for all Boost libraries that have this feature.
|
||||
|
||||
You can load the pretty-printers externally from the non-embedded Python script. Add the script, link:https://github.com/boostorg/unordered/blob/develop/extra/boost_unordered_printers.py[/extra/boost_unordered_printers.py], using the `source` command as shown below.
|
||||
|
||||
```plaintext
|
||||
(gdb) source [/path/to/boost]/libs/unordered/extra/boost_unordered_printers.py
|
||||
```
|
||||
|
||||
=== Visualization structure
|
||||
|
||||
The visualizations mirror the standard unordered containers. The map containers display an association from key to mapped value. The set containers display an association from index to value. An iterator is either displayed with its item, or as an end iterator. Here is what may be shown for an example `boost::unordered_map`, an example `boost::unordered_set`, and their respective begin and end iterators.
|
||||
|
||||
```plaintext
|
||||
(gdb) print example_unordered_map
|
||||
$1 = boost::unordered_map with 3 elements = {["C"] = "c", ["B"] = "b", ["A"] = "a"}
|
||||
(gdb) print example_unordered_map_begin
|
||||
$2 = iterator = { {first = "C", second = "c"} }
|
||||
(gdb) print example_unordered_map_end
|
||||
$3 = iterator = { end iterator }
|
||||
(gdb) print example_unordered_set
|
||||
$4 = boost::unordered_set with 3 elements = {[0] = "c", [1] = "b", [2] = "a"}
|
||||
(gdb) print example_unordered_set_begin
|
||||
$5 = iterator = { "c" }
|
||||
(gdb) print example_unordered_set_end
|
||||
$6 = iterator = { end iterator }
|
||||
```
|
||||
|
||||
The other containers are identical other than replacing "`boost::unordered_{map|set}`" with the appropriate template name when displaying the container itself. Note that each sub-element (i.e. the key, the mapped value, or the value) is displayed based on its own printing settings which may include its own pretty-printer.
|
||||
|
||||
Both the SIMD and the non-SIMD implementations are viewable through the GDB pretty-printers.
|
||||
|
||||
For open-addressing containers where xref:#hash_quality_container_statistics[container statistics] are enabled, you can obtain these statistics by calling `get_stats()` on the container, from within GDB. This is overridden in GDB as an link:https://sourceware.org/gdb/current/onlinedocs/gdb.html/Xmethod-API.html[xmethod], so it will not invoke any C++ synchronization code. See the following printout as an example for the expected format.
|
||||
|
||||
```plaintext
|
||||
(gdb) print example_flat_map.get_stats()
|
||||
$1 = [stats] = {[insertion] = {[count] = 5, [probe_length] = {avg = 1.0, var = 0.0, dev = 0.0}},
|
||||
[successful_lookup] = {[count] = 0, [probe_length] = {avg = 0.0, var = 0.0, dev = 0.0},
|
||||
[num_comparisons] = {avg = 0.0, var = 0.0, dev = 0.0}}, [unsuccessful_lookup] = {[count] = 5,
|
||||
[probe_length] = {avg = 1.0, var = 0.0, dev = 0.0},
|
||||
[num_comparisons] = {avg = 0.0, var = 0.0, dev = 0.0}}}
|
||||
```
|
||||
|
||||
=== Fancy pointers
|
||||
|
||||
The pretty-printers also work if you are using fancy pointers in your allocator, such as `boost::interprocess::offset_ptr`. While this is rare, Boost.Unordered has GDB pretty-printer customization points to support any type of fancy pointer. `boost::interprocess::offset_ptr` has support already defined in the Boost.Interprocess library, and you can add support to your own type by following the instructions contained in a comment near the end of the file link:https://github.com/boostorg/unordered/blob/develop/extra/boost_unordered_printers.py[/extra/boost_unordered_printers.py].
|
||||
|
389
extra/boost_unordered_printers.py
Normal file
389
extra/boost_unordered_printers.py
Normal file
@ -0,0 +1,389 @@
|
||||
# Copyright 2024 Braden Ganetsky
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
import gdb.printing
|
||||
import gdb.xmethod
|
||||
import re
|
||||
import math
|
||||
|
||||
class BoostUnorderedHelpers:
|
||||
def maybe_unwrap_atomic(n):
|
||||
if f"{n.type.strip_typedefs()}".startswith("std::atomic<"):
|
||||
underlying_type = n.type.template_argument(0)
|
||||
return n.cast(underlying_type)
|
||||
else:
|
||||
return n
|
||||
|
||||
def maybe_unwrap_foa_element(e):
|
||||
if f"{e.type.strip_typedefs()}".startswith("boost::unordered::detail::foa::element_type<"):
|
||||
return e["p"]
|
||||
else:
|
||||
return e
|
||||
|
||||
def maybe_unwrap_reference(value):
|
||||
if value.type.code == gdb.TYPE_CODE_REF:
|
||||
return value.referenced_value()
|
||||
else:
|
||||
return value
|
||||
|
||||
def countr_zero(n):
|
||||
for i in range(32):
|
||||
if (n & (1 << i)) != 0:
|
||||
return i
|
||||
return 32
|
||||
|
||||
class BoostUnorderedPointerCustomizationPoint:
|
||||
def __init__(self, any_ptr):
|
||||
vis = gdb.default_visualizer(any_ptr)
|
||||
if vis is None:
|
||||
self.to_address = lambda ptr: ptr
|
||||
self.next = lambda ptr, offset: ptr + offset
|
||||
else:
|
||||
self.to_address = lambda ptr: ptr if (ptr.type.code == gdb.TYPE_CODE_PTR) else type(vis).boost_to_address(ptr)
|
||||
self.next = lambda ptr, offset: type(vis).boost_next(ptr, offset)
|
||||
|
||||
class BoostUnorderedFcaPrinter:
|
||||
def __init__(self, val):
|
||||
self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)
|
||||
self.name = f"{self.val.type.strip_typedefs()}".split("<")[0]
|
||||
self.name = self.name.replace("boost::unordered::", "boost::")
|
||||
self.is_map = self.name.endswith("map")
|
||||
self.cpo = BoostUnorderedPointerCustomizationPoint(self.val["table_"]["buckets_"]["buckets"])
|
||||
|
||||
def to_string(self):
|
||||
size = self.val["table_"]["size_"]
|
||||
return f"{self.name} with {size} elements"
|
||||
|
||||
def display_hint(self):
|
||||
return "map"
|
||||
|
||||
def children(self):
|
||||
def generator():
|
||||
grouped_buckets = self.val["table_"]["buckets_"]
|
||||
|
||||
size = grouped_buckets["size_"]
|
||||
buckets = grouped_buckets["buckets"]
|
||||
bucket_index = 0
|
||||
|
||||
count = 0
|
||||
while bucket_index != size:
|
||||
current_bucket = self.cpo.next(self.cpo.to_address(buckets), bucket_index)
|
||||
node = self.cpo.to_address(current_bucket.dereference()["next"])
|
||||
while node != 0:
|
||||
value = node.dereference()["buf"]["t_"]
|
||||
if self.is_map:
|
||||
first = value["first"]
|
||||
second = value["second"]
|
||||
yield "", first
|
||||
yield "", second
|
||||
else:
|
||||
yield "", count
|
||||
yield "", value
|
||||
count += 1
|
||||
node = self.cpo.to_address(node.dereference()["next"])
|
||||
bucket_index += 1
|
||||
|
||||
return generator()
|
||||
|
||||
class BoostUnorderedFcaIteratorPrinter:
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.cpo = BoostUnorderedPointerCustomizationPoint(self.val["p"])
|
||||
|
||||
def to_string(self):
|
||||
if self.valid():
|
||||
value = self.cpo.to_address(self.val["p"]).dereference()["buf"]["t_"]
|
||||
return f"iterator = {{ {value} }}"
|
||||
else:
|
||||
return "iterator = { end iterator }"
|
||||
|
||||
def valid(self):
|
||||
return (self.cpo.to_address(self.val["p"]) != 0) and (self.cpo.to_address(self.val["itb"]["p"]) != 0)
|
||||
|
||||
class BoostUnorderedFoaTableCoreCumulativeStatsPrinter:
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
return "[stats]"
|
||||
|
||||
def display_hint(self):
|
||||
return "map"
|
||||
|
||||
def children(self):
|
||||
def generator():
|
||||
members = ["insertion", "successful_lookup", "unsuccessful_lookup"]
|
||||
for member in members:
|
||||
yield "", member
|
||||
yield "", self.val[member]
|
||||
return generator()
|
||||
|
||||
class BoostUnorderedFoaCumulativeStatsPrinter:
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.n = self.val["n"]
|
||||
self.N = self.val.type.template_argument(0)
|
||||
|
||||
def display_hint(self):
|
||||
return "map"
|
||||
|
||||
def children(self):
|
||||
def generator():
|
||||
yield "", "count"
|
||||
yield "", self.n
|
||||
|
||||
sequence_stats_data = gdb.lookup_type("boost::unordered::detail::foa::sequence_stats_data")
|
||||
data = self.val["data"]
|
||||
arr = data.address.reinterpret_cast(sequence_stats_data.pointer())
|
||||
def build_string(idx):
|
||||
entry = arr[idx]
|
||||
avg = float(entry["m"])
|
||||
var = float(entry["s"] / self.n) if (self.n != 0) else 0.0
|
||||
dev = math.sqrt(var)
|
||||
return f"{{avg = {avg}, var = {var}, dev = {dev}}}"
|
||||
|
||||
if self.N > 0:
|
||||
yield "", "probe_length"
|
||||
yield "", build_string(0)
|
||||
if self.N > 1:
|
||||
yield "", "num_comparisons"
|
||||
yield "", build_string(1)
|
||||
|
||||
return generator()
|
||||
|
||||
class BoostUnorderedFoaPrinter:
|
||||
def __init__(self, val):
|
||||
self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)
|
||||
self.name = f"{self.val.type.strip_typedefs()}".split("<")[0]
|
||||
self.name = self.name.replace("boost::unordered::", "boost::")
|
||||
self.is_map = self.name.endswith("map")
|
||||
self.cpo = BoostUnorderedPointerCustomizationPoint(self.val["table_"]["arrays"]["groups_"])
|
||||
|
||||
def to_string(self):
|
||||
size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.val["table_"]["size_ctrl"]["size"])
|
||||
return f"{self.name} with {size} elements"
|
||||
|
||||
def display_hint(self):
|
||||
return "map"
|
||||
|
||||
def is_regular_layout(self, group):
|
||||
typename = group["m"].type.strip_typedefs()
|
||||
array_size = typename.sizeof // typename.target().sizeof
|
||||
if array_size == 16:
|
||||
return True
|
||||
elif array_size == 2:
|
||||
return False
|
||||
|
||||
def match_occupied(self, group):
|
||||
m = group["m"]
|
||||
at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b]["n"])
|
||||
|
||||
if self.is_regular_layout(group):
|
||||
bits = [1 << b for b in range(16) if at(b) == 0]
|
||||
return 0x7FFF & ~sum(bits)
|
||||
else:
|
||||
xx = at(0) | at(1)
|
||||
yy = xx | (xx >> 32)
|
||||
return 0x7FFF & (yy | (yy >> 16))
|
||||
|
||||
def is_sentinel(self, group, pos):
|
||||
m = group["m"]
|
||||
at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b]["n"])
|
||||
|
||||
N = group["N"]
|
||||
sentinel_ = group["sentinel_"]
|
||||
if self.is_regular_layout(group):
|
||||
return pos == N-1 and at(N-1) == sentinel_
|
||||
else:
|
||||
return pos == N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0
|
||||
|
||||
def children(self):
|
||||
def generator():
|
||||
table = self.val["table_"]
|
||||
groups = self.cpo.to_address(table["arrays"]["groups_"])
|
||||
elements = self.cpo.to_address(table["arrays"]["elements_"])
|
||||
|
||||
pc_ = groups.cast(gdb.lookup_type("unsigned char").pointer())
|
||||
p_ = elements
|
||||
first_time = True
|
||||
mask = 0
|
||||
n0 = 0
|
||||
n = 0
|
||||
|
||||
count = 0
|
||||
while p_ != 0:
|
||||
# This if block mirrors the condition in the begin() call
|
||||
if (not first_time) or (self.match_occupied(groups.dereference()) & 1):
|
||||
pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(p_)
|
||||
value = self.cpo.to_address(pointer).dereference()
|
||||
if self.is_map:
|
||||
first = value["first"]
|
||||
second = value["second"]
|
||||
yield "", first
|
||||
yield "", second
|
||||
else:
|
||||
yield "", count
|
||||
yield "", value
|
||||
count += 1
|
||||
first_time = False
|
||||
|
||||
n0 = pc_.cast(gdb.lookup_type("uintptr_t")) % groups.dereference().type.sizeof
|
||||
pc_ = self.cpo.next(pc_, -n0)
|
||||
|
||||
mask = (self.match_occupied(pc_.cast(groups.type).dereference()) >> (n0+1)) << (n0+1)
|
||||
while mask == 0:
|
||||
pc_ = self.cpo.next(pc_, groups.dereference().type.sizeof)
|
||||
p_ = self.cpo.next(p_, groups.dereference()["N"])
|
||||
mask = self.match_occupied(pc_.cast(groups.type).dereference())
|
||||
|
||||
n = BoostUnorderedHelpers.countr_zero(mask)
|
||||
if self.is_sentinel(pc_.cast(groups.type).dereference(), n):
|
||||
p_ = 0
|
||||
else:
|
||||
pc_ = self.cpo.next(pc_, n)
|
||||
p_ = self.cpo.next(p_, n - n0)
|
||||
|
||||
return generator()
|
||||
|
||||
class BoostUnorderedFoaIteratorPrinter:
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.cpo = BoostUnorderedPointerCustomizationPoint(self.val["p_"])
|
||||
|
||||
def to_string(self):
|
||||
if self.valid():
|
||||
element = self.cpo.to_address(self.val["p_"])
|
||||
pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(element)
|
||||
value = self.cpo.to_address(pointer).dereference()
|
||||
return f"iterator = {{ {value} }}"
|
||||
else:
|
||||
return "iterator = { end iterator }"
|
||||
|
||||
def valid(self):
|
||||
return (self.cpo.to_address(self.val["p_"]) != 0) and (self.cpo.to_address(self.val["pc_"]) != 0)
|
||||
|
||||
def boost_unordered_build_pretty_printer():
|
||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("boost_unordered")
|
||||
add_template_printer = lambda name, printer: pp.add_printer(name, f"^{name}<.*>$", printer)
|
||||
add_concrete_printer = lambda name, printer: pp.add_printer(name, f"^{name}$", printer)
|
||||
|
||||
add_template_printer("boost::unordered::unordered_map", BoostUnorderedFcaPrinter)
|
||||
add_template_printer("boost::unordered::unordered_multimap", BoostUnorderedFcaPrinter)
|
||||
add_template_printer("boost::unordered::unordered_set", BoostUnorderedFcaPrinter)
|
||||
add_template_printer("boost::unordered::unordered_multiset", BoostUnorderedFcaPrinter)
|
||||
|
||||
add_template_printer("boost::unordered::detail::iterator_detail::iterator", BoostUnorderedFcaIteratorPrinter)
|
||||
add_template_printer("boost::unordered::detail::iterator_detail::c_iterator", BoostUnorderedFcaIteratorPrinter)
|
||||
|
||||
add_template_printer("boost::unordered::unordered_flat_map", BoostUnorderedFoaPrinter)
|
||||
add_template_printer("boost::unordered::unordered_flat_set", BoostUnorderedFoaPrinter)
|
||||
add_template_printer("boost::unordered::unordered_node_map", BoostUnorderedFoaPrinter)
|
||||
add_template_printer("boost::unordered::unordered_node_set", BoostUnorderedFoaPrinter)
|
||||
add_template_printer("boost::unordered::concurrent_flat_map", BoostUnorderedFoaPrinter)
|
||||
add_template_printer("boost::unordered::concurrent_flat_set", BoostUnorderedFoaPrinter)
|
||||
|
||||
add_template_printer("boost::unordered::detail::foa::table_iterator", BoostUnorderedFoaIteratorPrinter)
|
||||
|
||||
add_concrete_printer("boost::unordered::detail::foa::table_core_cumulative_stats", BoostUnorderedFoaTableCoreCumulativeStatsPrinter)
|
||||
add_template_printer("boost::unordered::detail::foa::cumulative_stats", BoostUnorderedFoaCumulativeStatsPrinter)
|
||||
add_template_printer("boost::unordered::detail::foa::concurrent_cumulative_stats", BoostUnorderedFoaCumulativeStatsPrinter)
|
||||
|
||||
return pp
|
||||
|
||||
gdb.printing.register_pretty_printer(gdb.current_objfile(), boost_unordered_build_pretty_printer())
|
||||
|
||||
|
||||
|
||||
# https://sourceware.org/gdb/current/onlinedocs/gdb.html/Writing-an-Xmethod.html
|
||||
class BoostUnorderedFoaGetStatsMethod(gdb.xmethod.XMethod):
|
||||
def __init__(self):
|
||||
gdb.xmethod.XMethod.__init__(self, "get_stats")
|
||||
|
||||
def get_worker(self, method_name):
|
||||
if method_name == "get_stats":
|
||||
return BoostUnorderedFoaGetStatsWorker()
|
||||
|
||||
class BoostUnorderedFoaGetStatsWorker(gdb.xmethod.XMethodWorker):
|
||||
def get_arg_types(self):
|
||||
return None
|
||||
|
||||
def get_result_type(self, obj):
|
||||
return gdb.lookup_type("boost::unordered::detail::foa::table_core_cumulative_stats")
|
||||
|
||||
def __call__(self, obj):
|
||||
try:
|
||||
return obj["table_"]["cstats"]
|
||||
except gdb.error:
|
||||
print("Error: Binary was compiled without stats. Recompile with `BOOST_UNORDERED_ENABLE_STATS` defined.")
|
||||
return
|
||||
|
||||
class BoostUnorderedFoaMatcher(gdb.xmethod.XMethodMatcher):
|
||||
def __init__(self):
|
||||
gdb.xmethod.XMethodMatcher.__init__(self, 'BoostUnorderedFoaMatcher')
|
||||
self.methods = [BoostUnorderedFoaGetStatsMethod()]
|
||||
|
||||
def match(self, class_type, method_name):
|
||||
template_name = f"{class_type.strip_typedefs()}".split("<")[0]
|
||||
regex = "^boost::unordered::(unordered|concurrent)_(flat|node)_(map|set)$"
|
||||
if not re.match(regex, template_name):
|
||||
return None
|
||||
|
||||
workers = []
|
||||
for method in self.methods:
|
||||
if method.enabled:
|
||||
worker = method.get_worker(method_name)
|
||||
if worker:
|
||||
workers.append(worker)
|
||||
return workers
|
||||
|
||||
gdb.xmethod.register_xmethod_matcher(None, BoostUnorderedFoaMatcher())
|
||||
|
||||
|
||||
|
||||
""" Fancy pointer support """
|
||||
|
||||
"""
|
||||
To allow your own fancy pointer type to interact with Boost.Unordered GDB pretty-printers,
|
||||
create a pretty-printer for your own type with the following additional methods.
|
||||
|
||||
(Note, this is assuming the presence of a type alias `pointer` for the underlying
|
||||
raw pointer type, Substitute whichever name is applicable in your case.)
|
||||
|
||||
`boost_to_address(fancy_ptr)`
|
||||
* A static method, but `@staticmethod` is not required
|
||||
* Parameter `fancy_ptr` of type `gdb.Value`
|
||||
* Its `.type` will be your fancy pointer type
|
||||
* Returns a `gdb.Value` with the raw pointer equivalent to your fancy pointer
|
||||
* This method should be equivalent to calling `operator->()` on your fancy pointer in C++
|
||||
|
||||
`boost_next(raw_ptr, offset)`
|
||||
* Parameter `raw_ptr` of type `gdb.Value`
|
||||
* Its `.type` will be `pointer`
|
||||
* Parameter `offset`
|
||||
* Either has integer type, or is of type `gdb.Value` with an underlying integer
|
||||
* Returns a `gdb.Value` with the raw pointer equivalent to your fancy pointer, as if you did the following operations
|
||||
1. Convert the incoming raw pointer to your fancy pointer
|
||||
2. Use operator+= to add the offset to the fancy pointer
|
||||
3. Convert back to the raw pointer
|
||||
* Note, you will not actually do these operations as stated. You will do equivalent lower-level operations that emulate having done the above
|
||||
* Ultimately, it will be as if you called `operator+()` on your fancy pointer in C++, but using only raw pointers
|
||||
|
||||
Example
|
||||
```
|
||||
class MyFancyPtrPrinter:
|
||||
...
|
||||
|
||||
# Equivalent to `operator->()`
|
||||
def boost_to_address(fancy_ptr):
|
||||
...
|
||||
return ...
|
||||
|
||||
# Equivalent to `operator+()`
|
||||
def boost_next(raw_ptr, offset):
|
||||
...
|
||||
return ...
|
||||
|
||||
...
|
||||
```
|
||||
"""
|
@ -29,6 +29,7 @@
|
||||
#include <boost/unordered/detail/static_assert.hpp>
|
||||
#include <boost/unordered/detail/type_traits.hpp>
|
||||
#include <boost/unordered/hash_traits.hpp>
|
||||
#include <boost/unordered/unordered_printers.hpp>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
412
include/boost/unordered/unordered_printers.hpp
Normal file
412
include/boost/unordered/unordered_printers.hpp
Normal file
@ -0,0 +1,412 @@
|
||||
// Copyright 2024 Braden Ganetsky
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// Generated on 2024-08-16T22:14:16
|
||||
|
||||
#ifndef BOOST_UNORDERED_UNORDERED_PRINTERS_HPP
|
||||
#define BOOST_UNORDERED_UNORDERED_PRINTERS_HPP
|
||||
|
||||
#ifndef BOOST_ALL_NO_EMBEDDED_GDB_SCRIPTS
|
||||
#if defined(__ELF__)
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Woverlength-strings"
|
||||
#endif
|
||||
__asm__(".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n"
|
||||
".ascii \"\\4gdb.inlined-script.BOOST_UNORDERED_UNORDERED_PRINTERS_HPP\\n\"\n"
|
||||
".ascii \"import gdb.printing\\n\"\n"
|
||||
".ascii \"import gdb.xmethod\\n\"\n"
|
||||
".ascii \"import re\\n\"\n"
|
||||
".ascii \"import math\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedHelpers:\\n\"\n"
|
||||
".ascii \" def maybe_unwrap_atomic(n):\\n\"\n"
|
||||
".ascii \" if f\\\"{n.type.strip_typedefs()}\\\".startswith(\\\"std::atomic<\\\"):\\n\"\n"
|
||||
".ascii \" underlying_type = n.type.template_argument(0)\\n\"\n"
|
||||
".ascii \" return n.cast(underlying_type)\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" return n\\n\"\n"
|
||||
|
||||
".ascii \" def maybe_unwrap_foa_element(e):\\n\"\n"
|
||||
".ascii \" if f\\\"{e.type.strip_typedefs()}\\\".startswith(\\\"boost::unordered::detail::foa::element_type<\\\"):\\n\"\n"
|
||||
".ascii \" return e[\\\"p\\\"]\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" return e\\n\"\n"
|
||||
|
||||
".ascii \" def maybe_unwrap_reference(value):\\n\"\n"
|
||||
".ascii \" if value.type.code == gdb.TYPE_CODE_REF:\\n\"\n"
|
||||
".ascii \" return value.referenced_value()\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" return value\\n\"\n"
|
||||
|
||||
".ascii \" def countr_zero(n):\\n\"\n"
|
||||
".ascii \" for i in range(32):\\n\"\n"
|
||||
".ascii \" if (n & (1 << i)) != 0:\\n\"\n"
|
||||
".ascii \" return i\\n\"\n"
|
||||
".ascii \" return 32\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedPointerCustomizationPoint:\\n\"\n"
|
||||
".ascii \" def __init__(self, any_ptr):\\n\"\n"
|
||||
".ascii \" vis = gdb.default_visualizer(any_ptr)\\n\"\n"
|
||||
".ascii \" if vis is None:\\n\"\n"
|
||||
".ascii \" self.to_address = lambda ptr: ptr\\n\"\n"
|
||||
".ascii \" self.next = lambda ptr, offset: ptr + offset\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" self.to_address = lambda ptr: ptr if (ptr.type.code == gdb.TYPE_CODE_PTR) else type(vis).boost_to_address(ptr)\\n\"\n"
|
||||
".ascii \" self.next = lambda ptr, offset: type(vis).boost_next(ptr, offset)\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedFcaPrinter:\\n\"\n"
|
||||
".ascii \" def __init__(self, val):\\n\"\n"
|
||||
".ascii \" self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n"
|
||||
".ascii \" self.name = f\\\"{self.val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n"
|
||||
".ascii \" self.name = self.name.replace(\\\"boost::unordered::\\\", \\\"boost::\\\")\\n\"\n"
|
||||
".ascii \" self.is_map = self.name.endswith(\\\"map\\\")\\n\"\n"
|
||||
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.val[\\\"table_\\\"][\\\"buckets_\\\"][\\\"buckets\\\"])\\n\"\n"
|
||||
|
||||
".ascii \" def to_string(self):\\n\"\n"
|
||||
".ascii \" size = self.val[\\\"table_\\\"][\\\"size_\\\"]\\n\"\n"
|
||||
".ascii \" return f\\\"{self.name} with {size} elements\\\"\\n\"\n"
|
||||
|
||||
".ascii \" def display_hint(self):\\n\"\n"
|
||||
".ascii \" return \\\"map\\\"\\n\"\n"
|
||||
|
||||
".ascii \" def children(self):\\n\"\n"
|
||||
".ascii \" def generator():\\n\"\n"
|
||||
".ascii \" grouped_buckets = self.val[\\\"table_\\\"][\\\"buckets_\\\"]\\n\"\n"
|
||||
|
||||
".ascii \" size = grouped_buckets[\\\"size_\\\"]\\n\"\n"
|
||||
".ascii \" buckets = grouped_buckets[\\\"buckets\\\"]\\n\"\n"
|
||||
".ascii \" bucket_index = 0\\n\"\n"
|
||||
|
||||
".ascii \" count = 0\\n\"\n"
|
||||
".ascii \" while bucket_index != size:\\n\"\n"
|
||||
".ascii \" current_bucket = self.cpo.next(self.cpo.to_address(buckets), bucket_index)\\n\"\n"
|
||||
".ascii \" node = self.cpo.to_address(current_bucket.dereference()[\\\"next\\\"])\\n\"\n"
|
||||
".ascii \" while node != 0:\\n\"\n"
|
||||
".ascii \" value = node.dereference()[\\\"buf\\\"][\\\"t_\\\"]\\n\"\n"
|
||||
".ascii \" if self.is_map:\\n\"\n"
|
||||
".ascii \" first = value[\\\"first\\\"]\\n\"\n"
|
||||
".ascii \" second = value[\\\"second\\\"]\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", first\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", second\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", count\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", value\\n\"\n"
|
||||
".ascii \" count += 1\\n\"\n"
|
||||
".ascii \" node = self.cpo.to_address(node.dereference()[\\\"next\\\"])\\n\"\n"
|
||||
".ascii \" bucket_index += 1\\n\"\n"
|
||||
|
||||
".ascii \" return generator()\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedFcaIteratorPrinter:\\n\"\n"
|
||||
".ascii \" def __init__(self, val):\\n\"\n"
|
||||
".ascii \" self.val = val\\n\"\n"
|
||||
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.val[\\\"p\\\"])\\n\"\n"
|
||||
|
||||
".ascii \" def to_string(self):\\n\"\n"
|
||||
".ascii \" if self.valid():\\n\"\n"
|
||||
".ascii \" value = self.cpo.to_address(self.val[\\\"p\\\"]).dereference()[\\\"buf\\\"][\\\"t_\\\"]\\n\"\n"
|
||||
".ascii \" return f\\\"iterator = {{ {value} }}\\\"\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" return \\\"iterator = { end iterator }\\\"\\n\"\n"
|
||||
|
||||
".ascii \" def valid(self):\\n\"\n"
|
||||
".ascii \" return (self.cpo.to_address(self.val[\\\"p\\\"]) != 0) and (self.cpo.to_address(self.val[\\\"itb\\\"][\\\"p\\\"]) != 0)\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedFoaTableCoreCumulativeStatsPrinter:\\n\"\n"
|
||||
".ascii \" def __init__(self, val):\\n\"\n"
|
||||
".ascii \" self.val = val\\n\"\n"
|
||||
|
||||
".ascii \" def to_string(self):\\n\"\n"
|
||||
".ascii \" return \\\"[stats]\\\"\\n\"\n"
|
||||
|
||||
".ascii \" def display_hint(self):\\n\"\n"
|
||||
".ascii \" return \\\"map\\\"\\n\"\n"
|
||||
|
||||
".ascii \" def children(self):\\n\"\n"
|
||||
".ascii \" def generator():\\n\"\n"
|
||||
".ascii \" members = [\\\"insertion\\\", \\\"successful_lookup\\\", \\\"unsuccessful_lookup\\\"]\\n\"\n"
|
||||
".ascii \" for member in members:\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", member\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", self.val[member]\\n\"\n"
|
||||
".ascii \" return generator()\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedFoaCumulativeStatsPrinter:\\n\"\n"
|
||||
".ascii \" def __init__(self, val):\\n\"\n"
|
||||
".ascii \" self.val = val\\n\"\n"
|
||||
".ascii \" self.n = self.val[\\\"n\\\"]\\n\"\n"
|
||||
".ascii \" self.N = self.val.type.template_argument(0)\\n\"\n"
|
||||
|
||||
".ascii \" def display_hint(self):\\n\"\n"
|
||||
".ascii \" return \\\"map\\\"\\n\"\n"
|
||||
|
||||
".ascii \" def children(self):\\n\"\n"
|
||||
".ascii \" def generator():\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", \\\"count\\\"\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", self.n\\n\"\n"
|
||||
|
||||
".ascii \" sequence_stats_data = gdb.lookup_type(\\\"boost::unordered::detail::foa::sequence_stats_data\\\")\\n\"\n"
|
||||
".ascii \" data = self.val[\\\"data\\\"]\\n\"\n"
|
||||
".ascii \" arr = data.address.reinterpret_cast(sequence_stats_data.pointer())\\n\"\n"
|
||||
".ascii \" def build_string(idx):\\n\"\n"
|
||||
".ascii \" entry = arr[idx]\\n\"\n"
|
||||
".ascii \" avg = float(entry[\\\"m\\\"])\\n\"\n"
|
||||
".ascii \" var = float(entry[\\\"s\\\"] / self.n) if (self.n != 0) else 0.0\\n\"\n"
|
||||
".ascii \" dev = math.sqrt(var)\\n\"\n"
|
||||
".ascii \" return f\\\"{{avg = {avg}, var = {var}, dev = {dev}}}\\\"\\n\"\n"
|
||||
|
||||
".ascii \" if self.N > 0:\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", \\\"probe_length\\\"\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", build_string(0)\\n\"\n"
|
||||
".ascii \" if self.N > 1:\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", \\\"num_comparisons\\\"\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", build_string(1)\\n\"\n"
|
||||
|
||||
".ascii \" return generator()\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedFoaPrinter:\\n\"\n"
|
||||
".ascii \" def __init__(self, val):\\n\"\n"
|
||||
".ascii \" self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n"
|
||||
".ascii \" self.name = f\\\"{self.val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n"
|
||||
".ascii \" self.name = self.name.replace(\\\"boost::unordered::\\\", \\\"boost::\\\")\\n\"\n"
|
||||
".ascii \" self.is_map = self.name.endswith(\\\"map\\\")\\n\"\n"
|
||||
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.val[\\\"table_\\\"][\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n"
|
||||
|
||||
".ascii \" def to_string(self):\\n\"\n"
|
||||
".ascii \" size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.val[\\\"table_\\\"][\\\"size_ctrl\\\"][\\\"size\\\"])\\n\"\n"
|
||||
".ascii \" return f\\\"{self.name} with {size} elements\\\"\\n\"\n"
|
||||
|
||||
".ascii \" def display_hint(self):\\n\"\n"
|
||||
".ascii \" return \\\"map\\\"\\n\"\n"
|
||||
|
||||
".ascii \" def is_regular_layout(self, group):\\n\"\n"
|
||||
".ascii \" typename = group[\\\"m\\\"].type.strip_typedefs()\\n\"\n"
|
||||
".ascii \" array_size = typename.sizeof // typename.target().sizeof\\n\"\n"
|
||||
".ascii \" if array_size == 16:\\n\"\n"
|
||||
".ascii \" return True\\n\"\n"
|
||||
".ascii \" elif array_size == 2:\\n\"\n"
|
||||
".ascii \" return False\\n\"\n"
|
||||
|
||||
".ascii \" def match_occupied(self, group):\\n\"\n"
|
||||
".ascii \" m = group[\\\"m\\\"]\\n\"\n"
|
||||
".ascii \" at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b][\\\"n\\\"])\\n\"\n"
|
||||
|
||||
".ascii \" if self.is_regular_layout(group):\\n\"\n"
|
||||
".ascii \" bits = [1 << b for b in range(16) if at(b) == 0]\\n\"\n"
|
||||
".ascii \" return 0x7FFF & ~sum(bits)\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" xx = at(0) | at(1)\\n\"\n"
|
||||
".ascii \" yy = xx | (xx >> 32)\\n\"\n"
|
||||
".ascii \" return 0x7FFF & (yy | (yy >> 16))\\n\"\n"
|
||||
|
||||
".ascii \" def is_sentinel(self, group, pos):\\n\"\n"
|
||||
".ascii \" m = group[\\\"m\\\"]\\n\"\n"
|
||||
".ascii \" at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b][\\\"n\\\"])\\n\"\n"
|
||||
|
||||
".ascii \" N = group[\\\"N\\\"]\\n\"\n"
|
||||
".ascii \" sentinel_ = group[\\\"sentinel_\\\"]\\n\"\n"
|
||||
".ascii \" if self.is_regular_layout(group):\\n\"\n"
|
||||
".ascii \" return pos == N-1 and at(N-1) == sentinel_\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" return pos == N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0\\n\"\n"
|
||||
|
||||
".ascii \" def children(self):\\n\"\n"
|
||||
".ascii \" def generator():\\n\"\n"
|
||||
".ascii \" table = self.val[\\\"table_\\\"]\\n\"\n"
|
||||
".ascii \" groups = self.cpo.to_address(table[\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n"
|
||||
".ascii \" elements = self.cpo.to_address(table[\\\"arrays\\\"][\\\"elements_\\\"])\\n\"\n"
|
||||
|
||||
".ascii \" pc_ = groups.cast(gdb.lookup_type(\\\"unsigned char\\\").pointer())\\n\"\n"
|
||||
".ascii \" p_ = elements\\n\"\n"
|
||||
".ascii \" first_time = True\\n\"\n"
|
||||
".ascii \" mask = 0\\n\"\n"
|
||||
".ascii \" n0 = 0\\n\"\n"
|
||||
".ascii \" n = 0\\n\"\n"
|
||||
|
||||
".ascii \" count = 0\\n\"\n"
|
||||
".ascii \" while p_ != 0:\\n\"\n"
|
||||
".ascii \" # This if block mirrors the condition in the begin() call\\n\"\n"
|
||||
".ascii \" if (not first_time) or (self.match_occupied(groups.dereference()) & 1):\\n\"\n"
|
||||
".ascii \" pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(p_)\\n\"\n"
|
||||
".ascii \" value = self.cpo.to_address(pointer).dereference()\\n\"\n"
|
||||
".ascii \" if self.is_map:\\n\"\n"
|
||||
".ascii \" first = value[\\\"first\\\"]\\n\"\n"
|
||||
".ascii \" second = value[\\\"second\\\"]\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", first\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", second\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", count\\n\"\n"
|
||||
".ascii \" yield \\\"\\\", value\\n\"\n"
|
||||
".ascii \" count += 1\\n\"\n"
|
||||
".ascii \" first_time = False\\n\"\n"
|
||||
|
||||
".ascii \" n0 = pc_.cast(gdb.lookup_type(\\\"uintptr_t\\\")) % groups.dereference().type.sizeof\\n\"\n"
|
||||
".ascii \" pc_ = self.cpo.next(pc_, -n0)\\n\"\n"
|
||||
|
||||
".ascii \" mask = (self.match_occupied(pc_.cast(groups.type).dereference()) >> (n0+1)) << (n0+1)\\n\"\n"
|
||||
".ascii \" while mask == 0:\\n\"\n"
|
||||
".ascii \" pc_ = self.cpo.next(pc_, groups.dereference().type.sizeof)\\n\"\n"
|
||||
".ascii \" p_ = self.cpo.next(p_, groups.dereference()[\\\"N\\\"])\\n\"\n"
|
||||
".ascii \" mask = self.match_occupied(pc_.cast(groups.type).dereference())\\n\"\n"
|
||||
|
||||
".ascii \" n = BoostUnorderedHelpers.countr_zero(mask)\\n\"\n"
|
||||
".ascii \" if self.is_sentinel(pc_.cast(groups.type).dereference(), n):\\n\"\n"
|
||||
".ascii \" p_ = 0\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" pc_ = self.cpo.next(pc_, n)\\n\"\n"
|
||||
".ascii \" p_ = self.cpo.next(p_, n - n0)\\n\"\n"
|
||||
|
||||
".ascii \" return generator()\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedFoaIteratorPrinter:\\n\"\n"
|
||||
".ascii \" def __init__(self, val):\\n\"\n"
|
||||
".ascii \" self.val = val\\n\"\n"
|
||||
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.val[\\\"p_\\\"])\\n\"\n"
|
||||
|
||||
".ascii \" def to_string(self):\\n\"\n"
|
||||
".ascii \" if self.valid():\\n\"\n"
|
||||
".ascii \" element = self.cpo.to_address(self.val[\\\"p_\\\"])\\n\"\n"
|
||||
".ascii \" pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(element)\\n\"\n"
|
||||
".ascii \" value = self.cpo.to_address(pointer).dereference()\\n\"\n"
|
||||
".ascii \" return f\\\"iterator = {{ {value} }}\\\"\\n\"\n"
|
||||
".ascii \" else:\\n\"\n"
|
||||
".ascii \" return \\\"iterator = { end iterator }\\\"\\n\"\n"
|
||||
|
||||
".ascii \" def valid(self):\\n\"\n"
|
||||
".ascii \" return (self.cpo.to_address(self.val[\\\"p_\\\"]) != 0) and (self.cpo.to_address(self.val[\\\"pc_\\\"]) != 0)\\n\"\n"
|
||||
|
||||
".ascii \"def boost_unordered_build_pretty_printer():\\n\"\n"
|
||||
".ascii \" pp = gdb.printing.RegexpCollectionPrettyPrinter(\\\"boost_unordered\\\")\\n\"\n"
|
||||
".ascii \" add_template_printer = lambda name, printer: pp.add_printer(name, f\\\"^{name}<.*>$\\\", printer)\\n\"\n"
|
||||
".ascii \" add_concrete_printer = lambda name, printer: pp.add_printer(name, f\\\"^{name}$\\\", printer)\\n\"\n"
|
||||
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::unordered_map\\\", BoostUnorderedFcaPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::unordered_multimap\\\", BoostUnorderedFcaPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::unordered_set\\\", BoostUnorderedFcaPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::unordered_multiset\\\", BoostUnorderedFcaPrinter)\\n\"\n"
|
||||
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::detail::iterator_detail::iterator\\\", BoostUnorderedFcaIteratorPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::detail::iterator_detail::c_iterator\\\", BoostUnorderedFcaIteratorPrinter)\\n\"\n"
|
||||
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::unordered_flat_map\\\", BoostUnorderedFoaPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::unordered_flat_set\\\", BoostUnorderedFoaPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::unordered_node_map\\\", BoostUnorderedFoaPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::unordered_node_set\\\", BoostUnorderedFoaPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::concurrent_flat_map\\\", BoostUnorderedFoaPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::concurrent_flat_set\\\", BoostUnorderedFoaPrinter)\\n\"\n"
|
||||
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::detail::foa::table_iterator\\\", BoostUnorderedFoaIteratorPrinter)\\n\"\n"
|
||||
|
||||
".ascii \" add_concrete_printer(\\\"boost::unordered::detail::foa::table_core_cumulative_stats\\\", BoostUnorderedFoaTableCoreCumulativeStatsPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::detail::foa::cumulative_stats\\\", BoostUnorderedFoaCumulativeStatsPrinter)\\n\"\n"
|
||||
".ascii \" add_template_printer(\\\"boost::unordered::detail::foa::concurrent_cumulative_stats\\\", BoostUnorderedFoaCumulativeStatsPrinter)\\n\"\n"
|
||||
|
||||
".ascii \" return pp\\n\"\n"
|
||||
|
||||
".ascii \"gdb.printing.register_pretty_printer(gdb.current_objfile(), boost_unordered_build_pretty_printer())\\n\"\n"
|
||||
|
||||
|
||||
|
||||
".ascii \"# https://sourceware.org/gdb/current/onlinedocs/gdb.html/Writing-an-Xmethod.html\\n\"\n"
|
||||
".ascii \"class BoostUnorderedFoaGetStatsMethod(gdb.xmethod.XMethod):\\n\"\n"
|
||||
".ascii \" def __init__(self):\\n\"\n"
|
||||
".ascii \" gdb.xmethod.XMethod.__init__(self, \\\"get_stats\\\")\\n\"\n"
|
||||
|
||||
".ascii \" def get_worker(self, method_name):\\n\"\n"
|
||||
".ascii \" if method_name == \\\"get_stats\\\":\\n\"\n"
|
||||
".ascii \" return BoostUnorderedFoaGetStatsWorker()\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedFoaGetStatsWorker(gdb.xmethod.XMethodWorker):\\n\"\n"
|
||||
".ascii \" def get_arg_types(self):\\n\"\n"
|
||||
".ascii \" return None\\n\"\n"
|
||||
|
||||
".ascii \" def get_result_type(self, obj):\\n\"\n"
|
||||
".ascii \" return gdb.lookup_type(\\\"boost::unordered::detail::foa::table_core_cumulative_stats\\\")\\n\"\n"
|
||||
|
||||
".ascii \" def __call__(self, obj):\\n\"\n"
|
||||
".ascii \" try:\\n\"\n"
|
||||
".ascii \" return obj[\\\"table_\\\"][\\\"cstats\\\"]\\n\"\n"
|
||||
".ascii \" except gdb.error:\\n\"\n"
|
||||
".ascii \" print(\\\"Error: Binary was compiled without stats. Recompile with `BOOST_UNORDERED_ENABLE_STATS` defined.\\\")\\n\"\n"
|
||||
".ascii \" return\\n\"\n"
|
||||
|
||||
".ascii \"class BoostUnorderedFoaMatcher(gdb.xmethod.XMethodMatcher):\\n\"\n"
|
||||
".ascii \" def __init__(self):\\n\"\n"
|
||||
".ascii \" gdb.xmethod.XMethodMatcher.__init__(self, 'BoostUnorderedFoaMatcher')\\n\"\n"
|
||||
".ascii \" self.methods = [BoostUnorderedFoaGetStatsMethod()]\\n\"\n"
|
||||
|
||||
".ascii \" def match(self, class_type, method_name):\\n\"\n"
|
||||
".ascii \" template_name = f\\\"{class_type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n"
|
||||
".ascii \" regex = \\\"^boost::unordered::(unordered|concurrent)_(flat|node)_(map|set)$\\\"\\n\"\n"
|
||||
".ascii \" if not re.match(regex, template_name):\\n\"\n"
|
||||
".ascii \" return None\\n\"\n"
|
||||
|
||||
".ascii \" workers = []\\n\"\n"
|
||||
".ascii \" for method in self.methods:\\n\"\n"
|
||||
".ascii \" if method.enabled:\\n\"\n"
|
||||
".ascii \" worker = method.get_worker(method_name)\\n\"\n"
|
||||
".ascii \" if worker:\\n\"\n"
|
||||
".ascii \" workers.append(worker)\\n\"\n"
|
||||
".ascii \" return workers\\n\"\n"
|
||||
|
||||
".ascii \"gdb.xmethod.register_xmethod_matcher(None, BoostUnorderedFoaMatcher())\\n\"\n"
|
||||
|
||||
|
||||
|
||||
".ascii \"\\\"\\\"\\\" Fancy pointer support \\\"\\\"\\\"\\n\"\n"
|
||||
|
||||
".ascii \"\\\"\\\"\\\"\\n\"\n"
|
||||
".ascii \"To allow your own fancy pointer type to interact with Boost.Unordered GDB pretty-printers,\\n\"\n"
|
||||
".ascii \"create a pretty-printer for your own type with the following additional methods.\\n\"\n"
|
||||
|
||||
".ascii \"(Note, this is assuming the presence of a type alias `pointer` for the underlying\\n\"\n"
|
||||
".ascii \"raw pointer type, Substitute whichever name is applicable in your case.)\\n\"\n"
|
||||
|
||||
".ascii \"`boost_to_address(fancy_ptr)`\\n\"\n"
|
||||
".ascii \" * A static method, but `@staticmethod` is not required\\n\"\n"
|
||||
".ascii \" * Parameter `fancy_ptr` of type `gdb.Value`\\n\"\n"
|
||||
".ascii \" * Its `.type` will be your fancy pointer type\\n\"\n"
|
||||
".ascii \" * Returns a `gdb.Value` with the raw pointer equivalent to your fancy pointer\\n\"\n"
|
||||
".ascii \" * This method should be equivalent to calling `operator->()` on your fancy pointer in C++\\n\"\n"
|
||||
|
||||
".ascii \"`boost_next(raw_ptr, offset)`\\n\"\n"
|
||||
".ascii \" * Parameter `raw_ptr` of type `gdb.Value`\\n\"\n"
|
||||
".ascii \" * Its `.type` will be `pointer`\\n\"\n"
|
||||
".ascii \" * Parameter `offset`\\n\"\n"
|
||||
".ascii \" * Either has integer type, or is of type `gdb.Value` with an underlying integer\\n\"\n"
|
||||
".ascii \" * Returns a `gdb.Value` with the raw pointer equivalent to your fancy pointer, as if you did the following operations\\n\"\n"
|
||||
".ascii \" 1. Convert the incoming raw pointer to your fancy pointer\\n\"\n"
|
||||
".ascii \" 2. Use operator+= to add the offset to the fancy pointer\\n\"\n"
|
||||
".ascii \" 3. Convert back to the raw pointer\\n\"\n"
|
||||
".ascii \" * Note, you will not actually do these operations as stated. You will do equivalent lower-level operations that emulate having done the above\\n\"\n"
|
||||
".ascii \" * Ultimately, it will be as if you called `operator+()` on your fancy pointer in C++, but using only raw pointers\\n\"\n"
|
||||
|
||||
".ascii \"Example\\n\"\n"
|
||||
".ascii \"```\\n\"\n"
|
||||
".ascii \"class MyFancyPtrPrinter:\\n\"\n"
|
||||
".ascii \" ...\\n\"\n"
|
||||
|
||||
".ascii \" # Equivalent to `operator->()`\\n\"\n"
|
||||
".ascii \" def boost_to_address(fancy_ptr):\\n\"\n"
|
||||
".ascii \" ...\\n\"\n"
|
||||
".ascii \" return ...\\n\"\n"
|
||||
|
||||
".ascii \" # Equivalent to `operator+()`\\n\"\n"
|
||||
".ascii \" def boost_next(raw_ptr, offset):\\n\"\n"
|
||||
".ascii \" ...\\n\"\n"
|
||||
".ascii \" return ...\\n\"\n"
|
||||
|
||||
".ascii \" ...\\n\"\n"
|
||||
".ascii \"```\\n\"\n"
|
||||
".ascii \"\\\"\\\"\\\"\\n\"\n"
|
||||
|
||||
".byte 0\n"
|
||||
".popsection\n");
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#endif // defined(__ELF__)
|
||||
#endif // !defined(BOOST_ALL_NO_EMBEDDED_GDB_SCRIPTS)
|
||||
|
||||
#endif // !defined(BOOST_UNORDERED_UNORDERED_PRINTERS_HPP)
|
@ -42,7 +42,7 @@ path-constant BOOST_UNORDERED_TEST_DIR : . ;
|
||||
|
||||
run quick.cpp ;
|
||||
|
||||
compile natvis_tests.cpp ;
|
||||
compile debuggability/visualization_tests.cpp ;
|
||||
|
||||
compile unordered/self_include_tests_obj.cpp
|
||||
: <define>BOOST_UNORDERED_HEADER="boost/unordered_map.hpp"
|
||||
|
@ -2,19 +2,10 @@
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// This test applies to MSVC only. This is a file for manual testing.
|
||||
// Run this test and break manually at the variable called `break_here`.
|
||||
// Inspect the variables using the Visual Studio debugger to test correctness.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if !defined(BOOST_MSVC)
|
||||
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
BOOST_PRAGMA_MESSAGE("These tests are for Visual Studio only.")
|
||||
int main() {}
|
||||
|
||||
#else
|
||||
// This is a file for testing of visualizations,
|
||||
// such as Visual Studio Natvis or GDB pretty printers.
|
||||
// Run this test and break at the label called `break_here`.
|
||||
// Inspect the variables to test correctness.
|
||||
|
||||
#if 0 // Change to `#if 1` to test turning off SIMD optimizations
|
||||
#define BOOST_UNORDERED_DISABLE_SSE2
|
||||
@ -37,6 +28,7 @@ int main() {}
|
||||
#include <boost/unordered/unordered_set.hpp>
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
@ -46,59 +38,69 @@ template <class... Args> void use(Args&&...) {}
|
||||
using map_value_type = std::pair<const std::string, int>;
|
||||
using set_value_type = std::string;
|
||||
|
||||
template <class Tester> void natvis_test(Tester& tester)
|
||||
template <class Tester> void visualization_test(Tester& tester)
|
||||
{
|
||||
// clang-format off
|
||||
auto fca_map = tester.template construct_map<boost::unordered_map>();
|
||||
auto fca_multimap = tester.template construct_map<boost::unordered_multimap>();
|
||||
auto fca_set = tester.template construct_set<boost::unordered_set>();
|
||||
auto fca_multiset = tester.template construct_set<boost::unordered_multiset>();
|
||||
auto fca_map_ptr = tester.template construct_map<boost::unordered_map>();
|
||||
auto fca_multimap_ptr = tester.template construct_map<boost::unordered_multimap>();
|
||||
auto fca_set_ptr = tester.template construct_set<boost::unordered_set>();
|
||||
auto fca_multiset_ptr = tester.template construct_set<boost::unordered_multiset>();
|
||||
auto& fca_map = *fca_map_ptr;
|
||||
auto& fca_multimap = *fca_multimap_ptr;
|
||||
auto& fca_set = *fca_set_ptr;
|
||||
auto& fca_multiset = *fca_multiset_ptr;
|
||||
|
||||
auto foa_flat_map = tester.template construct_map<boost::unordered_flat_map>();
|
||||
auto foa_flat_set = tester.template construct_set<boost::unordered_flat_set>();
|
||||
auto foa_node_map = tester.template construct_map<boost::unordered_node_map>();
|
||||
auto foa_node_set = tester.template construct_set<boost::unordered_node_set>();
|
||||
auto foa_flat_map_ptr = tester.template construct_map<boost::unordered_flat_map>();
|
||||
auto foa_flat_set_ptr = tester.template construct_set<boost::unordered_flat_set>();
|
||||
auto foa_node_map_ptr = tester.template construct_map<boost::unordered_node_map>();
|
||||
auto foa_node_set_ptr = tester.template construct_set<boost::unordered_node_set>();
|
||||
auto& foa_flat_map = *foa_flat_map_ptr;
|
||||
auto& foa_flat_set = *foa_flat_set_ptr;
|
||||
auto& foa_node_map = *foa_node_map_ptr;
|
||||
auto& foa_node_set = *foa_node_set_ptr;
|
||||
|
||||
auto cfoa_flat_map = tester.template construct_map<boost::concurrent_flat_map>();
|
||||
auto cfoa_flat_set = tester.template construct_set<boost::concurrent_flat_set>();
|
||||
auto cfoa_flat_map_ptr = tester.template construct_map<boost::concurrent_flat_map>();
|
||||
auto cfoa_flat_set_ptr = tester.template construct_set<boost::concurrent_flat_set>();
|
||||
auto& cfoa_flat_map = *cfoa_flat_map_ptr;
|
||||
auto& cfoa_flat_set = *cfoa_flat_set_ptr;
|
||||
// clang-format on
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
const auto str = std::to_string(i * 2);
|
||||
const auto num = i * 11;
|
||||
|
||||
fca_map->emplace(str, num);
|
||||
fca_multimap->emplace(str, num);
|
||||
fca_multimap->emplace(str, num + 1);
|
||||
foa_flat_map->emplace(str, num);
|
||||
foa_node_map->emplace(str, num);
|
||||
cfoa_flat_map->emplace(str, num);
|
||||
fca_map.emplace(str, num);
|
||||
fca_multimap.emplace(str, num);
|
||||
fca_multimap.emplace(str, num + 1);
|
||||
foa_flat_map.emplace(str, num);
|
||||
foa_node_map.emplace(str, num);
|
||||
cfoa_flat_map.emplace(str, num);
|
||||
|
||||
fca_set->emplace(str);
|
||||
fca_multiset->emplace(str);
|
||||
fca_multiset->emplace(str);
|
||||
foa_flat_set->emplace(str);
|
||||
foa_node_set->emplace(str);
|
||||
cfoa_flat_set->emplace(str);
|
||||
fca_set.emplace(str);
|
||||
fca_multiset.emplace(str);
|
||||
fca_multiset.emplace(str);
|
||||
foa_flat_set.emplace(str);
|
||||
foa_node_set.emplace(str);
|
||||
cfoa_flat_set.emplace(str);
|
||||
}
|
||||
|
||||
auto fca_map_begin = fca_map->begin();
|
||||
auto fca_map_end = fca_map->end();
|
||||
auto fca_multimap_begin = fca_multimap->begin();
|
||||
auto fca_multimap_end = fca_multimap->end();
|
||||
auto fca_set_begin = fca_set->begin();
|
||||
auto fca_set_end = fca_set->end();
|
||||
auto fca_multiset_begin = fca_multiset->begin();
|
||||
auto fca_multiset_end = fca_multiset->end();
|
||||
auto fca_map_begin = fca_map.begin();
|
||||
auto fca_map_end = fca_map.end();
|
||||
auto fca_multimap_begin = fca_multimap.begin();
|
||||
auto fca_multimap_end = fca_multimap.end();
|
||||
auto fca_set_begin = fca_set.begin();
|
||||
auto fca_set_end = fca_set.end();
|
||||
auto fca_multiset_begin = fca_multiset.begin();
|
||||
auto fca_multiset_end = fca_multiset.end();
|
||||
|
||||
auto foa_flat_map_begin = foa_flat_map->begin();
|
||||
auto foa_flat_map_end = foa_flat_map->end();
|
||||
auto foa_flat_set_begin = foa_flat_set->begin();
|
||||
auto foa_flat_set_end = foa_flat_set->end();
|
||||
auto foa_node_map_begin = foa_node_map->begin();
|
||||
auto foa_node_map_end = foa_node_map->end();
|
||||
auto foa_node_set_begin = foa_node_set->begin();
|
||||
auto foa_node_set_end = foa_node_set->end();
|
||||
auto foa_flat_map_begin = foa_flat_map.begin();
|
||||
auto foa_flat_map_end = foa_flat_map.end();
|
||||
auto foa_flat_set_begin = foa_flat_set.begin();
|
||||
auto foa_flat_set_end = foa_flat_set.end();
|
||||
auto foa_node_map_begin = foa_node_map.begin();
|
||||
auto foa_node_map_end = foa_node_map.end();
|
||||
auto foa_node_set_begin = foa_node_set.begin();
|
||||
auto foa_node_set_end = foa_node_set.end();
|
||||
|
||||
use(cfoa_flat_map, cfoa_flat_set);
|
||||
use(fca_map_begin, fca_map_end, fca_multimap_begin, fca_multimap_end,
|
||||
@ -107,8 +109,8 @@ template <class Tester> void natvis_test(Tester& tester)
|
||||
foa_flat_set_end, foa_node_map_begin, foa_node_map_end, foa_node_set_begin,
|
||||
foa_node_set_end);
|
||||
|
||||
int break_here = 0;
|
||||
use(break_here);
|
||||
goto break_here;
|
||||
break_here:;
|
||||
}
|
||||
|
||||
class offset_ptr_tester_
|
||||
@ -169,21 +171,21 @@ public:
|
||||
template <template <class...> class MapTemplate>
|
||||
std::unique_ptr<map_type<MapTemplate> > construct_map()
|
||||
{
|
||||
return std::make_unique<map_type<MapTemplate> >();
|
||||
using type = map_type<MapTemplate>;
|
||||
return std::unique_ptr<type>(new type());
|
||||
}
|
||||
template <template <class...> class SetTemplate>
|
||||
std::unique_ptr<set_type<SetTemplate> > construct_set()
|
||||
{
|
||||
return std::make_unique<set_type<SetTemplate> >();
|
||||
using type = set_type<SetTemplate>;
|
||||
return std::unique_ptr<type>(new type());
|
||||
}
|
||||
} default_tester;
|
||||
|
||||
int main()
|
||||
{
|
||||
natvis_test(default_tester);
|
||||
natvis_test(offset_ptr_tester);
|
||||
visualization_test(default_tester);
|
||||
visualization_test(offset_ptr_tester);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
#endif // !defined(BOOST_MSVC)
|
Reference in New Issue
Block a user