mirror of
https://github.com/boostorg/unordered.git
synced 2025-06-25 03:41:33 +02:00
* added concurrent node containers * removed spurious typename * added missing includes * avoided unused param warning * worked around Clang bug * s/{}/() to work around GCC4.8 problems with aggregate initialization * used /bigobj for cfoa/visit_tests.cpp * suppressed localized maybe-uninitialized warnings * fixed comments * added /bigobj to cfoa/insert_tests.cpp * instrumented double exact comparison to spot a spurious error * fixed pedantic error * refactored byte_span machinery * compromised on sub-epsilon equality for doubles that should be identical * documented boost::concurrent_node_(map|set) * added concurrent_node_set * added missing AlternativeType * tested empty node insertion * tested node_handle allocator management * added nonassignable_allocator and node_handle_allocator_swap_tests * fixed warning disabling * silenced spurious GCC warning * broadened scope of previous pragma * broadened even more * worked around spurious constexpr-related msvc-14.0 bug https://godbolt.org/z/v78545Ebf * added workaround back * replaced previous workaround with built-in one * added workaround back on top of built-in solution (which doesn't work 100% of the time)
510 lines
28 KiB
XML
510 lines
28 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!--
|
|
Copyright 2024 Braden Ganetsky.
|
|
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)
|
|
-->
|
|
|
|
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
|
|
|
<!-- FCA containers -->
|
|
|
|
<Type Name="boost::unordered::detail::functions<*>" Inheritable="false">
|
|
<Intrinsic Name="active_idx" Expression="current_ & 1" />
|
|
<Intrinsic Name="spare_idx" Expression="1 - active_idx()" />
|
|
<Intrinsic Name="has_spare" Expression="(current_ & 2) != 0" />
|
|
|
|
<Intrinsic Name="hash" Expression="*reinterpret_cast<$T1*>(static_cast<function_pair::base1*>(&funcs_[idx].t_))">
|
|
<Parameter Name="idx" Type="size_t" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="key_eq" Expression="*reinterpret_cast<$T2*>(static_cast<function_pair::base2*>(&funcs_[idx].t_))">
|
|
<Parameter Name="idx" Type="size_t" />
|
|
</Intrinsic>
|
|
|
|
<Expand>
|
|
<Item Name="[hash_function]">hash(active_idx())</Item>
|
|
<Item Name="[key_eq]">key_eq(active_idx())</Item>
|
|
<Item Name="[spare_hash_function]" Condition="has_spare()">hash(spare_idx())</Item>
|
|
<Item Name="[spare_key_eq]" Condition="has_spare()">key_eq(spare_idx())</Item>
|
|
</Expand>
|
|
</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="to_address(&buckets)" />
|
|
<Variable Name="node" InitialValue="to_address(&current_bucket->next)" />
|
|
<Loop Condition="bucket_index != size">
|
|
<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 = to_address(&node->next)</Exec>
|
|
</Loop>
|
|
<Exec>++bucket_index</Exec>
|
|
</Loop>
|
|
</CustomListItems>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::detail::grouped_bucket_array<*>" Inheritable="false" IncludeView="MapHelper">
|
|
<Expand>
|
|
<CustomListItems MaxItemsPerView="100">
|
|
<Variable Name="size" InitialValue="size_" />
|
|
<Variable Name="bucket_index" InitialValue="0" />
|
|
<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 = 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 = to_address(&node->next)</Exec>
|
|
</Loop>
|
|
<Exec>++bucket_index</Exec>
|
|
</Loop>
|
|
</CustomListItems>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::unordered_map<*>" Priority="Medium">
|
|
<AlternativeType Name="boost::unordered::unordered_multimap<*>" />
|
|
<AlternativeType Name="boost::unordered::unordered_set<*>" />
|
|
<AlternativeType Name="boost::unordered::unordered_multiset<*>" />
|
|
<DisplayString>{{ size={table_.size_} }}</DisplayString>
|
|
<Expand>
|
|
<Item Name="[bucket_count]" IncludeView="detailed">table_.buckets_.size_</Item>
|
|
<Item Name="[max_load_factor]" IncludeView="detailed">table_.mlf_</Item>
|
|
<ExpandedItem ExcludeView="simple">*reinterpret_cast<table::functions*>(&table_)</ExpandedItem>
|
|
<Item Name="[allocator]" ExcludeView="simple">*reinterpret_cast<table::bucket_array_type::node_allocator_type*>(&table_.buckets_)</Item>
|
|
<ExpandedItem>table_.buckets_</ExpandedItem>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::unordered_map<*>" Priority="MediumHigh" ExcludeView="ShowElementsByIndex">
|
|
<AlternativeType Name="boost::unordered::unordered_multimap<*>" />
|
|
<DisplayString>{{ size={table_.size_} }}</DisplayString>
|
|
<Expand>
|
|
<Item Name="[bucket_count]" IncludeView="detailed">table_.buckets_.size_</Item>
|
|
<Item Name="[max_load_factor]" IncludeView="detailed">table_.mlf_</Item>
|
|
<ExpandedItem ExcludeView="simple">*reinterpret_cast<table::functions*>(&table_)</ExpandedItem>
|
|
<Item Name="[allocator]" ExcludeView="simple">*reinterpret_cast<table::bucket_array_type::node_allocator_type*>(&table_.buckets_)</Item>
|
|
<ExpandedItem>table_.buckets_,view(MapHelper)</ExpandedItem>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<!-- FCA iterators -->
|
|
|
|
<Type Name="boost::unordered::detail::iterator_detail::iterator<*>" Inheritable="false">
|
|
<AlternativeType Name="boost::unordered::detail::iterator_detail::c_iterator<*>" />
|
|
<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()">to_address(&p)->buf.t_</ExpandedItem>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<!-- FOA and CFOA helpers -->
|
|
|
|
<Type Name="boost::unordered::detail::foa::element_type<*>" Priority="Medium" Inheritable="false">
|
|
<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>*get()</ExpandedItem>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::detail::foa::plain_integral<*>" Inheritable="false">
|
|
<Intrinsic Name="get" Expression="n" />
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::detail::foa::atomic_integral<*>" Inheritable="false">
|
|
<Intrinsic Name="get" Expression="n._Storage._Value" />
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::detail::foa::group15<*>" Inheritable="false">
|
|
<Intrinsic Name="check_bit" Expression="(m[b].get() == 0) ? (1 << b) : 0">
|
|
<Parameter Name="b" Type="int" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="__match_occupied_regular_layout_true" Expression="0x7FFF & ~(
|
|
check_bit( 0) + check_bit( 1) + check_bit( 2) + check_bit( 3) +
|
|
check_bit( 4) + check_bit( 5) + check_bit( 6) + check_bit( 7) +
|
|
check_bit( 8) + check_bit( 9) + check_bit(10) + check_bit(11) +
|
|
check_bit(12) + check_bit(13) + check_bit(14) + check_bit(15)
|
|
)" />
|
|
<Intrinsic Name="__match_occupied_x" Expression="m[0].get() | m[1].get()" />
|
|
<Intrinsic Name="__match_occupied_y" Expression="static_cast<uint32_t>(__match_occupied_x() | (__match_occupied_x() >> 32))" />
|
|
<Intrinsic Name="__match_occupied_regular_layout_false" Expression="0x7FFF & (__match_occupied_y() | (__match_occupied_y() >> 16))" />
|
|
<Intrinsic Name="match_occupied" Expression="regular_layout ? __match_occupied_regular_layout_true() : __match_occupied_regular_layout_false()" />
|
|
|
|
<Intrinsic Name="__is_sentinel_regular_layout_true" Expression="pos == N-1 && m[N-1].get() == sentinel_" >
|
|
<Parameter Name="pos" Type="size_t" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="__is_sentinel_regular_layout_false" Expression="pos == N-1 && (m[0].get() & uint64_t(0x4000400040004000ull)) == uint64_t(0x4000ull) && (m[1].get() & uint64_t(0x4000400040004000ull))==0" >
|
|
<Parameter Name="pos" Type="size_t" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="is_sentinel" Expression="regular_layout ? __is_sentinel_regular_layout_true(pos) : __is_sentinel_regular_layout_false(pos)" >
|
|
<Parameter Name="pos" Type="size_t" />
|
|
</Intrinsic>
|
|
</Type>
|
|
|
|
<!-- FOA and CFOA stats -->
|
|
|
|
<Type Name="boost::unordered::detail::foa::table_core_cumulative_stats" Inheritable="false">
|
|
<DisplayString>stats</DisplayString>
|
|
<Expand>
|
|
<Item Name="[insertion]">insertion</Item>
|
|
<Item Name="[successful_lookup]">successful_lookup</Item>
|
|
<Item Name="[unsuccessful_lookup]">unsuccessful_lookup</Item>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::detail::foa::cumulative_stats<*>" Inheritable="true">
|
|
<Intrinsic Name="bit_cast_to_double" Expression="*reinterpret_cast<double*>(&i)">
|
|
<Parameter Name="i" Type="uint64_t" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="bit_cast_to_uint64_t" Expression="*reinterpret_cast<uint64_t*>(&d)">
|
|
<Parameter Name="d" Type="double" />
|
|
</Intrinsic>
|
|
|
|
<!-- https://en.wikipedia.org/wiki/Fast_inverse_square_root#Magic_number -->
|
|
<Intrinsic Name="__inv_sqrt_init" Expression="bit_cast_to_double(0x5FE6EB50C7B537A9ull - (bit_cast_to_uint64_t(x) >> 1))">
|
|
<Parameter Name="x" Type="double" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="__inv_sqrt_iter" Expression="0.5 * f * (3 - x * f * f)">
|
|
<Parameter Name="x" Type="double" />
|
|
<Parameter Name="f" Type="double" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="inv_sqrt" Expression="__inv_sqrt_iter(x, __inv_sqrt_iter(x, __inv_sqrt_iter(x, __inv_sqrt_iter(x, __inv_sqrt_init(x)))))">
|
|
<Parameter Name="x" Type="double" />
|
|
</Intrinsic>
|
|
|
|
<Intrinsic Name="average" Expression="data[idx].m">
|
|
<Parameter Name="idx" Type="size_t" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="variance" Expression="n != 0 ? data[idx].s / static_cast<double>(n) : 0.0">
|
|
<Parameter Name="idx" Type="size_t" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="deviation" Expression="variance(idx) == 0 ? 0.0 : 1/inv_sqrt(variance(idx))">
|
|
<Parameter Name="idx" Type="size_t" />
|
|
</Intrinsic>
|
|
|
|
<DisplayString>{{ count = {n} }}</DisplayString>
|
|
<Expand>
|
|
<Item Name="[count]">n</Item>
|
|
<Synthetic Name="[probe_length]" Condition="$T1 > 0">
|
|
<DisplayString>{{ average = {average(0)} }}</DisplayString>
|
|
<Expand>
|
|
<Item Name="[average]">average(0)</Item>
|
|
<Item Name="[variance]">variance(0)</Item>
|
|
<Item Name="[deviation]">deviation(0)</Item>
|
|
</Expand>
|
|
</Synthetic>
|
|
<Synthetic Name="[num_comparisons]" Condition="$T1 > 1">
|
|
<DisplayString>{{ average = {average(1)} }}</DisplayString>
|
|
<Expand>
|
|
<Item Name="[average]">average(1)</Item>
|
|
<Item Name="[variance]">variance(1)</Item>
|
|
<Item Name="[deviation]">deviation(1)</Item>
|
|
</Expand>
|
|
</Synthetic>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<!-- FOA and CFOA containers -->
|
|
|
|
<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->get()">
|
|
<Parameter Name="e" Type="element_type*" />
|
|
</Intrinsic>
|
|
|
|
<Intrinsic Name="check_bit" Expression="(n & (1 << i)) != 0">
|
|
<Parameter Name="n" Type="unsigned int" />
|
|
<Parameter Name="i" Type="unsigned int" />
|
|
</Intrinsic>
|
|
<Intrinsic Name="countr_zero" Expression="
|
|
check_bit(n, 0) ? 0 : check_bit(n, 1) ? 1 : check_bit(n, 2) ? 2 : check_bit(n, 3) ? 3 :
|
|
check_bit(n, 4) ? 4 : check_bit(n, 5) ? 5 : check_bit(n, 6) ? 6 : check_bit(n, 7) ? 7 :
|
|
check_bit(n, 8) ? 8 : check_bit(n, 9) ? 9 : check_bit(n, 10) ? 10 : check_bit(n, 11) ? 11 :
|
|
check_bit(n, 12) ? 12 : check_bit(n, 13) ? 13 : check_bit(n, 14) ? 14 : check_bit(n, 15) ? 15 :
|
|
check_bit(n, 16) ? 16 : check_bit(n, 17) ? 17 : check_bit(n, 18) ? 18 : check_bit(n, 19) ? 19 :
|
|
check_bit(n, 20) ? 20 : check_bit(n, 21) ? 21 : check_bit(n, 22) ? 22 : check_bit(n, 23) ? 23 :
|
|
check_bit(n, 24) ? 24 : check_bit(n, 25) ? 25 : check_bit(n, 26) ? 26 : check_bit(n, 27) ? 27 :
|
|
check_bit(n, 28) ? 28 : check_bit(n, 29) ? 29 : check_bit(n, 30) ? 30 : check_bit(n, 31) ? 31 : 32
|
|
">
|
|
<Parameter Name="n" Type="unsigned int" />
|
|
</Intrinsic>
|
|
|
|
<Expand>
|
|
<Item Name="[stats]" Optional="true">cstats</Item>
|
|
<CustomListItems MaxItemsPerView="100">
|
|
<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" />
|
|
<Variable Name="n" InitialValue="(unsigned int)0" />
|
|
|
|
<Loop Condition="p_ != nullptr">
|
|
|
|
<!-- This if block mirrors the condition in the begin() call -->
|
|
<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_ = 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_ = 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>
|
|
|
|
<Exec>n = countr_zero(mask)</Exec>
|
|
<If Condition="reinterpret_cast<group_type*>(pc_)->is_sentinel(n)">
|
|
<Exec>p_ = nullptr</Exec>
|
|
</If>
|
|
<Else>
|
|
<Exec>pc_ = next(pc_, (ptrdiff_t)n)</Exec>
|
|
<Exec>p_ = next(p_, (ptrdiff_t)n - (ptrdiff_t)n0)</Exec>
|
|
</Else>
|
|
|
|
</Loop>
|
|
</CustomListItems>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::detail::foa::table<*>" Inheritable="false" IncludeView="MapHelper">
|
|
<AlternativeType Name="boost::unordered::detail::foa::concurrent_table<*>" />
|
|
<Expand>
|
|
<Item Name="[stats]" Optional="true">cstats</Item>
|
|
<CustomListItems MaxItemsPerView="100">
|
|
<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" />
|
|
<Variable Name="n" InitialValue="(unsigned int)0" />
|
|
|
|
<Loop Condition="p_ != nullptr">
|
|
|
|
<!-- This if block mirrors the condition in the begin() call -->
|
|
<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_ = 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_ = 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>
|
|
|
|
<Exec>n = countr_zero(mask)</Exec>
|
|
<If Condition="reinterpret_cast<group_type*>(pc_)->is_sentinel(n)">
|
|
<Exec>p_ = nullptr</Exec>
|
|
</If>
|
|
<Else>
|
|
<Exec>pc_ = next(pc_, (ptrdiff_t)n)</Exec>
|
|
<Exec>p_ = next(p_, (ptrdiff_t)n - (ptrdiff_t)n0)</Exec>
|
|
</Else>
|
|
|
|
</Loop>
|
|
</CustomListItems>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::unordered_flat_map<*>" Priority="Medium">
|
|
<AlternativeType Name="boost::unordered::unordered_flat_set<*>" />
|
|
<AlternativeType Name="boost::unordered::unordered_node_map<*>" />
|
|
<AlternativeType Name="boost::unordered::unordered_node_set<*>" />
|
|
<AlternativeType Name="boost::unordered::concurrent_flat_map<*>" />
|
|
<AlternativeType Name="boost::unordered::concurrent_flat_set<*>" />
|
|
<AlternativeType Name="boost::unordered::concurrent_node_map<*>" />
|
|
<AlternativeType Name="boost::unordered::concurrent_node_set<*>" />
|
|
<DisplayString>{{ size={table_.size_ctrl.size} }}</DisplayString>
|
|
<Expand>
|
|
<Item Name="[hash_function]" ExcludeView="simple">*reinterpret_cast<hasher*>(static_cast<table_type::super::hash_base*>(&table_))</Item>
|
|
<Item Name="[key_eq]" ExcludeView="simple">*reinterpret_cast<key_equal*>(static_cast<table_type::super::pred_base*>(&table_))</Item>
|
|
<Item Name="[allocator]" ExcludeView="simple">*reinterpret_cast<allocator_type*>(static_cast<table_type::super::allocator_base*>(&table_))</Item>
|
|
<ExpandedItem>table_</ExpandedItem>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<Type Name="boost::unordered::unordered_flat_map<*>" Priority="MediumHigh" ExcludeView="ShowElementsByIndex">
|
|
<AlternativeType Name="boost::unordered::unordered_node_map<*>" />
|
|
<AlternativeType Name="boost::unordered::concurrent_flat_map<*>" />
|
|
<AlternativeType Name="boost::unordered::concurrent_node_map<*>" />
|
|
<DisplayString>{{ size={table_.size_ctrl.size} }}</DisplayString>
|
|
<Expand>
|
|
<Item Name="[hash_function]" ExcludeView="simple">*reinterpret_cast<hasher*>(static_cast<table_type::super::hash_base*>(&table_))</Item>
|
|
<Item Name="[key_eq]" ExcludeView="simple">*reinterpret_cast<key_equal*>(static_cast<table_type::super::pred_base*>(&table_))</Item>
|
|
<Item Name="[allocator]" ExcludeView="simple">*reinterpret_cast<allocator_type*>(static_cast<table_type::super::allocator_base*>(&table_))</Item>
|
|
<ExpandedItem>table_,view(MapHelper)</ExpandedItem>
|
|
</Expand>
|
|
</Type>
|
|
|
|
<!-- FOA iterators -->
|
|
|
|
<Type Name="boost::unordered::detail::foa::table_iterator<*>" Inheritable="false">
|
|
<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()">*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>
|