Я хотел бы написать визуализатор natvis для двусвязного списка. В списке не хранится узел счетчика, и простой способ работает не очень хорошо, так как расширение никогда не останавливается (следующий никогда не равен нулю, последний элемент списка указывает на корень списка).
<Type Name="TListBidir<*>">
<Expand>
<LinkedListItems>
<HeadPointer>next</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>($T1 *)this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
Я надеялся, что смогу добавить атрибут Condition для NextPointer, сравнивая его с заголовком списка, но, поскольку NextPoint оценивается в контексте узла, я не знаю, с чем его сравнивать:
<NextPointer Condition="next!=XXXXXXXXX">next</NextPointer>
Вот как это выглядело с предыдущими (2010 г.) визуализаторами, использующими директиву skip, как #list обрабатывал это автоматически:
#list
защищен от бесконечных обходов и изящно справляется с циклическим списком. Кроме того, вы можете использовать выражениеskip:
для обозначения контрольного узла, о котором не следует сообщать. Хотя название подразумевает, что узел будет пропущен, на самом деле это приводит к остановке обхода, поэтому, если ваш дозорный узел находится первым, вы должны начать обход после него.
TListBidir<*,*,*>{
children
(
#list(
head: ((($T2 *)&$c)->next),
next: next,
skip : &($c)
): (($T1 *)(&$e))
)
}
Как я могу объяснить в natvis отладчику, что он должен прекратить расширять список, как только он снова достигнет корневого элемента?