mirror of
https://github.com/boostorg/container.git
synced 2026-07-05 22:10:45 +02:00
165 lines
5.6 KiB
Python
165 lines
5.6 KiB
Python
|
|
# Copyright 2026 Joaquin M Lopez Munoz.
|
||
|
|
# Distributed under the Boost Software License, Version 1.0.
|
||
|
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||
|
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||
|
|
|
||
|
|
import gdb.printing
|
||
|
|
import gdb.xmethod
|
||
|
|
|
||
|
|
class BoostContainerHubHelpers:
|
||
|
|
def countr_zero(n):
|
||
|
|
for i in range(64):
|
||
|
|
if (n & (1 << i)) != 0: return i
|
||
|
|
return 64
|
||
|
|
|
||
|
|
def popcount(n):
|
||
|
|
c = 0
|
||
|
|
while n:
|
||
|
|
c += 1
|
||
|
|
n &= n - 1
|
||
|
|
return c
|
||
|
|
|
||
|
|
# Fancy pointer support: fancy pointer's visualizer is assumed to provide
|
||
|
|
# a static boost_to_address(fancy_ptr) method returning a gdb.Value with the
|
||
|
|
# equivalent raw pointer.
|
||
|
|
|
||
|
|
def to_address(ptr):
|
||
|
|
if ptr.type.strip_typedefs().code == gdb.TYPE_CODE_PTR: # strip_typedefs() needed for some unknown reason
|
||
|
|
return ptr
|
||
|
|
try:
|
||
|
|
return type(gdb.default_visualizer(ptr)).boost_to_address(ptr)
|
||
|
|
except AttributeError:
|
||
|
|
raise gdb.error(
|
||
|
|
f"{ptr.type.strip_typedefs().name}'s visualizer must have a static boost_to_address(ptr) method "
|
||
|
|
"for proper visualization")
|
||
|
|
|
||
|
|
class BoostContainerHubProxy:
|
||
|
|
def __init__(self, val):
|
||
|
|
self.N = 64
|
||
|
|
self.blist = val["blist"]
|
||
|
|
self.num_blocks = int(val["num_blocks"])
|
||
|
|
self.size_ = int(val["size_"])
|
||
|
|
# block_list derives from block
|
||
|
|
self.block_type = next(f for f in self.blist.type.fields() if f.is_base_class).type
|
||
|
|
|
||
|
|
def __iter__(self):
|
||
|
|
pbb = BoostContainerHubHelpers.to_address(self.blist["next"])
|
||
|
|
mask = int(pbb.dereference()["mask"])
|
||
|
|
count = 0
|
||
|
|
while count != self.size_:
|
||
|
|
n = BoostContainerHubHelpers.countr_zero(mask)
|
||
|
|
pb = pbb.cast(self.block_type.pointer())
|
||
|
|
pd = BoostContainerHubHelpers.to_address(pb.dereference()["data_"])
|
||
|
|
yield (pd + n).dereference()
|
||
|
|
mask &= mask - 1
|
||
|
|
if mask == 0:
|
||
|
|
pbb = BoostContainerHubHelpers.to_address(pbb.dereference()["next"])
|
||
|
|
mask = int(pbb.dereference()["mask"])
|
||
|
|
count += 1
|
||
|
|
|
||
|
|
def __getitem__(self, n):
|
||
|
|
if self.size_ == 0:
|
||
|
|
raise IndexError("Container is empty")
|
||
|
|
elif n < 0 or n >= self.size_:
|
||
|
|
raise IndexError("Out of bounds")
|
||
|
|
pbb = BoostContainerHubHelpers.to_address(self.blist["next"])
|
||
|
|
while True:
|
||
|
|
m = BoostContainerHubHelpers.popcount(int(pbb.dereference()["mask"]))
|
||
|
|
if m <= n:
|
||
|
|
n -= m
|
||
|
|
pbb = BoostContainerHubHelpers.to_address(pbb.dereference()["next"])
|
||
|
|
else:
|
||
|
|
break
|
||
|
|
mask = int(pbb.dereference()["mask"])
|
||
|
|
pb = pbb.cast(self.block_type.pointer())
|
||
|
|
pd = BoostContainerHubHelpers.to_address(pb.dereference()["data_"])
|
||
|
|
while n:
|
||
|
|
mask &= mask - 1
|
||
|
|
n -= 1
|
||
|
|
pb = pbb.cast(self.block_type.pointer())
|
||
|
|
pd = BoostContainerHubHelpers.to_address(pb.dereference()["data_"])
|
||
|
|
return (pd + BoostContainerHubHelpers.countr_zero(mask)).dereference()
|
||
|
|
|
||
|
|
class BoostContainerHubPrinter:
|
||
|
|
def __init__(self, val):
|
||
|
|
self.hub = BoostContainerHubProxy(val)
|
||
|
|
|
||
|
|
def to_string(self):
|
||
|
|
return f"boost::container::hub with {{size = {self.hub.size_}, capacity = {self.hub.num_blocks * self.hub.N}}}"
|
||
|
|
|
||
|
|
def display_hint(self):
|
||
|
|
return "array"
|
||
|
|
|
||
|
|
def children(self):
|
||
|
|
for count, v in enumerate(self.hub):
|
||
|
|
yield f"[{count}]", v
|
||
|
|
|
||
|
|
class BoostContainerHubIteratorPrinter:
|
||
|
|
def __init__(self, val):
|
||
|
|
# TODO: ::block typedef may have been stripped away by compiler
|
||
|
|
block_type = gdb.lookup_type(f"{val.type.strip_typedefs().name}::block")
|
||
|
|
self.pb = BoostContainerHubHelpers.to_address(val["pbb"]).cast(block_type.pointer())
|
||
|
|
if self.pb != 0:
|
||
|
|
self.px = BoostContainerHubHelpers.to_address(self.pb.dereference()["data_"]) + int(val["n"])
|
||
|
|
|
||
|
|
def to_string(self):
|
||
|
|
if self.pb == 0:
|
||
|
|
return "iterator = { invalid }"
|
||
|
|
elif self.px == 0:
|
||
|
|
return "iterator = { end iterator }"
|
||
|
|
else:
|
||
|
|
return f"iterator = {{ {self.px.dereference()} }}"
|
||
|
|
|
||
|
|
def boost_container_hub_build_pretty_printers():
|
||
|
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("boost_container_hub")
|
||
|
|
add_template_printer = lambda name, printer: pp.add_printer(name, f"^{name}<.*>$", printer)
|
||
|
|
|
||
|
|
add_template_printer("boost::container::hub", BoostContainerHubPrinter)
|
||
|
|
add_template_printer("boost::container::hub_detail::iterator", BoostContainerHubIteratorPrinter)
|
||
|
|
|
||
|
|
return pp
|
||
|
|
|
||
|
|
gdb.printing.register_pretty_printer(gdb.current_objfile(), boost_container_hub_build_pretty_printers())
|
||
|
|
|
||
|
|
# https://sourceware.org/gdb/current/onlinedocs/gdb.html/Writing-an-Xmethod.html
|
||
|
|
|
||
|
|
class BoostContainerHubSubscriptMethod(gdb.xmethod.XMethod):
|
||
|
|
def __init__(self):
|
||
|
|
gdb.xmethod.XMethod.__init__(self, "subscript")
|
||
|
|
|
||
|
|
def get_worker(self, class_type, method_name):
|
||
|
|
if method_name == "operator[]":
|
||
|
|
return BoostContainerHubSubscriptWorker(class_type.template_argument(0))
|
||
|
|
|
||
|
|
class BoostContainerHubSubscriptWorker(gdb.xmethod.XMethodWorker):
|
||
|
|
def __init__(self, value_type):
|
||
|
|
self.value_type = value_type
|
||
|
|
|
||
|
|
def get_arg_types(self):
|
||
|
|
return [gdb.lookup_type("std::size_t")]
|
||
|
|
|
||
|
|
def get_result_type(self, obj):
|
||
|
|
return self.value_type.reference()
|
||
|
|
|
||
|
|
def __call__(self, obj, index):
|
||
|
|
return BoostContainerHubProxy(obj)[index]
|
||
|
|
|
||
|
|
class BoostContainerHubMatcher(gdb.xmethod.XMethodMatcher):
|
||
|
|
def __init__(self):
|
||
|
|
gdb.xmethod.XMethodMatcher.__init__(self, "BoostContainerHubMatcher")
|
||
|
|
self.methods = [BoostContainerHubSubscriptMethod()]
|
||
|
|
|
||
|
|
def match(self, class_type, method_name):
|
||
|
|
if not class_type.tag.startswith("boost::container::hub<"):
|
||
|
|
return None
|
||
|
|
|
||
|
|
workers = []
|
||
|
|
for method in self.methods:
|
||
|
|
if method.enabled:
|
||
|
|
worker = method.get_worker(class_type, method_name)
|
||
|
|
if worker:
|
||
|
|
workers.append(worker)
|
||
|
|
return workers
|
||
|
|
|
||
|
|
gdb.xmethod.register_xmethod_matcher(None, BoostContainerHubMatcher())
|