mirror of
https://github.com/boostorg/unordered.git
synced 2025-08-01 04:14:29 +02:00
Implement natvis for fancy pointers (#262)
* Add file for manual natvis testing * Equip natvis file to allow fancy pointers * Update docs * [skip ci] add links to natvis docs
This commit is contained in:
@@ -30,18 +30,50 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::unordered::detail::grouped_bucket_array<*>" Inheritable="false">
|
||||
<!--
|
||||
The expression `&**p` is used so the Intrinsic fails to parse for a fancy pointer type.
|
||||
Only one of the definitions can exist at any given time, so the other must always fail to parse, similar to SFINAE in C++.
|
||||
For a raw pointer, this expression is exactly equivalent to `*p`.
|
||||
For a fancy pointer, this expression will try to call a user-defined `operator*()`, which is not allowed in Natvis, and it will fail.
|
||||
-->
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="bucket_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="node_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="bucket_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="node_pointer*" />
|
||||
</Intrinsic>
|
||||
<!--
|
||||
The casting expression `(xyz_pointer)p` is used so the Intrinsic fails to parse for a fancy pointer type.
|
||||
Only one of the definitions can exist at any given time, so the other must always fail to parse, similar to SFINAE in C++.
|
||||
In this case, `(xyz_pointer)p` is either a no-op for a raw pointer type, or it's an invalid expression.
|
||||
-->
|
||||
<Intrinsic Name="next" Optional="true" Expression="((bucket_pointer)p) + n">
|
||||
<Parameter Name="p" Type="bucket_type*" />
|
||||
<Parameter Name="n" Type="ptrdiff_t" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="next" Optional="true" Expression="((bucket_pointer*)nullptr)->boost_next(p, n)">
|
||||
<Parameter Name="p" Type="bucket_type*" />
|
||||
<Parameter Name="n" Type="ptrdiff_t" />
|
||||
</Intrinsic>
|
||||
|
||||
<Expand>
|
||||
<CustomListItems MaxItemsPerView="100">
|
||||
<Variable Name="size" InitialValue="size_" />
|
||||
<Variable Name="bucket_index" InitialValue="0" />
|
||||
<Variable Name="current_bucket" InitialValue="&buckets[bucket_index]" />
|
||||
<Variable Name="node" InitialValue="current_bucket->next" />
|
||||
<Variable Name="current_bucket" InitialValue="to_address(&buckets)" />
|
||||
<Variable Name="node" InitialValue="to_address(&current_bucket->next)" />
|
||||
<Loop Condition="bucket_index != size">
|
||||
<Exec>current_bucket = &buckets[bucket_index]</Exec>
|
||||
<Exec>node = current_bucket->next</Exec>
|
||||
<Exec>current_bucket = next(to_address(&buckets), bucket_index)</Exec>
|
||||
<Exec>node = to_address(&current_bucket->next)</Exec>
|
||||
<Loop Condition="node != nullptr">
|
||||
<Item>node->buf.t_</Item>
|
||||
<Exec>node = node->next</Exec>
|
||||
<Exec>node = to_address(&node->next)</Exec>
|
||||
</Loop>
|
||||
<Exec>++bucket_index</Exec>
|
||||
</Loop>
|
||||
@@ -54,14 +86,14 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<CustomListItems MaxItemsPerView="100">
|
||||
<Variable Name="size" InitialValue="size_" />
|
||||
<Variable Name="bucket_index" InitialValue="0" />
|
||||
<Variable Name="current_bucket" InitialValue="&buckets[bucket_index]" />
|
||||
<Variable Name="node" InitialValue="current_bucket->next" />
|
||||
<Variable Name="current_bucket" InitialValue="to_address(&buckets)" />
|
||||
<Variable Name="node" InitialValue="to_address(&current_bucket->next)" />
|
||||
<Loop Condition="bucket_index != size">
|
||||
<Exec>current_bucket = &buckets[bucket_index]</Exec>
|
||||
<Exec>node = current_bucket->next</Exec>
|
||||
<Exec>current_bucket = next(to_address(&buckets), bucket_index)</Exec>
|
||||
<Exec>node = to_address(&current_bucket->next)</Exec>
|
||||
<Loop Condition="node != nullptr">
|
||||
<Item Name="[{node->buf.t_.first}]">node->buf.t_</Item>
|
||||
<Exec>node = node->next</Exec>
|
||||
<Exec>node = to_address(&node->next)</Exec>
|
||||
</Loop>
|
||||
<Exec>++bucket_index</Exec>
|
||||
</Loop>
|
||||
@@ -99,29 +131,46 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
<Type Name="boost::unordered::detail::iterator_detail::iterator<*>" Inheritable="false">
|
||||
<AlternativeType Name="boost::unordered::detail::iterator_detail::c_iterator<*>" />
|
||||
<Intrinsic Name="valid" Expression="p != nullptr && itb.p != nullptr && itb.pbg != nullptr" />
|
||||
<DisplayString Condition="valid()">{p->buf.t_}</DisplayString>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="node_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="bucket_iterator::bucket_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="bucket_iterator::bucket_group_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="node_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="bucket_iterator::bucket_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="bucket_iterator::bucket_group_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="valid" Expression="to_address(&p) && to_address(&itb.p) && to_address(&itb.pbg)" />
|
||||
<DisplayString Condition="valid()">{to_address(&p)->buf.t_}</DisplayString>
|
||||
<DisplayString Condition="!valid()">{{ end iterator }}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="valid()">p->buf.t_</ExpandedItem>
|
||||
<ExpandedItem Condition="valid()">to_address(&p)->buf.t_</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- FOA and CFOA helpers -->
|
||||
|
||||
<Type Name="boost::unordered::detail::foa::element_type<*>" Priority="Medium" Inheritable="false">
|
||||
<DisplayString>{*p}</DisplayString>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="get" Expression="to_address(&p)" />
|
||||
|
||||
<DisplayString>{*get()}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>*p</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="boost::unordered::detail::foa::element_type<std::pair<*>,*>" Priority="MediumHigh" Inheritable="false">
|
||||
<!-- Manually expand when holding a `std::pair`, otherwise the debugger complains about recursion-->
|
||||
<DisplayString>({p->first}, {p->second})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="first">p->first</Item>
|
||||
<Item Name="second">p->second</Item>
|
||||
<ExpandedItem>*get()</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
@@ -227,10 +276,39 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<Type Name="boost::unordered::detail::foa::table<*>" Inheritable="false">
|
||||
<AlternativeType Name="boost::unordered::detail::foa::concurrent_table<*>" />
|
||||
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="arrays_type::value_type_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="arrays_type::group_type_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="arrays_type::value_type_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="arrays_type::group_type_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="next" Optional="true" Expression="((arrays_type::value_type_pointer)p) + n">
|
||||
<Parameter Name="p" Type="arrays_type::value_type*" />
|
||||
<Parameter Name="n" Type="ptrdiff_t" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="next" Optional="true" Expression="((arrays_type::char_pointer)p) + n">
|
||||
<Parameter Name="p" Type="unsigned char*" />
|
||||
<Parameter Name="n" Type="ptrdiff_t" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="next" Optional="true" Expression="((arrays_type::value_type_pointer*)nullptr)->boost_next(p, n)">
|
||||
<Parameter Name="p" Type="arrays_type::value_type*" />
|
||||
<Parameter Name="n" Type="ptrdiff_t" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="next" Optional="true" Expression="((arrays_type::char_pointer*)nullptr)->boost_next(p, n)">
|
||||
<Parameter Name="p" Type="unsigned char*" />
|
||||
<Parameter Name="n" Type="ptrdiff_t" />
|
||||
</Intrinsic>
|
||||
|
||||
<Intrinsic Optional="true" Name="get_value" ReturnType="value_type*" Expression="e">
|
||||
<Parameter Name="e" Type="value_type*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Optional="true" Name="get_value" ReturnType="value_type*" Expression="e->p">
|
||||
<Intrinsic Optional="true" Name="get_value" ReturnType="value_type*" Expression="e->get()">
|
||||
<Parameter Name="e" Type="element_type*" />
|
||||
</Intrinsic>
|
||||
|
||||
@@ -254,8 +332,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<Expand>
|
||||
<Item Name="[stats]" Optional="true">cstats</Item>
|
||||
<CustomListItems MaxItemsPerView="100">
|
||||
<Variable Name="pc_" InitialValue="reinterpret_cast<unsigned char*>(arrays.groups_)" />
|
||||
<Variable Name="p_" InitialValue="arrays.elements_" />
|
||||
<Variable Name="pc_" InitialValue="reinterpret_cast<unsigned char*>(to_address(&arrays.groups_))" />
|
||||
<Variable Name="p_" InitialValue="to_address(&arrays.elements_)" />
|
||||
<Variable Name="first_time" InitialValue="true" />
|
||||
<Variable Name="mask" InitialValue="(int)0" />
|
||||
<Variable Name="n0" InitialValue="(size_t)0" />
|
||||
@@ -264,18 +342,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<Loop Condition="p_ != nullptr">
|
||||
|
||||
<!-- This if block mirrors the condition in the begin() call -->
|
||||
<If Condition="!first_time || !(arrays.elements_ && !(arrays.groups_[0].match_occupied() & 0x1))">
|
||||
<If Condition="!first_time || !(p_ && !(to_address(&arrays.groups_)[0].match_occupied() & 0x1))">
|
||||
<Item>*p_</Item>
|
||||
</If>
|
||||
<Exec>first_time = false</Exec>
|
||||
|
||||
<Exec>n0 = reinterpret_cast<uintptr_t>(pc_) % sizeof(group_type)</Exec>
|
||||
<Exec>pc_ -= (ptrdiff_t)n0</Exec>
|
||||
<Exec>pc_ = next(pc_, -(ptrdiff_t)n0)</Exec>
|
||||
|
||||
<Exec>mask = (reinterpret_cast<group_type*>(pc_)->match_occupied() >> (n0+1)) << (n0+1)</Exec>
|
||||
<Loop Condition="mask == 0">
|
||||
<Exec>pc_ += sizeof(group_type)</Exec>
|
||||
<Exec>p_ += group_type::N</Exec>
|
||||
<Exec>pc_ = next(pc_, sizeof(group_type))</Exec>
|
||||
<Exec>p_ = next(p_, group_type::N)</Exec>
|
||||
<Exec>mask = reinterpret_cast<group_type*>(pc_)->match_occupied()</Exec>
|
||||
</Loop>
|
||||
|
||||
@@ -284,9 +362,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<Exec>p_ = nullptr</Exec>
|
||||
</If>
|
||||
<Else>
|
||||
<Exec>pc_ += (ptrdiff_t)n</Exec>
|
||||
<Exec>p_ -= (ptrdiff_t)n0</Exec>
|
||||
<Exec>p_ += (ptrdiff_t)n</Exec>
|
||||
<Exec>pc_ = next(pc_, (ptrdiff_t)n)</Exec>
|
||||
<Exec>p_ = next(p_, (ptrdiff_t)n - (ptrdiff_t)n0)</Exec>
|
||||
</Else>
|
||||
|
||||
</Loop>
|
||||
@@ -299,8 +376,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<Expand>
|
||||
<Item Name="[stats]" Optional="true">cstats</Item>
|
||||
<CustomListItems MaxItemsPerView="100">
|
||||
<Variable Name="pc_" InitialValue="reinterpret_cast<unsigned char*>(arrays.groups_)" />
|
||||
<Variable Name="p_" InitialValue="arrays.elements_" />
|
||||
<Variable Name="pc_" InitialValue="reinterpret_cast<unsigned char*>(to_address(&arrays.groups_))" />
|
||||
<Variable Name="p_" InitialValue="to_address(&arrays.elements_)" />
|
||||
<Variable Name="first_time" InitialValue="true" />
|
||||
<Variable Name="mask" InitialValue="(int)0" />
|
||||
<Variable Name="n0" InitialValue="(size_t)0" />
|
||||
@@ -309,18 +386,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<Loop Condition="p_ != nullptr">
|
||||
|
||||
<!-- This if block mirrors the condition in the begin() call -->
|
||||
<If Condition="!first_time || !(arrays.elements_ && !(arrays.groups_[0].match_occupied() & 0x1))">
|
||||
<If Condition="!first_time || !(p_ && !(to_address(&arrays.groups_)[0].match_occupied() & 0x1))">
|
||||
<Item Name="[{get_value(p_)->first}]">*p_</Item>
|
||||
</If>
|
||||
<Exec>first_time = false</Exec>
|
||||
|
||||
<Exec>n0 = reinterpret_cast<uintptr_t>(pc_) % sizeof(group_type)</Exec>
|
||||
<Exec>pc_ -= (ptrdiff_t)n0</Exec>
|
||||
<Exec>pc_ = next(pc_, -(ptrdiff_t)n0)</Exec>
|
||||
|
||||
<Exec>mask = (reinterpret_cast<group_type*>(pc_)->match_occupied() >> (n0+1)) << (n0+1)</Exec>
|
||||
<Loop Condition="mask == 0">
|
||||
<Exec>pc_ += sizeof(group_type)</Exec>
|
||||
<Exec>p_ += group_type::N</Exec>
|
||||
<Exec>pc_ = next(pc_, sizeof(group_type))</Exec>
|
||||
<Exec>p_ = next(p_, group_type::N)</Exec>
|
||||
<Exec>mask = reinterpret_cast<group_type*>(pc_)->match_occupied()</Exec>
|
||||
</Loop>
|
||||
|
||||
@@ -329,9 +406,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<Exec>p_ = nullptr</Exec>
|
||||
</If>
|
||||
<Else>
|
||||
<Exec>pc_ += (ptrdiff_t)n</Exec>
|
||||
<Exec>p_ -= (ptrdiff_t)n0</Exec>
|
||||
<Exec>p_ += (ptrdiff_t)n</Exec>
|
||||
<Exec>pc_ = next(pc_, (ptrdiff_t)n)</Exec>
|
||||
<Exec>p_ = next(p_, (ptrdiff_t)n - (ptrdiff_t)n0)</Exec>
|
||||
</Else>
|
||||
|
||||
</Loop>
|
||||
@@ -369,12 +445,62 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<!-- FOA iterators -->
|
||||
|
||||
<Type Name="boost::unordered::detail::foa::table_iterator<*>" Inheritable="false">
|
||||
<Intrinsic Name="valid" Expression="p_ != nullptr && pc_ != nullptr" />
|
||||
<DisplayString Condition="valid()">{*p_}</DisplayString>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="table_element_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="table_element_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="&**p">
|
||||
<Parameter Name="p" Type="char_pointer*" />
|
||||
</Intrinsic>
|
||||
<Intrinsic Name="to_address" Optional="true" Expression="p->boost_to_address()">
|
||||
<Parameter Name="p" Type="char_pointer*" />
|
||||
</Intrinsic>
|
||||
|
||||
<Intrinsic Name="valid" Expression="to_address(&p_) != nullptr && to_address(&pc_) != nullptr" />
|
||||
<DisplayString Condition="valid()">{*to_address(&p_)}</DisplayString>
|
||||
<DisplayString Condition="!valid()">{{ end iterator }}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="valid()">*p_</ExpandedItem>
|
||||
<ExpandedItem Condition="valid()">*to_address(&p_)</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<!-- Fancy pointer support -->
|
||||
|
||||
<!--
|
||||
To allow your own fancy pointer type to interact with Boost.Unordered Natvis,
|
||||
add the following intrinsics to your type, with the following conditions.
|
||||
|
||||
(Note, this is assuming the presence of a type alias `pointer` for the underlying
|
||||
raw pointer type, and a type alias `difference_type` for your fancy pointer
|
||||
difference type. Substitute whichever names are applicable in your case.)
|
||||
|
||||
`boost_to_address`
|
||||
* Takes no parameters
|
||||
* Returns the raw pointer equivalent to your fancy pointer
|
||||
|
||||
`boost_next`
|
||||
* Parameter 1, an underlying raw pointer of type `pointer`
|
||||
* Parameter 2, an offset of type `difference_type`
|
||||
* Returns 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.
|
||||
|
||||
Example
|
||||
```
|
||||
<Type Name="my_fancy_ptr<*>">
|
||||
...
|
||||
<Intrinsic Name="boost_to_address" ReturnType="pointer" Expression="..." />
|
||||
<Intrinsic Name="boost_next" ReturnType="pointer" Expression="...">
|
||||
<Parameter Name="ptr" Type="pointer" />
|
||||
<Parameter Name="offset" Type="difference_type" />
|
||||
</Intrinsic>
|
||||
...
|
||||
</Type>
|
||||
```
|
||||
-->
|
||||
|
||||
</AutoVisualizer>
|
||||
|
Reference in New Issue
Block a user