Compare commits
11 Commits
02ac817616
...
86752d9dc8
Author | SHA1 | Date | |
---|---|---|---|
|
86752d9dc8 | ||
|
d3cb9d638d | ||
|
a931a75c4f | ||
|
76e71478a8 | ||
|
d7b3e4267a | ||
|
fff7ef4728 | ||
|
2a45dc29a0 | ||
|
c21e684001 | ||
|
7a1f795198 | ||
|
b5de7dad8a | ||
|
847f195808 |
@ -0,0 +1,138 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
SPDX-FileCopyrightText: Rory O'Kane at Wikimedia Commons
|
||||
<https://commons.wikimedia.org/wiki/File:Sorted_binary_tree_breadth-first_traversal.svg>
|
||||
SPDX-FileCopyrightText: 2024 Frank Dana
|
||||
-->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="266px" height="212px" viewBox="0 0 266 212" enable-background="new 0 0 266 212" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" x1="27.23" y1="23.192" x2="29.23" y2="23.192"/>
|
||||
|
||||
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9562,3.9562" x1="33.187" y1="23.192" x2="236.932" y2="23.192"/>
|
||||
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="238.91,23.192 240.91,23.192
|
||||
238.97,23.677 "/>
|
||||
|
||||
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="24.646" x2="27.971" y2="76.427"/>
|
||||
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="26.035,76.912 24.095,77.396
|
||||
26.095,77.396 "/>
|
||||
|
||||
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="77.396" x2="236.902" y2="77.396"/>
|
||||
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="238.91,77.396 240.91,77.396
|
||||
238.97,77.881 "/>
|
||||
|
||||
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="78.85" x2="27.971" y2="130.631"/>
|
||||
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="26.035,131.114 24.095,131.6
|
||||
26.095,131.6 "/>
|
||||
|
||||
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="131.6" x2="236.902" y2="131.6"/>
|
||||
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="238.91,131.6 240.91,131.6
|
||||
238.97,132.085 "/>
|
||||
|
||||
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="133.053" x2="27.971" y2="184.835"/>
|
||||
<polyline fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" points="26.035,185.318 24.095,185.804
|
||||
26.095,185.804 "/>
|
||||
|
||||
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0086,4.0086" x1="30.104" y1="185.804" x2="228.53" y2="185.804"/>
|
||||
|
||||
<line fill="none" stroke="#90c2ff" stroke-width="2" stroke-miterlimit="10" x1="230.534" y1="185.804" x2="232.534" y2="185.804"/>
|
||||
<g>
|
||||
<rect fill="#90c2ff" x="24.095" y="19.892" width="6.602" height="6.602"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#90c2ff" d="M238.569,185.804c-2.84,1.054-6.363,2.852-8.548,4.756l1.721-4.756l-1.721-4.755
|
||||
C232.206,182.953,235.729,184.751,238.569,185.804z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="graph0">
|
||||
<title>sorted_binary_tree</title>
|
||||
<g id="node1">
|
||||
<title>C</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="60.23" cy="185.804" rx="18.067" ry="18.067"/>
|
||||
<text transform="matrix(1 0 0 1 55.5435 190.8223)" font-family="'Times-Roman'" font-size="14.0528">C</text>
|
||||
</g>
|
||||
<g id="node2">
|
||||
<title>E</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="132.502" cy="185.804" rx="18.067" ry="18.067"/>
|
||||
<text transform="matrix(1 0 0 1 128.21 190.8223)" font-family="'Times-Roman'" font-size="14.0528">E</text>
|
||||
</g>
|
||||
<g id="node3">
|
||||
<title>H</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="204.773" cy="185.804" rx="17.064" ry="18.067"/>
|
||||
<text transform="matrix(1 0 0 1 199.6992 190.8223)" font-family="'Times-Roman'" font-size="14.0528">H</text>
|
||||
</g>
|
||||
<g id="node4">
|
||||
<title>A</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="24.094" cy="131.6" rx="17.064" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 19.02 136.6191)" font-family="'Times-Roman'" font-size="14.0528">A</text>
|
||||
</g>
|
||||
<g id="node5">
|
||||
<title>D</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="96.366" cy="131.6" rx="17.064" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 91.292 136.6191)" font-family="'Times-Roman'" font-size="14.0528">D</text>
|
||||
</g>
|
||||
<g id="edge6">
|
||||
<title>D->C</title>
|
||||
<path fill="none" stroke="#ffffff" d="M86.328,147.66c-3.011,4.016-7.026,9.034-10.038,14.053"/>
|
||||
<polygon fill="#ffffff" stroke="#ffffff" points="78.298,164.725 70.268,170.747 73.279,160.709 "/>
|
||||
</g>
|
||||
<g id="edge8">
|
||||
<title>D->E</title>
|
||||
<path fill="none" stroke="#ffffff" d="M106.404,147.66c3.011,4.016,7.026,9.034,10.038,14.053"/>
|
||||
<polygon fill="#ffffff" stroke="#ffffff" points="119.453,160.709 122.464,170.747 114.434,164.725 "/>
|
||||
</g>
|
||||
<g id="node6">
|
||||
<title>I</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="240.909" cy="131.6" rx="18.068" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 238.5693 136.6191)" font-family="'Times-Roman'" font-size="14.0528">I</text>
|
||||
</g>
|
||||
<g id="edge12">
|
||||
<title>I->H</title>
|
||||
<path fill="none" stroke="#ffffff" d="M230.871,146.656c-3.011,5.02-6.021,10.038-10.037,15.057"/>
|
||||
<polygon fill="#ffffff" stroke="#ffffff" points="223.846,163.721 214.812,169.743 217.822,159.705 "/>
|
||||
</g>
|
||||
<g id="node7">
|
||||
<title>B</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="60.23" cy="77.396" rx="18.068" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 55.5435 82.415)" font-family="'Times-Roman'" font-size="14.0528">B</text>
|
||||
</g>
|
||||
<g id="edge3">
|
||||
<title>B->A</title>
|
||||
<path fill="none" stroke="#ffffff" d="M50.192,92.453c-3.011,5.019-6.022,10.038-10.038,15.057"/>
|
||||
<polygon fill="#ffffff" stroke="#ffffff" points="43.166,109.518 34.132,115.539 37.144,105.502 "/>
|
||||
</g>
|
||||
<g id="edge5">
|
||||
<title>B->D</title>
|
||||
<path fill="none" stroke="#ffffff" d="M70.268,92.453c3.011,5.019,6.022,10.038,10.038,15.057"/>
|
||||
<polygon fill="#ffffff" stroke="#ffffff" points="83.317,105.502 86.328,115.539 77.294,109.518 "/>
|
||||
</g>
|
||||
<g id="node8">
|
||||
<title>G</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="204.773" cy="77.396" rx="17.064" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 199.6992 82.415)" font-family="'Times-Roman'" font-size="14.0528">G</text>
|
||||
</g>
|
||||
<g id="edge11">
|
||||
<title>G->I</title>
|
||||
<path fill="none" stroke="#ffffff" d="M214.812,93.457c3.011,4.015,7.026,9.034,10.038,14.053"/>
|
||||
<polygon fill="#ffffff" stroke="#ffffff" points="227.86,106.506 230.871,116.543 222.842,110.521 "/>
|
||||
</g>
|
||||
<g id="node9">
|
||||
<title>F</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#ffffff" cx="132.502" cy="23.192" rx="18.068" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 128.5942 28.2109)" font-family="'Times-Roman'" font-size="14.0528">F</text>
|
||||
</g>
|
||||
<g id="edge2">
|
||||
<title>F->B</title>
|
||||
<path fill="none" stroke="#ffffff" d="M117.445,34.234c-11.042,8.03-23.087,17.064-34.128,26.098"/>
|
||||
<polygon fill="#ffffff" stroke="#ffffff" points="85.325,63.343 75.287,66.354 81.31,57.321 "/>
|
||||
</g>
|
||||
<g id="edge10">
|
||||
<title>F->G</title>
|
||||
<path fill="none" stroke="#ffffff" d="M147.559,34.234c11.041,8.03,23.087,17.064,34.129,26.098"/>
|
||||
<polygon fill="#ffffff" stroke="#ffffff" points="183.694,57.321 189.717,66.354 179.68,63.343 "/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.2 KiB |
@ -1,134 +1,138 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="266px" height="212px" viewBox="0 0 266 212" enable-background="new 0 0 266 212" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" x1="27.23" y1="23.192" x2="29.23" y2="23.192"/>
|
||||
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9562,3.9562" x1="33.187" y1="23.192" x2="236.932" y2="23.192"/>
|
||||
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="238.91,23.192 240.91,23.192
|
||||
238.97,23.677 "/>
|
||||
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="24.646" x2="27.971" y2="76.427"/>
|
||||
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="26.035,76.912 24.095,77.396
|
||||
26.095,77.396 "/>
|
||||
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="77.396" x2="236.902" y2="77.396"/>
|
||||
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="238.91,77.396 240.91,77.396
|
||||
238.97,77.881 "/>
|
||||
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="78.85" x2="27.971" y2="130.631"/>
|
||||
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="26.035,131.114 24.095,131.6
|
||||
26.095,131.6 "/>
|
||||
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="131.6" x2="236.902" y2="131.6"/>
|
||||
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="238.91,131.6 240.91,131.6
|
||||
238.97,132.085 "/>
|
||||
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="133.053" x2="27.971" y2="184.835"/>
|
||||
<polyline fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" points="26.035,185.318 24.095,185.804
|
||||
26.095,185.804 "/>
|
||||
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0086,4.0086" x1="30.104" y1="185.804" x2="228.53" y2="185.804"/>
|
||||
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" x1="230.534" y1="185.804" x2="232.534" y2="185.804"/>
|
||||
<g>
|
||||
<rect x="24.095" y="19.892" width="6.602" height="6.602"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M238.569,185.804c-2.84,1.054-6.363,2.852-8.548,4.756l1.721-4.756l-1.721-4.755
|
||||
C232.206,182.953,235.729,184.751,238.569,185.804z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="graph0">
|
||||
<title>sorted_binary_tree</title>
|
||||
<g id="node1">
|
||||
<title>C</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="60.23" cy="185.804" rx="18.067" ry="18.067"/>
|
||||
<text transform="matrix(1 0 0 1 55.5435 190.8223)" font-family="'Times-Roman'" font-size="14.0528">C</text>
|
||||
</g>
|
||||
<g id="node2">
|
||||
<title>E</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="132.502" cy="185.804" rx="18.067" ry="18.067"/>
|
||||
<text transform="matrix(1 0 0 1 128.21 190.8223)" font-family="'Times-Roman'" font-size="14.0528">E</text>
|
||||
</g>
|
||||
<g id="node3">
|
||||
<title>H</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="204.773" cy="185.804" rx="17.064" ry="18.067"/>
|
||||
<text transform="matrix(1 0 0 1 199.6992 190.8223)" font-family="'Times-Roman'" font-size="14.0528">H</text>
|
||||
</g>
|
||||
<g id="node4">
|
||||
<title>A</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="24.094" cy="131.6" rx="17.064" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 19.02 136.6191)" font-family="'Times-Roman'" font-size="14.0528">A</text>
|
||||
</g>
|
||||
<g id="node5">
|
||||
<title>D</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="96.366" cy="131.6" rx="17.064" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 91.292 136.6191)" font-family="'Times-Roman'" font-size="14.0528">D</text>
|
||||
</g>
|
||||
<g id="edge6">
|
||||
<title>D->C</title>
|
||||
<path fill="none" stroke="#000000" d="M86.328,147.66c-3.011,4.016-7.026,9.034-10.038,14.053"/>
|
||||
<polygon stroke="#000000" points="78.298,164.725 70.268,170.747 73.279,160.709 "/>
|
||||
</g>
|
||||
<g id="edge8">
|
||||
<title>D->E</title>
|
||||
<path fill="none" stroke="#000000" d="M106.404,147.66c3.011,4.016,7.026,9.034,10.038,14.053"/>
|
||||
<polygon stroke="#000000" points="119.453,160.709 122.464,170.747 114.434,164.725 "/>
|
||||
</g>
|
||||
<g id="node6">
|
||||
<title>I</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="240.909" cy="131.6" rx="18.068" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 238.5693 136.6191)" font-family="'Times-Roman'" font-size="14.0528">I</text>
|
||||
</g>
|
||||
<g id="edge12">
|
||||
<title>I->H</title>
|
||||
<path fill="none" stroke="#000000" d="M230.871,146.656c-3.011,5.02-6.021,10.038-10.037,15.057"/>
|
||||
<polygon stroke="#000000" points="223.846,163.721 214.812,169.743 217.822,159.705 "/>
|
||||
</g>
|
||||
<g id="node7">
|
||||
<title>B</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="60.23" cy="77.396" rx="18.068" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 55.5435 82.415)" font-family="'Times-Roman'" font-size="14.0528">B</text>
|
||||
</g>
|
||||
<g id="edge3">
|
||||
<title>B->A</title>
|
||||
<path fill="none" stroke="#000000" d="M50.192,92.453c-3.011,5.019-6.022,10.038-10.038,15.057"/>
|
||||
<polygon stroke="#000000" points="43.166,109.518 34.132,115.539 37.144,105.502 "/>
|
||||
</g>
|
||||
<g id="edge5">
|
||||
<title>B->D</title>
|
||||
<path fill="none" stroke="#000000" d="M70.268,92.453c3.011,5.019,6.022,10.038,10.038,15.057"/>
|
||||
<polygon stroke="#000000" points="83.317,105.502 86.328,115.539 77.294,109.518 "/>
|
||||
</g>
|
||||
<g id="node8">
|
||||
<title>G</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="204.773" cy="77.396" rx="17.064" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 199.6992 82.415)" font-family="'Times-Roman'" font-size="14.0528">G</text>
|
||||
</g>
|
||||
<g id="edge11">
|
||||
<title>G->I</title>
|
||||
<path fill="none" stroke="#000000" d="M214.812,93.457c3.011,4.015,7.026,9.034,10.038,14.053"/>
|
||||
<polygon stroke="#000000" points="227.86,106.506 230.871,116.543 222.842,110.521 "/>
|
||||
</g>
|
||||
<g id="node9">
|
||||
<title>F</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="132.502" cy="23.192" rx="18.068" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 128.5942 28.2109)" font-family="'Times-Roman'" font-size="14.0528">F</text>
|
||||
</g>
|
||||
<g id="edge2">
|
||||
<title>F->B</title>
|
||||
<path fill="none" stroke="#000000" d="M117.445,34.234c-11.042,8.03-23.087,17.064-34.128,26.098"/>
|
||||
<polygon stroke="#000000" points="85.325,63.343 75.287,66.354 81.31,57.321 "/>
|
||||
</g>
|
||||
<g id="edge10">
|
||||
<title>F->G</title>
|
||||
<path fill="none" stroke="#000000" d="M147.559,34.234c11.041,8.03,23.087,17.064,34.129,26.098"/>
|
||||
<polygon stroke="#000000" points="183.694,57.321 189.717,66.354 179.68,63.343 "/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
SPDX-FileCopyrightText: Rory O'Kane at Wikimedia Commons
|
||||
<https://commons.wikimedia.org/wiki/File:Sorted_binary_tree_breadth-first_traversal.svg>
|
||||
SPDX-FileCopyrightText: 2024 Frank Dana
|
||||
-->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="266px" height="212px" viewBox="0 0 266 212" enable-background="new 0 0 266 212" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" x1="27.23" y1="23.192" x2="29.23" y2="23.192"/>
|
||||
|
||||
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9562,3.9562" x1="33.187" y1="23.192" x2="236.932" y2="23.192"/>
|
||||
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="238.91,23.192 240.91,23.192
|
||||
238.97,23.677 "/>
|
||||
|
||||
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="24.646" x2="27.971" y2="76.427"/>
|
||||
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="26.035,76.912 24.095,77.396
|
||||
26.095,77.396 "/>
|
||||
|
||||
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="77.396" x2="236.902" y2="77.396"/>
|
||||
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="238.91,77.396 240.91,77.396
|
||||
238.97,77.881 "/>
|
||||
|
||||
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="78.85" x2="27.971" y2="130.631"/>
|
||||
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="26.035,131.114 24.095,131.6
|
||||
26.095,131.6 "/>
|
||||
|
||||
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0154,4.0154" x1="30.11" y1="131.6" x2="236.902" y2="131.6"/>
|
||||
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="238.91,131.6 240.91,131.6
|
||||
238.97,132.085 "/>
|
||||
|
||||
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="3.9907,3.9907" x1="235.099" y1="133.053" x2="27.971" y2="184.835"/>
|
||||
<polyline fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" points="26.035,185.318 24.095,185.804
|
||||
26.095,185.804 "/>
|
||||
|
||||
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="4.0086,4.0086" x1="30.104" y1="185.804" x2="228.53" y2="185.804"/>
|
||||
|
||||
<line fill="none" stroke="#1c76e4" stroke-width="2" stroke-miterlimit="10" x1="230.534" y1="185.804" x2="232.534" y2="185.804"/>
|
||||
<g>
|
||||
<rect fill="#1c76e4" x="24.095" y="19.892" width="6.602" height="6.602"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#1c76e4" d="M238.569,185.804c-2.84,1.054-6.363,2.852-8.548,4.756l1.721-4.756l-1.721-4.755
|
||||
C232.206,182.953,235.729,184.751,238.569,185.804z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="graph0">
|
||||
<title>sorted_binary_tree</title>
|
||||
<g id="node1">
|
||||
<title>C</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="60.23" cy="185.804" rx="18.067" ry="18.067"/>
|
||||
<text transform="matrix(1 0 0 1 55.5435 190.8223)" font-family="'Times-Roman'" font-size="14.0528">C</text>
|
||||
</g>
|
||||
<g id="node2">
|
||||
<title>E</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="132.502" cy="185.804" rx="18.067" ry="18.067"/>
|
||||
<text transform="matrix(1 0 0 1 128.21 190.8223)" font-family="'Times-Roman'" font-size="14.0528">E</text>
|
||||
</g>
|
||||
<g id="node3">
|
||||
<title>H</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="204.773" cy="185.804" rx="17.064" ry="18.067"/>
|
||||
<text transform="matrix(1 0 0 1 199.6992 190.8223)" font-family="'Times-Roman'" font-size="14.0528">H</text>
|
||||
</g>
|
||||
<g id="node4">
|
||||
<title>A</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="24.094" cy="131.6" rx="17.064" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 19.02 136.6191)" font-family="'Times-Roman'" font-size="14.0528">A</text>
|
||||
</g>
|
||||
<g id="node5">
|
||||
<title>D</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="96.366" cy="131.6" rx="17.064" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 91.292 136.6191)" font-family="'Times-Roman'" font-size="14.0528">D</text>
|
||||
</g>
|
||||
<g id="edge6">
|
||||
<title>D->C</title>
|
||||
<path fill="none" stroke="#000000" d="M86.328,147.66c-3.011,4.016-7.026,9.034-10.038,14.053"/>
|
||||
<polygon stroke="#000000" points="78.298,164.725 70.268,170.747 73.279,160.709 "/>
|
||||
</g>
|
||||
<g id="edge8">
|
||||
<title>D->E</title>
|
||||
<path fill="none" stroke="#000000" d="M106.404,147.66c3.011,4.016,7.026,9.034,10.038,14.053"/>
|
||||
<polygon stroke="#000000" points="119.453,160.709 122.464,170.747 114.434,164.725 "/>
|
||||
</g>
|
||||
<g id="node6">
|
||||
<title>I</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="240.909" cy="131.6" rx="18.068" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 238.5693 136.6191)" font-family="'Times-Roman'" font-size="14.0528">I</text>
|
||||
</g>
|
||||
<g id="edge12">
|
||||
<title>I->H</title>
|
||||
<path fill="none" stroke="#000000" d="M230.871,146.656c-3.011,5.02-6.021,10.038-10.037,15.057"/>
|
||||
<polygon stroke="#000000" points="223.846,163.721 214.812,169.743 217.822,159.705 "/>
|
||||
</g>
|
||||
<g id="node7">
|
||||
<title>B</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="60.23" cy="77.396" rx="18.068" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 55.5435 82.415)" font-family="'Times-Roman'" font-size="14.0528">B</text>
|
||||
</g>
|
||||
<g id="edge3">
|
||||
<title>B->A</title>
|
||||
<path fill="none" stroke="#000000" d="M50.192,92.453c-3.011,5.019-6.022,10.038-10.038,15.057"/>
|
||||
<polygon stroke="#000000" points="43.166,109.518 34.132,115.539 37.144,105.502 "/>
|
||||
</g>
|
||||
<g id="edge5">
|
||||
<title>B->D</title>
|
||||
<path fill="none" stroke="#000000" d="M70.268,92.453c3.011,5.019,6.022,10.038,10.038,15.057"/>
|
||||
<polygon stroke="#000000" points="83.317,105.502 86.328,115.539 77.294,109.518 "/>
|
||||
</g>
|
||||
<g id="node8">
|
||||
<title>G</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="204.773" cy="77.396" rx="17.064" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 199.6992 82.415)" font-family="'Times-Roman'" font-size="14.0528">G</text>
|
||||
</g>
|
||||
<g id="edge11">
|
||||
<title>G->I</title>
|
||||
<path fill="none" stroke="#000000" d="M214.812,93.457c3.011,4.015,7.026,9.034,10.038,14.053"/>
|
||||
<polygon stroke="#000000" points="227.86,106.506 230.871,116.543 222.842,110.521 "/>
|
||||
</g>
|
||||
<g id="node9">
|
||||
<title>F</title>
|
||||
<ellipse fill="#FFFFFF" stroke="#000000" cx="132.502" cy="23.192" rx="18.068" ry="18.068"/>
|
||||
<text transform="matrix(1 0 0 1 128.5942 28.2109)" font-family="'Times-Roman'" font-size="14.0528">F</text>
|
||||
</g>
|
||||
<g id="edge2">
|
||||
<title>F->B</title>
|
||||
<path fill="none" stroke="#000000" d="M117.445,34.234c-11.042,8.03-23.087,17.064-34.128,26.098"/>
|
||||
<polygon stroke="#000000" points="85.325,63.343 75.287,66.354 81.31,57.321 "/>
|
||||
</g>
|
||||
<g id="edge10">
|
||||
<title>F->G</title>
|
||||
<path fill="none" stroke="#000000" d="M147.559,34.234c11.041,8.03,23.087,17.064,34.129,26.098"/>
|
||||
<polygon stroke="#000000" points="183.694,57.321 189.717,66.354 179.68,63.343 "/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.0 KiB |
758
docs/reference/glib/Sorted_binary_tree_inorder-dark.svg
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
755
docs/reference/glib/Sorted_binary_tree_postorder-dark.svg
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
755
docs/reference/glib/Sorted_binary_tree_preorder-dark.svg
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@ -99,6 +99,10 @@ content_images = [
|
||||
"Sorted_binary_tree_inorder.svg",
|
||||
"Sorted_binary_tree_postorder.svg",
|
||||
"Sorted_binary_tree_preorder.svg",
|
||||
"Sorted_binary_tree_breadth-first_traversal-dark.svg",
|
||||
"Sorted_binary_tree_inorder-dark.svg",
|
||||
"Sorted_binary_tree_postorder-dark.svg",
|
||||
"Sorted_binary_tree_preorder-dark.svg",
|
||||
]
|
||||
|
||||
[[object]]
|
||||
|
381
glib/gdataset.c
@ -68,6 +68,22 @@
|
||||
|
||||
#define G_DATALIST_FLAGS_MASK_INTERNAL 0x7
|
||||
|
||||
/* When GData.alloc grows to size ALLOC_THRESHOLD_INDEX, we reserve one additional
|
||||
* GHashTable* at &data->data[data->alloc]. This will contain the index for fast
|
||||
* lookup. See datalist_index*() helpers.
|
||||
*
|
||||
* Note that we grow the GData.data buffer by doubling the allocation size. So
|
||||
* we first allocate 64 entries, when adding the 33 entry.
|
||||
*
|
||||
* Conversely, we exponentially shrink the buffer. That means, when we remove
|
||||
* entries and reach 16 (or lower), we will shrink the buffer from 64 to 32
|
||||
* entries (and stop using the index).
|
||||
*
|
||||
* So we start using the index when adding >= 33 entries. And stop using it
|
||||
* when removing to <= 16 entries.
|
||||
*/
|
||||
#define ALLOC_THRESHOLD_INDEX 64u
|
||||
|
||||
#define G_DATALIST_CLEAN_POINTER(ptr) \
|
||||
((GData *) ((gpointer) (((guintptr) (ptr)) & ~((guintptr) G_DATALIST_FLAGS_MASK_INTERNAL))))
|
||||
|
||||
@ -158,53 +174,178 @@ g_datalist_unlock_and_set (GData **datalist, gpointer ptr)
|
||||
g_pointer_bit_unlock_and_set ((void **) datalist, DATALIST_LOCK_BIT, ptr, G_DATALIST_FLAGS_MASK_INTERNAL);
|
||||
}
|
||||
|
||||
static gsize
|
||||
datalist_alloc_size (guint32 alloc)
|
||||
{
|
||||
/* GDataElt also contains pointer. It thus is suitable aligned for pointers,
|
||||
* and we can just append the pointer for the index at the end. */
|
||||
return G_STRUCT_OFFSET (GData, data) +
|
||||
(((gsize) alloc) * sizeof (GDataElt)) +
|
||||
(G_UNLIKELY (alloc >= ALLOC_THRESHOLD_INDEX) ? sizeof (GHashTable *) : 0u);
|
||||
}
|
||||
|
||||
G_ALWAYS_INLINE static inline GHashTable **
|
||||
datalist_index_get_ptr (GData *data)
|
||||
{
|
||||
if (G_LIKELY (data->alloc < ALLOC_THRESHOLD_INDEX))
|
||||
return NULL;
|
||||
|
||||
return (gpointer) (&(data->data[data->alloc]));
|
||||
}
|
||||
|
||||
G_ALWAYS_INLINE static inline GHashTable *
|
||||
datalist_index_get (GData *data)
|
||||
{
|
||||
GHashTable **p_index;
|
||||
|
||||
p_index = datalist_index_get_ptr (data);
|
||||
|
||||
#if G_ENABLE_DEBUG
|
||||
g_assert (!p_index || *p_index);
|
||||
#endif
|
||||
|
||||
return G_UNLIKELY (p_index) ? *p_index : NULL;
|
||||
}
|
||||
|
||||
static guint
|
||||
_datalist_index_hash (gconstpointer key)
|
||||
{
|
||||
const GQuark *ptr = key;
|
||||
|
||||
G_STATIC_ASSERT (G_STRUCT_OFFSET (GDataElt, key) == 0);
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_datalist_index_equal (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const GQuark *ptr_a = a;
|
||||
const GQuark *ptr_b = b;
|
||||
|
||||
return *ptr_a == *ptr_b;
|
||||
}
|
||||
|
||||
G_ALWAYS_INLINE static inline GHashTable *
|
||||
datalist_index_new (void)
|
||||
{
|
||||
return g_hash_table_new (_datalist_index_hash, _datalist_index_equal);
|
||||
}
|
||||
|
||||
static GData *
|
||||
datalist_realloc (GData *data, guint32 alloc, gboolean *out_reallocated)
|
||||
{
|
||||
guintptr data_old;
|
||||
gboolean reallocated;
|
||||
GHashTable *index;
|
||||
GHashTable **p_index;
|
||||
guint32 i;
|
||||
|
||||
data_old = (guintptr) ((gpointer) data);
|
||||
index = datalist_index_get (data);
|
||||
|
||||
data = g_realloc (data, datalist_alloc_size (alloc));
|
||||
|
||||
reallocated = (((guintptr) ((gpointer) (data))) != data_old);
|
||||
|
||||
data->alloc = alloc;
|
||||
|
||||
if (out_reallocated)
|
||||
*out_reallocated = reallocated;
|
||||
|
||||
/* Note that if data was @reallocated, then @index contains only dangling pointers.
|
||||
* We can only destroy/remove-all, which we rely on not following those pointers. */
|
||||
|
||||
p_index = datalist_index_get_ptr (data);
|
||||
|
||||
if (G_LIKELY (!p_index))
|
||||
{
|
||||
if (G_UNLIKELY (index))
|
||||
g_hash_table_unref (index);
|
||||
}
|
||||
else if (!reallocated && index)
|
||||
{
|
||||
/* The index is still fine and the pointers are all still valid. We
|
||||
* can keep it. */
|
||||
*p_index = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (G_UNLIKELY (index))
|
||||
{
|
||||
/* Note that the GHashTable's keys are now all dangling pointers!
|
||||
* We rely on remove-all to not following them. */
|
||||
g_hash_table_remove_all (index);
|
||||
}
|
||||
else
|
||||
index = datalist_index_new ();
|
||||
|
||||
*p_index = index;
|
||||
|
||||
for (i = 0; i < data->len; i++)
|
||||
g_hash_table_add (index, &data->data[i]);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
datalist_append (GData **data, GQuark key_id, gpointer new_data, GDestroyNotify destroy_func)
|
||||
{
|
||||
GDataElt *data_elt;
|
||||
GHashTable *index;
|
||||
gboolean reallocated;
|
||||
GData *d;
|
||||
|
||||
d = *data;
|
||||
if (!d)
|
||||
{
|
||||
d = g_malloc (G_STRUCT_OFFSET (GData, data) + 2u * sizeof (GDataElt));
|
||||
d = g_malloc (datalist_alloc_size (2u));
|
||||
d->len = 0;
|
||||
d->alloc = 2u;
|
||||
|
||||
if (2u >= ALLOC_THRESHOLD_INDEX)
|
||||
*(datalist_index_get_ptr (d)) = datalist_index_new ();
|
||||
|
||||
*data = d;
|
||||
reallocated = TRUE;
|
||||
}
|
||||
else if (d->len == d->alloc)
|
||||
{
|
||||
d->alloc = d->alloc * 2u;
|
||||
#if G_ENABLE_DEBUG
|
||||
/* d->alloc is always a power of two. It thus overflows the first time
|
||||
* when going to (G_MAXUINT32+1), or when requesting 2^31+1 elements.
|
||||
*
|
||||
* This is not handled, and we just crash. That's because we track the GData
|
||||
* in a linear list, which horribly degrades long before we add 2 billion entries.
|
||||
* Don't ever try to do that. */
|
||||
g_assert (d->alloc > d->len);
|
||||
#endif
|
||||
d = g_realloc (d, G_STRUCT_OFFSET (GData, data) + d->alloc * sizeof (GDataElt));
|
||||
guint32 alloc = d->alloc * 2u;
|
||||
|
||||
if (G_UNLIKELY (alloc < d->alloc))
|
||||
{
|
||||
if (d->alloc == G_MAXUINT32)
|
||||
g_error ("GData cannot contain more than 4294967295 entries");
|
||||
alloc = G_MAXUINT32;
|
||||
}
|
||||
d = datalist_realloc (d, alloc, &reallocated);
|
||||
*data = d;
|
||||
reallocated = TRUE;
|
||||
}
|
||||
else
|
||||
reallocated = FALSE;
|
||||
|
||||
d->data[d->len] = (GDataElt){
|
||||
data_elt = &d->data[d->len];
|
||||
*data_elt = (GDataElt){
|
||||
.key = key_id,
|
||||
.data = new_data,
|
||||
.destroy = destroy_func,
|
||||
};
|
||||
d->len++;
|
||||
|
||||
index = datalist_index_get (d);
|
||||
if (G_UNLIKELY (index))
|
||||
g_hash_table_add (index, data_elt);
|
||||
|
||||
return reallocated;
|
||||
}
|
||||
|
||||
static void
|
||||
datalist_remove (GData *data, guint32 idx)
|
||||
{
|
||||
GHashTable *index;
|
||||
|
||||
#if G_ENABLE_DEBUG
|
||||
g_assert (idx < data->len);
|
||||
#endif
|
||||
@ -214,15 +355,24 @@ datalist_remove (GData *data, guint32 idx)
|
||||
* to @idx are left unchanged, and the last entry is moved to position @idx.
|
||||
* */
|
||||
|
||||
index = datalist_index_get (data);
|
||||
if (G_UNLIKELY (index))
|
||||
g_hash_table_remove (index, &data->data[idx]);
|
||||
|
||||
data->len--;
|
||||
|
||||
if (idx != data->len)
|
||||
data->data[idx] = data->data[data->len];
|
||||
{
|
||||
data->data[idx] = data->data[data->len];
|
||||
if (G_UNLIKELY (index))
|
||||
g_hash_table_add (index, &data->data[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
datalist_shrink (GData **data, GData **d_to_free)
|
||||
{
|
||||
gboolean reallocated;
|
||||
guint32 alloc_by_4;
|
||||
guint32 v;
|
||||
GData *d;
|
||||
@ -239,10 +389,17 @@ datalist_shrink (GData **data, GData **d_to_free)
|
||||
|
||||
if (d->len == 0)
|
||||
{
|
||||
GHashTable *index;
|
||||
|
||||
/* The list became empty. We drop the allocated memory altogether. */
|
||||
|
||||
/* The caller will free the buffer after releasing the lock, to minimize
|
||||
* the time we hold the lock. Transfer it out. */
|
||||
|
||||
index = datalist_index_get (d);
|
||||
if (G_UNLIKELY (index))
|
||||
g_hash_table_unref (index);
|
||||
|
||||
*d_to_free = d;
|
||||
*data = NULL;
|
||||
return TRUE;
|
||||
@ -253,8 +410,9 @@ datalist_shrink (GData **data, GData **d_to_free)
|
||||
v = d->len;
|
||||
if (v != alloc_by_4)
|
||||
{
|
||||
/* d->alloc is a power of two. Usually, we remove one element at a
|
||||
* time, then we will just reach reach a quarter of that.
|
||||
/* d->alloc is a power of two (unless it's G_MAXUINT32). Usually, we
|
||||
* remove one element at a time, then we will just reach reach a quarter
|
||||
* of that.
|
||||
*
|
||||
* However, with g_datalist_id_remove_multiple(), len can be smaller
|
||||
* at once. In that case, find first the next power of two. */
|
||||
@ -264,27 +422,55 @@ datalist_shrink (GData **data, GData **d_to_free)
|
||||
|
||||
#if G_ENABLE_DEBUG
|
||||
g_assert (v > d->len);
|
||||
g_assert (v <= d->alloc / 2u);
|
||||
g_assert (v <= (d->alloc == G_MAXUINT32 ? 0x80000000u : d->alloc / 2u));
|
||||
#endif
|
||||
|
||||
d->alloc = v;
|
||||
d = g_realloc (d, G_STRUCT_OFFSET (GData, data) + (v * sizeof (GDataElt)));
|
||||
d = datalist_realloc (d, v, &reallocated);
|
||||
*d_to_free = NULL;
|
||||
*data = d;
|
||||
return TRUE;
|
||||
return reallocated;
|
||||
}
|
||||
|
||||
static void
|
||||
datalist_destroy (GData *data)
|
||||
{
|
||||
GHashTable *index;
|
||||
guint32 i;
|
||||
|
||||
/* Must be called without lock. Will free @data and invoke the
|
||||
* destroy() notifications. */
|
||||
|
||||
index = datalist_index_get (data);
|
||||
if (G_UNLIKELY (index))
|
||||
g_hash_table_unref (index);
|
||||
|
||||
for (i = 0; i < data->len; i++)
|
||||
{
|
||||
if (data->data[i].destroy)
|
||||
data->data[i].destroy (data->data[i].data);
|
||||
}
|
||||
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static GDataElt *
|
||||
datalist_find (GData *data, GQuark key_id, guint32 *out_idx)
|
||||
{
|
||||
GDataElt *data_elt;
|
||||
GHashTable *index;
|
||||
guint32 i;
|
||||
|
||||
if (data)
|
||||
if (!data)
|
||||
goto out_not_found;
|
||||
|
||||
index = datalist_index_get (data);
|
||||
|
||||
if (G_LIKELY (!index))
|
||||
{
|
||||
/* We have no index. Do a linear search. */
|
||||
for (i = 0; i < data->len; i++)
|
||||
{
|
||||
GDataElt *data_elt = &data->data[i];
|
||||
|
||||
data_elt = &data->data[i];
|
||||
if (data_elt->key == key_id)
|
||||
{
|
||||
if (out_idx)
|
||||
@ -292,7 +478,23 @@ datalist_find (GData *data, GQuark key_id, guint32 *out_idx)
|
||||
return data_elt;
|
||||
}
|
||||
}
|
||||
|
||||
goto out_not_found;
|
||||
}
|
||||
|
||||
data_elt = g_hash_table_lookup (index, &key_id);
|
||||
if (!data_elt)
|
||||
goto out_not_found;
|
||||
|
||||
#if G_ENABLE_DEBUG
|
||||
g_assert (data_elt >= data->data && data_elt < &data->data[data->len]);
|
||||
#endif
|
||||
|
||||
if (out_idx)
|
||||
*out_idx = (data_elt - data->data);
|
||||
return data_elt;
|
||||
|
||||
out_not_found:
|
||||
if (out_idx)
|
||||
*out_idx = G_MAXUINT32;
|
||||
return NULL;
|
||||
@ -310,7 +512,6 @@ void
|
||||
g_datalist_clear (GData **datalist)
|
||||
{
|
||||
GData *data;
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (datalist != NULL);
|
||||
|
||||
@ -324,13 +525,7 @@ g_datalist_clear (GData **datalist)
|
||||
|
||||
g_datalist_unlock_and_set (datalist, NULL);
|
||||
|
||||
for (i = 0; i < data->len; i++)
|
||||
{
|
||||
if (data->data[i].data && data->data[i].destroy)
|
||||
data->data[i].destroy (data->data[i].data);
|
||||
}
|
||||
|
||||
g_free (data);
|
||||
datalist_destroy (data);
|
||||
}
|
||||
|
||||
/* HOLDS: g_dataset_global_lock */
|
||||
@ -359,7 +554,6 @@ g_dataset_destroy_internal (GDataset *dataset)
|
||||
while (dataset)
|
||||
{
|
||||
GData *data;
|
||||
guint i;
|
||||
|
||||
data = G_DATALIST_GET_POINTER (&dataset->datalist);
|
||||
|
||||
@ -376,12 +570,7 @@ g_dataset_destroy_internal (GDataset *dataset)
|
||||
|
||||
G_UNLOCK (g_dataset_global);
|
||||
|
||||
for (i = 0; i < data->len; i++)
|
||||
{
|
||||
if (data->data[i].data && data->data[i].destroy)
|
||||
data->data[i].destroy (data->data[i].data);
|
||||
}
|
||||
g_free (data);
|
||||
datalist_destroy (data);
|
||||
|
||||
G_LOCK (g_dataset_global);
|
||||
dataset = g_dataset_lookup (dataset_location);
|
||||
@ -530,7 +719,9 @@ g_data_remove_internal (GData **datalist,
|
||||
GData *d_to_free;
|
||||
gsize found_keys;
|
||||
gsize i_keys;
|
||||
guint32 i_data;
|
||||
|
||||
if (n_keys == 0)
|
||||
return;
|
||||
|
||||
d = g_datalist_lock_and_get (datalist);
|
||||
|
||||
@ -556,33 +747,23 @@ g_data_remove_internal (GData **datalist,
|
||||
old = old_to_free;
|
||||
}
|
||||
|
||||
i_data = 0;
|
||||
found_keys = 0;
|
||||
while (i_data < d->len && found_keys < n_keys)
|
||||
for (i_keys = 0; i_keys < n_keys; i_keys++)
|
||||
{
|
||||
GDataElt *data = &d->data[i_data];
|
||||
gboolean remove = FALSE;
|
||||
GDataElt *data_elt;
|
||||
guint32 idx;
|
||||
|
||||
for (i_keys = 0; i_keys < n_keys; i_keys++)
|
||||
{
|
||||
if (data->key == keys[i_keys])
|
||||
{
|
||||
/* We must invoke the destroy notifications in the order of @keys.
|
||||
* Hence, build up the list @old at index @i_keys. */
|
||||
old[i_keys] = *data;
|
||||
found_keys++;
|
||||
remove = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
data_elt = datalist_find (d, keys[i_keys], &idx);
|
||||
if (!data_elt)
|
||||
continue;
|
||||
|
||||
if (!remove)
|
||||
{
|
||||
i_data++;
|
||||
continue;
|
||||
}
|
||||
|
||||
datalist_remove (d, i_data);
|
||||
/* We must destroy the keys in the order in which they are specified.
|
||||
* We achieve that here.
|
||||
*
|
||||
* Note that even if @keys contains duplicates, we correctly only
|
||||
* find them once, as we remove the found entry right away. */
|
||||
old[found_keys++] = *data_elt;
|
||||
datalist_remove (d, idx);
|
||||
}
|
||||
|
||||
if (found_keys > 0 && datalist_shrink (&d, &d_to_free))
|
||||
@ -594,13 +775,10 @@ g_data_remove_internal (GData **datalist,
|
||||
else
|
||||
g_datalist_unlock (datalist);
|
||||
|
||||
if (found_keys > 0)
|
||||
for (i_keys = 0; i_keys < found_keys; i_keys++)
|
||||
{
|
||||
for (i_keys = 0; i_keys < n_keys; i_keys++)
|
||||
{
|
||||
if (old[i_keys].destroy)
|
||||
old[i_keys].destroy (old[i_keys].data);
|
||||
}
|
||||
if (old[i_keys].destroy)
|
||||
old[i_keys].destroy (old[i_keys].data);
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (old_to_free))
|
||||
@ -803,9 +981,7 @@ g_datalist_id_set_data_full (GData **datalist,
|
||||
* This is more efficient than calling g_datalist_id_remove_data()
|
||||
* multiple times in a row.
|
||||
*
|
||||
* Before 2.80, @n_keys had to be not larger than 16. Now it can be larger, but
|
||||
* note that GData does a linear search, so an excessive number of keys will
|
||||
* perform badly.
|
||||
* Before 2.80, @n_keys had to be not larger than 16.
|
||||
*
|
||||
* Since: 2.74
|
||||
*/
|
||||
@ -1228,37 +1404,56 @@ g_datalist_id_replace_data (GData **datalist,
|
||||
* is not found.
|
||||
**/
|
||||
gpointer
|
||||
g_datalist_get_data (GData **datalist,
|
||||
const gchar *key)
|
||||
g_datalist_get_data (GData **datalist,
|
||||
const gchar *key)
|
||||
{
|
||||
GQuark key_id;
|
||||
GHashTable *index;
|
||||
gpointer res = NULL;
|
||||
GDataElt *data_elt;
|
||||
GData *d;
|
||||
GDataElt *data, *data_end;
|
||||
|
||||
g_return_val_if_fail (datalist != NULL, NULL);
|
||||
|
||||
d = g_datalist_lock_and_get (datalist);
|
||||
if (d)
|
||||
|
||||
if (!d)
|
||||
goto out;
|
||||
|
||||
index = datalist_index_get (d);
|
||||
|
||||
if (G_LIKELY (!index))
|
||||
{
|
||||
data = d->data;
|
||||
data_end = data + d->len;
|
||||
while (data < data_end)
|
||||
{
|
||||
/* Here we intentionally compare by strings, instead of calling
|
||||
* g_quark_try_string() first.
|
||||
*
|
||||
* See commit 1cceda49b60b ('Make g_datalist_get_data not look up the
|
||||
* quark').
|
||||
*/
|
||||
if (g_strcmp0 (g_quark_to_string (data->key), key) == 0)
|
||||
{
|
||||
res = data->data;
|
||||
break;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
guint32 i;
|
||||
|
||||
for (i = 0; i < d->len; i++)
|
||||
{
|
||||
data_elt = &d->data[i];
|
||||
/* Here we intentionally compare by strings, instead of calling
|
||||
* g_quark_try_string() first.
|
||||
*
|
||||
* See commit 1cceda49b60b ('Make g_datalist_get_data not look up the
|
||||
* quark').
|
||||
*/
|
||||
if (g_strcmp0 (g_quark_to_string (data_elt->key), key) == 0)
|
||||
{
|
||||
res = data_elt->data;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
key_id = g_quark_try_string (key);
|
||||
if (key_id == 0 && key)
|
||||
goto out;
|
||||
|
||||
data_elt = g_hash_table_lookup (index, &key_id);
|
||||
|
||||
if (data_elt)
|
||||
res = data_elt->data;
|
||||
|
||||
out:
|
||||
g_datalist_unlock (datalist);
|
||||
|
||||
return res;
|
||||
|
34
glib/gnode.c
@ -800,16 +800,38 @@ g_node_depth_traverse_level (GNode *node,
|
||||
* efficient than the other orders.
|
||||
*
|
||||
* Specifies the type of traversal performed by g_tree_traverse(),
|
||||
* g_node_traverse() and g_node_find(). The different orders are
|
||||
* illustrated here:
|
||||
* g_node_traverse() and g_node_find().
|
||||
*
|
||||
* The different orders are illustrated here:
|
||||
*
|
||||
* - In order: A, B, C, D, E, F, G, H, I
|
||||
* ![](Sorted_binary_tree_inorder.svg)
|
||||
* <picture>
|
||||
* <source srcset="Sorted_binary_tree_inorder-dark.svg"
|
||||
* media="(prefers-color-scheme: dark)">
|
||||
* <img src="Sorted_binary_tree_inorder.svg"
|
||||
* alt="Sorted binary tree, in-order traversal">
|
||||
* </picture>
|
||||
* - Pre order: F, B, A, D, C, E, G, I, H
|
||||
* ![](Sorted_binary_tree_preorder.svg)
|
||||
* <picture>
|
||||
* <source srcset="Sorted_binary_tree_preorder-dark.svg"
|
||||
* media="(prefers-color-scheme: dark)">
|
||||
* <img src="Sorted_binary_tree_preorder.svg"
|
||||
* alt="Sorted binary tree, pre-order traversal">
|
||||
* </picture>
|
||||
* - Post order: A, C, E, D, B, H, I, G, F
|
||||
* ![](Sorted_binary_tree_postorder.svg)
|
||||
* <picture>
|
||||
* <source srcset="Sorted_binary_tree_postorder-dark.svg"
|
||||
* media="(prefers-color-scheme: dark)">
|
||||
* <img src="Sorted_binary_tree_postorder.svg"
|
||||
* alt="Sorted binary tree, post-order traversal">
|
||||
* </picture>
|
||||
* - Level order: F, B, G, A, D, I, C, E, H
|
||||
* ![](Sorted_binary_tree_breadth-first_traversal.svg)
|
||||
* <picture>
|
||||
* <source srcset="Sorted_binary_tree_breadth-first_traversal-dark.svg"
|
||||
* media="(prefers-color-scheme: dark)">
|
||||
* <img src="Sorted_binary_tree_breadth-first_traversal.svg"
|
||||
* alt="Sorted binary tree, breadth-first level order traversal">
|
||||
* </picture>
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -305,6 +305,7 @@ test_datalist_id_remove_multiple_resize (void)
|
||||
{
|
||||
GQuark *quarks;
|
||||
GQuark *quarks2;
|
||||
gboolean *has;
|
||||
const guint N = 1000;
|
||||
const guint PRIME = 1048583u;
|
||||
guint i;
|
||||
@ -314,6 +315,7 @@ test_datalist_id_remove_multiple_resize (void)
|
||||
|
||||
quarks = g_new (GQuark, N);
|
||||
quarks2 = g_new (GQuark, N);
|
||||
has = g_new0 (gboolean, N);
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
@ -322,12 +324,15 @@ test_datalist_id_remove_multiple_resize (void)
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
g_datalist_id_set_data (&list, quarks[i], GINT_TO_POINTER (i));
|
||||
{
|
||||
g_datalist_id_set_data (&list, quarks[i], (gpointer) g_quark_to_string (quarks[i]));
|
||||
has[i] = TRUE;
|
||||
}
|
||||
|
||||
/* Now we perform a list of random operations (remove/add quarks). */
|
||||
for (i_run = 0; TRUE; i_run++)
|
||||
{
|
||||
int MODE = ((guint) g_test_rand_int ()) % 4;
|
||||
int MODE = ((guint) g_test_rand_int ()) % 6;
|
||||
guint n;
|
||||
guint j;
|
||||
|
||||
@ -355,9 +360,15 @@ test_datalist_id_remove_multiple_resize (void)
|
||||
{
|
||||
j = (j + PRIME) % N;
|
||||
if (MODE == 0)
|
||||
g_datalist_id_remove_data (&list, quarks[j]);
|
||||
{
|
||||
g_datalist_id_remove_data (&list, quarks[j]);
|
||||
has[j] = FALSE;
|
||||
}
|
||||
else
|
||||
g_datalist_id_set_data (&list, quarks[j], GINT_TO_POINTER (j));
|
||||
{
|
||||
g_datalist_id_set_data (&list, quarks[j], (gpointer) g_quark_to_string (quarks[j]));
|
||||
has[j] = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
@ -366,15 +377,59 @@ test_datalist_id_remove_multiple_resize (void)
|
||||
{
|
||||
j = (j + PRIME) % N;
|
||||
quarks2[i] = quarks[j];
|
||||
has[j] = FALSE;
|
||||
}
|
||||
|
||||
g_datalist_id_remove_multiple (&list, quarks2, n);
|
||||
break;
|
||||
case 4:
|
||||
/* Mode: lookup string via g_datalist_get_data()*/
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
const char *data;
|
||||
const char *data2;
|
||||
const char *key;
|
||||
|
||||
j = (j + PRIME) % N;
|
||||
|
||||
key = g_quark_to_string (quarks[j]);
|
||||
|
||||
data = g_datalist_id_get_data (&list, quarks[j]);
|
||||
data2 = g_datalist_get_data (&list, key);
|
||||
g_assert_true (data == data2);
|
||||
if (data)
|
||||
g_assert_true (data == key);
|
||||
g_assert_true ((!!data) == has[j]);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
/* Fill/empty the list completely. */
|
||||
switch (((guint) g_test_rand_int ()) % 5)
|
||||
{
|
||||
case 0:
|
||||
g_datalist_clear (&list);
|
||||
for (i = 0; i < N; i++)
|
||||
has[i] = FALSE;
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < N; i++)
|
||||
{
|
||||
j = (j + PRIME) % N;
|
||||
g_datalist_id_set_data (&list, quarks[j], (gpointer) g_quark_to_string (quarks[j]));
|
||||
has[i] = TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Most of the time we do nothing. The case where we fill/empty
|
||||
* the list entirely is less interesting. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_free (quarks);
|
||||
g_free (quarks2);
|
||||
g_free (has);
|
||||
}
|
||||
|
||||
static void
|
||||
|