mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-14 21:09:05 +08:00
+ Upd: Version files of uthash and Oniguruma
This commit is contained in:
parent
38dfa4f96c
commit
2c0a8fa90c
@ -435,7 +435,7 @@ read the files without being told the new key.
|
||||
|
||||
|
||||
Technical Details:
|
||||
(http://www.andromeda.com/people/ddyer/notepad/NotepadCrypt-technotes.html)
|
||||
(https://www.real-me.net/ddyer/notepad/NotepadCrypt-technotes.html)
|
||||
|
||||
Passphrase Management:
|
||||
256 bit encryption keys are geneated from ascii passphrases by
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
Oniguruma Regular Expressions Version 6.9.5 2020/01/28
|
||||
Oniguruma Regular Expressions Version 6.9.6 2020/07/31
|
||||
|
||||
syntax: ONIG_SYNTAX_ONIGURUMA (default)
|
||||
syntax: ONIG_SYNTAX_ONIGURUMA (default syntax)
|
||||
|
||||
|
||||
1. Syntax elements
|
||||
@ -21,19 +21,28 @@ syntax: ONIG_SYNTAX_ONIGURUMA (default)
|
||||
\f form feed (0x0C)
|
||||
\a bell (0x07)
|
||||
\e escape (0x1B)
|
||||
\nnn octal char (encoded byte value)
|
||||
\o{17777777777} wide octal char (character code point value)
|
||||
\uHHHH wide hexadecimal char (character code point value)
|
||||
\xHH hexadecimal char (encoded byte value)
|
||||
\x{7HHHHHHH} wide hexadecimal char (character code point value)
|
||||
\cx control char (character code point value)
|
||||
\C-x control char (character code point value)
|
||||
\M-x meta (x|0x80) (character code point value)
|
||||
\M-\C-x meta control char (character code point value)
|
||||
\nnn octal char (encoded byte value)
|
||||
\xHH hexadecimal char (encoded byte value)
|
||||
\x{7HHHHHHH} (1-8 digits) hexadecimal char (code point value)
|
||||
\o{17777777777} (1-11 digits) octal char (code point value)
|
||||
\uHHHH hexadecimal char (code point value)
|
||||
\cx control char (code point value)
|
||||
\C-x control char (code point value)
|
||||
\M-x meta (x|0x80) (code point value)
|
||||
\M-\C-x meta control char (code point value)
|
||||
|
||||
(* \b as backspace is effective in character class only)
|
||||
|
||||
|
||||
2.1 Code point sequences
|
||||
|
||||
Hexadecimal code point (1-8 digits)
|
||||
\x{7HHHHHHH 7HHHHHHH ... 7HHHHHHH}
|
||||
|
||||
Octal code point (1-11 digits)
|
||||
\o{17777777777 17777777777 ... 17777777777}
|
||||
|
||||
|
||||
3. Character types
|
||||
|
||||
. any character (except newline)
|
||||
@ -91,13 +100,13 @@ syntax: ONIG_SYNTAX_ONIGURUMA (default)
|
||||
|
||||
[Extended Grapheme Cluster mode] (default)
|
||||
Unicode case:
|
||||
See [Unicode Standard Annex #29: https://unicode.org/reports/tr29]
|
||||
See [Unicode Standard Annex #29: https://unicode.org/reports/tr29/]
|
||||
|
||||
Not Unicode case: \X === (?>\r\n|\O)
|
||||
|
||||
[Word mode]
|
||||
Currently, this mode is supported in Unicode only.
|
||||
See [Unicode Standard Annex #29: https://unicode.org/reports/tr29]
|
||||
See [Unicode Standard Annex #29: https://unicode.org/reports/tr29/]
|
||||
|
||||
|
||||
Character Property
|
||||
@ -182,14 +191,14 @@ syntax: ONIG_SYNTAX_ONIGURUMA (default)
|
||||
|
||||
[Extended Grapheme Cluster mode] (default)
|
||||
Unicode case:
|
||||
See [Unicode Standard Annex #29: https://unicode.org/reports/tr29]
|
||||
See [Unicode Standard Annex #29: https://unicode.org/reports/tr29/]
|
||||
|
||||
Not Unicode:
|
||||
All positions except between \r and \n.
|
||||
|
||||
[Word mode]
|
||||
Currently, this mode is supported in Unicode only.
|
||||
See [Unicode Standard Annex #29: https://unicode.org/reports/tr29]
|
||||
See [Unicode Standard Annex #29: https://unicode.org/reports/tr29/]
|
||||
|
||||
|
||||
|
||||
@ -357,7 +366,7 @@ syntax: ONIG_SYNTAX_ONIGURUMA (default)
|
||||
|
||||
(?~|absent) Absent stopper (* original)
|
||||
After passed this operator, string right range is limited
|
||||
at the point that does not include the string match whth
|
||||
at the point that does not include the string match with
|
||||
<absent>.
|
||||
|
||||
(?~|) Range clear
|
||||
|
||||
6
Build/Docs/uthash/.gitignore
vendored
6
Build/Docs/uthash/.gitignore
vendored
@ -1,6 +0,0 @@
|
||||
ChangeLog.html
|
||||
userguide.html
|
||||
utarray.html
|
||||
utlist.html
|
||||
utringbuffer.html
|
||||
utstring.html
|
||||
@ -5,6 +5,18 @@ Click to return to the link:index.html[uthash home page].
|
||||
|
||||
NOTE: This ChangeLog may be incomplete and/or incorrect. See the git commit log.
|
||||
|
||||
Version 2.1.0 (2018-12-20)
|
||||
--------------------------
|
||||
* silence some Clang static analysis warnings
|
||||
* add LL_INSERT_INORDER and LL_LOWER_BOUND etc (thanks, Jeffrey Lovitz and Mattias Eriksson!)
|
||||
* add uthash_bzero for platforms without <string.h>
|
||||
* fix a missing HASH_BLOOM_ADD in HASH_SELECT (thanks, Pawel Veselov!)
|
||||
* permit malloc failure to be recoverable via HASH_NONFATAL_OOM (thanks, Pawel Veselov!)
|
||||
* avoid repeated calls to uthash_strlen in HASH_FIND_STR
|
||||
* rename uthash_memcmp to HASH_KEYCMP, leaving the old name for compatibility
|
||||
* add utstack.h
|
||||
* remove libut
|
||||
|
||||
Version 2.0.2 (2017-03-02)
|
||||
--------------------------
|
||||
* fix segfault in HASH_ADD_INORDER etc (thanks, Yana Kireyonok!)
|
||||
@ -17,6 +29,7 @@ Version 2.0.1 (2016-07-05)
|
||||
* in-order insertion macros HASH_ADD_INORDER etc (thanks, Thilo Schulz!)
|
||||
* by-hashvalue insertion macros HASH_ADD_BYHASHVALUE etc
|
||||
* during key comparison, check hashvalue before doing a full memcmp
|
||||
* add utringbuffer.h
|
||||
|
||||
Version 1.9.9.1 (2014-11-18)
|
||||
----------------------------
|
||||
@ -43,7 +56,7 @@ Version 1.9.8 (2013-03-10)
|
||||
* `HASH_REPLACE` now in uthash (thanks, Nick Vatamaniuc!)
|
||||
* fixed clang warnings (thanks wynnw!)
|
||||
* fixed `utarray_insert` when inserting past array end (thanks Rob Willett!)
|
||||
* you can now find https://troydhanson.github.com/uthash[uthash on GitHub]
|
||||
* you can now find https://troydhanson.github.com/uthash/[uthash on GitHub]
|
||||
* there's a https://groups.google.com/d/forum/uthash[uthash Google Group]
|
||||
* uthash has been downloaded 29,000+ times since 2006 on SourceForge
|
||||
|
||||
@ -183,7 +196,7 @@ Version 1.5 (2009-02-19)
|
||||
This change made HASH_FIND about 13% faster and enabled reader concurrency.
|
||||
* made link:license.html[BSD license] terms even more permissive
|
||||
* added link:userguide.pdf[PDF version] of User Guide
|
||||
* added https://troydhanson.wordpress.com/feed[update news] image:rss.png[(RSS)]
|
||||
* added https://troydhanson.wordpress.com/feed/[update news] image:rss.png[(RSS)]
|
||||
|
||||
Version 1.4 (2008-09-23)
|
||||
--------------------------
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2005-2016, Troy D. Hanson https://troydhanson.github.com/uthash
|
||||
Copyright (c) 2005-2018, Troy D. Hanson https://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -18,3 +18,4 @@ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
@ -1,451 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="728px"
|
||||
height="90px"
|
||||
id="svg1307"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45.1"
|
||||
sodipodi:docbase="/Users/thanson/code/uthash/trunk/doc/html/img"
|
||||
sodipodi:docname="banner.svg"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/banner.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs1309">
|
||||
<linearGradient
|
||||
id="linearGradient12743">
|
||||
<stop
|
||||
style="stop-color:#99e1fa;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop12745" />
|
||||
<stop
|
||||
id="stop12753"
|
||||
offset="0"
|
||||
style="stop-color:#99e1fa;stop-opacity:0.49803922;" />
|
||||
<stop
|
||||
style="stop-color:#99e1fa;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop12747" />
|
||||
</linearGradient>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible;">
|
||||
<path
|
||||
id="path7755"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
|
||||
transform="scale(0.4) rotate(180)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Sstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Sstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path7752"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
|
||||
transform="scale(0.2)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Send"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Send"
|
||||
style="overflow:visible;">
|
||||
<path
|
||||
id="path7749"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
|
||||
transform="scale(0.2) rotate(180)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="StopM"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="StopM"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path7651"
|
||||
d="M 0.0,5.65 L 0.0,-5.65"
|
||||
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
|
||||
transform="scale(0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow2Mend"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow2Mend"
|
||||
style="overflow:visible;">
|
||||
<path
|
||||
id="path7737"
|
||||
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
transform="scale(0.6) rotate(180) translate(-5,0)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleInM"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="TriangleInM"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path7669"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
|
||||
transform="scale(-0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="StopL"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="StopL"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path7654"
|
||||
d="M 0.0,5.65 L 0.0,-5.65"
|
||||
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
|
||||
transform="scale(0.8)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="TriangleOutM"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="TriangleOutM"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path7660"
|
||||
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
|
||||
transform="scale(0.4)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="DiamondS"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="DiamondS"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path7675"
|
||||
d="M -2.1579186e-005,-7.0710768 L -7.0710894,-8.9383918e-006 L -2.1579186e-005,7.0710589 L 7.0710462,-8.9383918e-006 L -2.1579186e-005,-7.0710768 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
|
||||
transform="scale(0.2)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Tail"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Tail"
|
||||
style="overflow:visible">
|
||||
<g
|
||||
id="g7716"
|
||||
transform="scale(-1.2)">
|
||||
<path
|
||||
id="path7718"
|
||||
d="M -3.8048674,-3.9585227 L 0.54352094,-0.00068114835"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.8;marker-start:none;marker-end:none;stroke-linecap:round" />
|
||||
<path
|
||||
id="path7720"
|
||||
d="M -1.2866832,-3.9585227 L 3.0617053,-0.00068114835"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.8;marker-start:none;marker-end:none;stroke-linecap:round" />
|
||||
<path
|
||||
id="path7722"
|
||||
d="M 1.3053582,-3.9585227 L 5.6537466,-0.00068114835"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.8;marker-start:none;marker-end:none;stroke-linecap:round" />
|
||||
<path
|
||||
id="path7724"
|
||||
d="M -3.8048674,4.1775838 L 0.54352094,0.21974226"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.8;marker-start:none;marker-end:none;stroke-linecap:round" />
|
||||
<path
|
||||
id="path7726"
|
||||
d="M -1.2866832,4.1775838 L 3.0617053,0.21974226"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.8;marker-start:none;marker-end:none;stroke-linecap:round" />
|
||||
<path
|
||||
id="path7728"
|
||||
d="M 1.3053582,4.1775838 L 5.6537466,0.21974226"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.8;marker-start:none;marker-end:none;stroke-linecap:round" />
|
||||
</g>
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Lstart"
|
||||
orient="auto"
|
||||
refY="0.0"
|
||||
refX="0.0"
|
||||
id="Arrow1Lstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path7764"
|
||||
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
|
||||
transform="scale(0.8)" />
|
||||
</marker>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3964">
|
||||
<stop
|
||||
style="stop-color:#00eb00;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3966" />
|
||||
<stop
|
||||
style="stop-color:#00eb00;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3968" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3964"
|
||||
id="radialGradient3996"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.237347,4.901628e-13,36.5688)"
|
||||
cx="176.99219"
|
||||
cy="47.949429"
|
||||
fx="176.99219"
|
||||
fy="47.949429"
|
||||
r="78.257812" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient12743"
|
||||
id="radialGradient12751"
|
||||
cx="165.91866"
|
||||
cy="45.584854"
|
||||
fx="165.91866"
|
||||
fy="45.584854"
|
||||
r="56.51194"
|
||||
gradientTransform="matrix(1,0,0,0.603517,0,18.07364)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.9793956"
|
||||
inkscape:cx="372.32157"
|
||||
inkscape:cy="45"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g2335"
|
||||
inkscape:window-width="791"
|
||||
inkscape:window-height="581"
|
||||
inkscape:window-x="4"
|
||||
inkscape:window-y="48" />
|
||||
<metadata
|
||||
id="metadata1312">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<rect
|
||||
style="opacity:1;fill:#393be9;fill-opacity:1;stroke:#f18a00;stroke-width:5.65522385;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect3981"
|
||||
width="435.17825"
|
||||
height="78.666664"
|
||||
x="5.1747785"
|
||||
y="6"
|
||||
rx="29.141403"
|
||||
ry="20"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/logo.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<flowRoot
|
||||
transform="matrix(1.673678,0,0,1.673678,-141.8484,-37.12273)"
|
||||
style="font-size:47.99999774;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;fill:#faf599;fill-opacity:1;stroke:#f3bf33;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||
id="flowRoot3988"
|
||||
xml:space="preserve"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/logo.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"><flowRegion
|
||||
style="fill:url(#radialGradient3996);fill-opacity:1"
|
||||
id="flowRegion3990"><rect
|
||||
style="font-size:47.99999774;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;fill:#faf599;fill-opacity:1;stroke:#f3bf33;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||
y="18"
|
||||
x="94.666664"
|
||||
height="61.333332"
|
||||
width="321.33334"
|
||||
id="rect3992" /></flowRegion><flowPara
|
||||
id="flowPara7831">ut hash</flowPara></flowRoot> <rect
|
||||
style="opacity:1;fill:url(#radialGradient12751);fill-opacity:1.0;stroke:none;stroke-width:2.82532263;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect10995"
|
||||
width="113.02388"
|
||||
height="68.211792"
|
||||
x="109.40672"
|
||||
y="11.478957"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/logo.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<g
|
||||
id="g7808"
|
||||
transform="matrix(0.807859,0,0,0.807859,-140.848,9.677403)"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/logo.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<rect
|
||||
y="37.730064"
|
||||
x="382.39673"
|
||||
height="18.405188"
|
||||
width="23.206543"
|
||||
id="rect4882"
|
||||
style="opacity:1;fill:#9be5ea;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#d48c21;fill-opacity:0.97777776;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect4886"
|
||||
width="23.206543"
|
||||
height="18.405188"
|
||||
x="416.39673"
|
||||
y="37.730064" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path4890"
|
||||
d="M 372.60327,46.932658 L 381.39673,46.932658"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path4892"
|
||||
d="M 406.60327,46.932658 L 415.39673,46.932658"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<rect
|
||||
y="9.7300644"
|
||||
x="348.39673"
|
||||
height="18.405188"
|
||||
width="23.206543"
|
||||
id="rect4896"
|
||||
style="opacity:1;fill:#79c71a;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#f5e1a2;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect4898"
|
||||
width="23.206543"
|
||||
height="18.405188"
|
||||
x="382.39673"
|
||||
y="9.7300644" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 372.60327,18.932658 L 381.39673,18.932658"
|
||||
id="path4902"
|
||||
inkscape:connector-type="polyline" />
|
||||
<rect
|
||||
y="14.207111"
|
||||
x="318.45328"
|
||||
height="10.1194"
|
||||
width="10.1194"
|
||||
id="rect4906"
|
||||
style="opacity:1;fill:#1336e6;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path5789"
|
||||
d="M 328.57268,19.220474 L 347.39673,19.048081"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 328.57268,19.220474 L 347.39673,19.048081"
|
||||
id="path5795"
|
||||
inkscape:connector-type="polyline" />
|
||||
<rect
|
||||
y="37.789951"
|
||||
x="348.20978"
|
||||
height="18.405188"
|
||||
width="23.206543"
|
||||
id="rect5803"
|
||||
style="opacity:1;fill:#e5e5e5;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="42.267002"
|
||||
x="318.26633"
|
||||
height="10.1194"
|
||||
width="10.1194"
|
||||
id="rect5805"
|
||||
style="opacity:1;fill:#1336e6;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 328.38572,47.280365 L 347.20977,47.107972"
|
||||
id="path5807"
|
||||
inkscape:connector-type="polyline" />
|
||||
<rect
|
||||
style="opacity:1;fill:#ddf9ed;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect5809"
|
||||
width="23.206543"
|
||||
height="18.405188"
|
||||
x="348.20978"
|
||||
y="63.720913" />
|
||||
<rect
|
||||
style="opacity:1;fill:#1336e6;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect5811"
|
||||
width="10.1194"
|
||||
height="10.1194"
|
||||
x="318.26633"
|
||||
y="68.197968" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path5813"
|
||||
d="M 328.38572,73.211328 L 347.20977,73.038935"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path5833"
|
||||
d="M 323.47927,24.326511 L 323.35974,42.267002"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#2f29df;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path5835"
|
||||
d="M 323.32603,52.386402 L 323.32603,68.197968"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#2f29df;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path6716"
|
||||
d="M 429.08836,47.11641 L 394.37307,18.527349 L 394.37307,49.158485 L 359.65778,18.527349 L 359.65778,50.179523 L 359.65778,75.70547"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#f3bf33;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#StopM);marker-end:url(#Arrow1Send);stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g2335"
|
||||
transform="translate(0,-10)"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/logo_tag.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:18.43119621px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||
x="565.8512"
|
||||
y="50.633156"
|
||||
id="text2331"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2333"
|
||||
x="565.85119"
|
||||
y="50.633156">a hash table</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="565.8512"
|
||||
y="73.672151"
|
||||
id="tspan2361">for C structures</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 18 KiB |
@ -1,121 +0,0 @@
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XTHML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||
<title>uthash: a hash table for C structures</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="banner">
|
||||
<img src="banner.png" alt="uthash: a hash table for C structures" />
|
||||
</div> <!-- banner -->
|
||||
|
||||
<div id="topnav">
|
||||
<a href="http://github.com/troydhanson/uthash">GitHub page</a> >
|
||||
uthash home <!-- http://troydhanson.github.com/uthash/ -->
|
||||
|
||||
<a href="https://twitter.com/share" class="twitter-share-button" data-via="troydhanson">Tweet</a>
|
||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div id="mid">
|
||||
|
||||
<div id="nav">
|
||||
|
||||
<h2>documentation</h2>
|
||||
<div><a href="userguide.html">uthash</a></div>
|
||||
<div><a href="utlist.html">utlist</a></div>
|
||||
<div><a href="utarray.html">utarray</a></div>
|
||||
<div><a href="utringbuffer.html">utringbuffer</a></div>
|
||||
<div><a href="utstring.html">utstring</a></div>
|
||||
|
||||
<h2>download</h2>
|
||||
<h3>GNU/Linux, Windows</h3>
|
||||
<div><a href=https://github.com/troydhanson/uthash/archive/master.zip>uthash-master.zip</a></div>
|
||||
<div><a href=https://github.com/troydhanson/uthash>git clone</a></div>
|
||||
|
||||
<h2>license</h2>
|
||||
<div><a href="license.html">BSD revised</a></div>
|
||||
|
||||
|
||||
<h2>developer</h2>
|
||||
<div><a href="http://troydhanson.github.io/">Troy D. Hanson</a></div>
|
||||
|
||||
<h2>maintainer</h2>
|
||||
<div><a href="https://github.com/Quuxplusone">Arthur O'Dwyer</a></div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div id="main">
|
||||
Any C structure can be stored in a hash table using uthash. Just add a
|
||||
<em>UT_hash_handle</em> to the structure and choose one or more fields
|
||||
in your structure to act as the key. Then use these macros to store,
|
||||
retrieve or delete items from the hash table.
|
||||
|
||||
<div class="listing">
|
||||
Example 1. Adding an item to a hash.
|
||||
<div class="code">
|
||||
<pre>
|
||||
#include "uthash.h"
|
||||
|
||||
struct my_struct {
|
||||
int id; /* we'll use this field as the key */
|
||||
char name[10];
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
};
|
||||
|
||||
struct my_struct *users = NULL;
|
||||
|
||||
void add_user(struct my_struct *s) {
|
||||
HASH_ADD_INT( users, id, s );
|
||||
}
|
||||
|
||||
</pre>
|
||||
</div> <!-- code -->
|
||||
</div> <!-- listing -->
|
||||
|
||||
<div class="listing">
|
||||
Example 2. Looking up an item in a hash.
|
||||
<div class="code">
|
||||
<pre>
|
||||
struct my_struct *find_user(int user_id) {
|
||||
struct my_struct *s;
|
||||
|
||||
HASH_FIND_INT( users, &user_id, s );
|
||||
return s;
|
||||
}
|
||||
|
||||
</pre>
|
||||
</div> <!-- code -->
|
||||
</div> <!-- listing -->
|
||||
|
||||
<div class="listing">
|
||||
Example 3. Deleting an item from a hash.
|
||||
<div class="code">
|
||||
|
||||
<pre>
|
||||
void delete_user(struct my_struct *user) {
|
||||
HASH_DEL( users, user);
|
||||
}
|
||||
|
||||
</pre>
|
||||
</div> <!-- code -->
|
||||
</div> <!-- listing -->
|
||||
|
||||
For more information and examples, please see the <a href="userguide.html">User Guide.</a>
|
||||
|
||||
</div> <!-- main -->
|
||||
</div> <!-- mid -->
|
||||
|
||||
<hr />
|
||||
<div id="footer">
|
||||
</div> <!-- footer -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 689 B |
@ -1,141 +0,0 @@
|
||||
#banner {
|
||||
/* font-size: x-large; */
|
||||
/* background: #ff00ff; */
|
||||
/* height: 100px; */
|
||||
}
|
||||
|
||||
#topnav {
|
||||
/* background-image: url(img/grad_topnav.png); */
|
||||
/* background-repeat: repeat-y; */
|
||||
/* background-color: #af00af; */
|
||||
/* height: 25px; */
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
padding: 3px;
|
||||
font-size: 9pt;
|
||||
font-family: sans-serif;
|
||||
/* border-style: solid; */
|
||||
/* border-width: 1px; */
|
||||
}
|
||||
|
||||
#topnav a {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
h1,p { margin: 0; } /* non-0 margin on firefox */
|
||||
|
||||
#mid {
|
||||
/* background-image: url(img/grad_blue.png); */
|
||||
background-repeat: repeat-y;
|
||||
/* background-color: #ffddaa; */
|
||||
padding-top: 20px;
|
||||
padding-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#mid img {
|
||||
padding-left: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: 0
|
||||
}
|
||||
|
||||
.twitter-share-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.twitter-follow-button {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#nav {
|
||||
background-color: #fff8f1;
|
||||
margin-left: 10px;
|
||||
margin-top: 20px;
|
||||
margin-right: 20px;
|
||||
float: left;
|
||||
padding: 10px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
|
||||
#nav h2 {
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#nav h3 {
|
||||
/* font-weight: bold; */
|
||||
padding-left: 5px;
|
||||
/* font-style: oblique; */
|
||||
font-family: sans-serif;
|
||||
font-size: 7pt;
|
||||
}
|
||||
|
||||
#nav div {
|
||||
font-size: 9pt;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
#main {
|
||||
background: #ffffff;
|
||||
margin-top: 20px;
|
||||
margin-left: 170px;
|
||||
padding-left: 20px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#main h1 {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.listing {
|
||||
margin: 20px;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.code {
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
font-size: 8pt;
|
||||
font-weight: normal;
|
||||
background: #f3f3f3;
|
||||
width: 100%;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
#footer {
|
||||
/* background: #00ffff; */
|
||||
margin-top: 5px;
|
||||
font-size: small;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 0.04em;
|
||||
background: black;
|
||||
margin: 0 10% 0 0;
|
||||
}
|
||||
|
||||
#footer {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#footer img {
|
||||
margin-right: 5px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#footer #support {
|
||||
float: right;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 80%;
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
uthash User Guide
|
||||
=================
|
||||
Troy D. Hanson, Arthur O'Dwyer
|
||||
v2.0.2, March 2017
|
||||
v2.1.0, December 2018
|
||||
|
||||
To download uthash, follow this link back to the
|
||||
https://github.com/troydhanson/uthash[GitHub project page].
|
||||
Back to my https://troydhanson.github.io[other projects].
|
||||
Back to my https://troydhanson.github.io/[other projects].
|
||||
|
||||
A hash in C
|
||||
-----------
|
||||
@ -230,8 +230,8 @@ last parameter is a pointer to the structure being added.
|
||||
.Wait.. the field name is a parameter?
|
||||
*******************************************************************************
|
||||
If you find it strange that `id`, which is the 'name of a field' in the
|
||||
structure, can be passed as a parameter, welcome to the world of macros. Don't
|
||||
worry- the C preprocessor expands this to valid C code.
|
||||
structure, can be passed as a parameter... welcome to the world of macros. Don't
|
||||
worry; the C preprocessor expands this to valid C code.
|
||||
*******************************************************************************
|
||||
|
||||
Key must not be modified while in-use
|
||||
@ -257,7 +257,7 @@ Otherwise we just modify the structure that already exists.
|
||||
|
||||
HASH_FIND_INT(users, &user_id, s); /* id already in the hash? */
|
||||
if (s==NULL) {
|
||||
s = (struct my_struct*)malloc(sizeof(struct my_struct));
|
||||
s = (struct my_struct *)malloc(sizeof *s);
|
||||
s->id = user_id;
|
||||
HASH_ADD_INT( users, id, s ); /* id: name of key field */
|
||||
}
|
||||
@ -534,7 +534,7 @@ void add_user(int user_id, char *name) {
|
||||
|
||||
HASH_FIND_INT(users, &user_id, s); /* id already in the hash? */
|
||||
if (s==NULL) {
|
||||
s = (struct my_struct*)malloc(sizeof(struct my_struct));
|
||||
s = (struct my_struct *)malloc(sizeof *s);
|
||||
s->id = user_id;
|
||||
HASH_ADD_INT( users, id, s ); /* id: name of key field */
|
||||
}
|
||||
@ -713,14 +713,13 @@ struct my_struct {
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char **n, *names[] = { "joe", "bob", "betty", NULL };
|
||||
const char *names[] = { "joe", "bob", "betty", NULL };
|
||||
struct my_struct *s, *tmp, *users = NULL;
|
||||
int i=0;
|
||||
|
||||
for (n = names; *n != NULL; n++) {
|
||||
s = (struct my_struct*)malloc(sizeof(struct my_struct));
|
||||
strncpy(s->name, *n,10);
|
||||
s->id = i++;
|
||||
for (int i = 0; names[i]; ++i) {
|
||||
s = (struct my_struct *)malloc(sizeof *s);
|
||||
strcpy(s->name, names[i]);
|
||||
s->id = i;
|
||||
HASH_ADD_STR( users, name, s );
|
||||
}
|
||||
|
||||
@ -760,14 +759,13 @@ struct my_struct {
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char **n, *names[] = { "joe", "bob", "betty", NULL };
|
||||
const char *names[] = { "joe", "bob", "betty", NULL };
|
||||
struct my_struct *s, *tmp, *users = NULL;
|
||||
int i=0;
|
||||
|
||||
for (n = names; *n != NULL; n++) {
|
||||
s = (struct my_struct*)malloc(sizeof(struct my_struct));
|
||||
s->name = *n;
|
||||
s->id = i++;
|
||||
for (int i = 0; names[i]; ++i) {
|
||||
s = (struct my_struct *)malloc(sizeof *s);
|
||||
s->name = names[i];
|
||||
s->id = i;
|
||||
HASH_ADD_KEYPTR( hh, users, s->name, strlen(s->name), s );
|
||||
}
|
||||
|
||||
@ -810,7 +808,7 @@ char *someaddr = NULL;
|
||||
|
||||
int main() {
|
||||
el_t *d;
|
||||
el_t *e = (el_t*)malloc(sizeof(el_t));
|
||||
el_t *e = (el_t *)malloc(sizeof *e);
|
||||
if (!e) return -1;
|
||||
e->key = (void*)someaddr;
|
||||
e->i = 1;
|
||||
@ -861,8 +859,8 @@ typedef struct {
|
||||
int main(int argc, char *argv[]) {
|
||||
record_t l, *p, *r, *tmp, *records = NULL;
|
||||
|
||||
r = (record_t*)malloc( sizeof(record_t) );
|
||||
memset(r, 0, sizeof(record_t));
|
||||
r = (record_t *)malloc(sizeof *r);
|
||||
memset(r, 0, sizeof *r);
|
||||
r->key.a = 'a';
|
||||
r->key.b = 1;
|
||||
HASH_ADD(hh, records, key, sizeof(record_key_t), r);
|
||||
@ -926,7 +924,7 @@ int main(int argc, char *argv[]) {
|
||||
int beijing[] = {0x5317, 0x4eac}; /* UTF-32LE for 北京 */
|
||||
|
||||
/* allocate and initialize our structure */
|
||||
msg = (msg_t*)malloc( sizeof(msg_t) + sizeof(beijing) );
|
||||
msg = (msg_t *)malloc( sizeof(msg_t) + sizeof(beijing) );
|
||||
memset(msg, 0, sizeof(msg_t)+sizeof(beijing)); /* zero fill */
|
||||
msg->len = sizeof(beijing);
|
||||
msg->encoding = UTF32;
|
||||
@ -943,7 +941,7 @@ int main(int argc, char *argv[]) {
|
||||
/* look it up to prove that it worked :-) */
|
||||
msg=NULL;
|
||||
|
||||
lookup_key = (lookup_key_t*)malloc(sizeof(*lookup_key) + sizeof(beijing));
|
||||
lookup_key = (lookup_key_t *)malloc(sizeof(*lookup_key) + sizeof(beijing));
|
||||
memset(lookup_key, 0, sizeof(*lookup_key) + sizeof(beijing));
|
||||
lookup_key->encoding = UTF32;
|
||||
memcpy(lookup_key->text, beijing, sizeof(beijing));
|
||||
@ -968,6 +966,7 @@ by an `int` will normally have 3 "wasted" bytes of padding after the char, in
|
||||
order to make the `int` field start on a multiple-of-4 address (4 is the length
|
||||
of the int).
|
||||
|
||||
[[multifield_note]]
|
||||
.Calculating the length of a multi-field key:
|
||||
*******************************************************************************
|
||||
To determine the key length when using a multi-field key, you must include any
|
||||
@ -992,6 +991,10 @@ didn't zero-fill the structure, this padding would contain random values. The
|
||||
random values would lead to `HASH_FIND` failures; as two "identical" keys will
|
||||
appear to mismatch if there are any differences within their padding.
|
||||
|
||||
Alternatively, you can customize the global <<hash_keycompare,key comparison function>>
|
||||
and <<hash_functions,key hashing function>> to ignore the padding in your key.
|
||||
See <<hash_keycompare,Specifying an alternate key comparison function>>.
|
||||
|
||||
[[multilevel]]
|
||||
Multi-level hash tables
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -1072,7 +1075,7 @@ Items in several hash tables
|
||||
A structure can be added to more than one hash table. A few reasons you might do
|
||||
this include:
|
||||
|
||||
- each hash table may use an alternative key;
|
||||
- each hash table may use a different key;
|
||||
- each hash table may have its own sort order;
|
||||
- or you might simply use multiple hash tables for grouping purposes. E.g.,
|
||||
you could have users in an `admin_users` and a `users` hash table.
|
||||
@ -1082,19 +1085,19 @@ which it might be added. You can name them anything. E.g.,
|
||||
|
||||
UT_hash_handle hh1, hh2;
|
||||
|
||||
Items with alternative keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Items with multiple keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
You might create a hash table keyed on an ID field, and another hash table keyed
|
||||
on username (if usernames are unique). You can add the same user structure to
|
||||
both hash tables (without duplication of the structure), allowing lookup of a
|
||||
user structure by their name or ID. The way to achieve this is to have a
|
||||
separate `UT_hash_handle` for each hash to which the structure may be added.
|
||||
|
||||
.A structure with two alternative keys
|
||||
.A structure with two different keys
|
||||
----------------------------------------------------------------------
|
||||
struct my_struct {
|
||||
int id; /* usual key */
|
||||
char username[10]; /* alternative key */
|
||||
int id; /* first key */
|
||||
char username[10]; /* second key */
|
||||
UT_hash_handle hh1; /* handle for first hash table */
|
||||
UT_hash_handle hh2; /* handle for second hash table */
|
||||
};
|
||||
@ -1124,12 +1127,12 @@ always used with the `users_by_name` hash table).
|
||||
HASH_ADD(hh1, users_by_id, id, sizeof(int), s);
|
||||
HASH_ADD(hh2, users_by_name, username, strlen(s->username), s);
|
||||
|
||||
/* lookup user by ID in the "users_by_id" hash table */
|
||||
/* find user by ID in the "users_by_id" hash table */
|
||||
i=1;
|
||||
HASH_FIND(hh1, users_by_id, &i, sizeof(int), s);
|
||||
if (s) printf("found id %d: %s\n", i, s->username);
|
||||
|
||||
/* lookup user by username in the "users_by_name" hash table */
|
||||
/* find user by username in the "users_by_name" hash table */
|
||||
name = "thanson";
|
||||
HASH_FIND(hh2, users_by_name, name, strlen(name), s);
|
||||
if (s) printf("found user %s: %d\n", name, s->id);
|
||||
@ -1171,7 +1174,7 @@ ways. This is based on the ability to store a structure in several hash tables.
|
||||
|
||||
Extending the previous example, suppose we have many users. We have added each
|
||||
user structure to the `users_by_id` hash table and the `users_by_name` hash table.
|
||||
(To reiterate, this is done without the need to have two copies of each structure).
|
||||
(To reiterate, this is done without the need to have two copies of each structure.)
|
||||
Now we can define two sort functions, then use `HASH_SRT`.
|
||||
|
||||
int sort_by_id(struct my_struct *a, struct my_struct *b) {
|
||||
@ -1269,12 +1272,67 @@ items to the destination hash selectively.
|
||||
The two hash handles must differ. An example of using `HASH_SELECT` is included
|
||||
in `tests/test36.c`.
|
||||
|
||||
[[hash_keycompare]]
|
||||
Specifying an alternate key comparison function
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When you call `HASH_FIND(hh, head, intfield, sizeof(int), out)`, uthash will
|
||||
first call <<hash_functions,`HASH_FUNCTION`>>`(intfield, sizeof(int), hashvalue)` to
|
||||
determine the bucket `b` in which to search, and then, for each element `elt`
|
||||
of bucket `b`, uthash will evaluate
|
||||
`elt->hh.hashv == hashvalue && elt.hh.keylen == sizeof(int) && HASH_KEYCMP(intfield, elt->hh.key, sizeof(int)) == 0`.
|
||||
`HASH_KEYCMP` should return `0` to indicate that `elt` is a match and should be
|
||||
returned, and any non-zero value to indicate that the search for a matching
|
||||
element should continue.
|
||||
|
||||
By default, uthash defines `HASH_KEYCMP` as an alias for `memcmp`. On platforms
|
||||
that do not provide `memcmp`, you can substitute your own implementation.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#undef HASH_KEYCMP
|
||||
#define HASH_KEYCMP(a,b,len) bcmp(a,b,len)
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Another reason to substitute your own key comparison function is if your "key" is not
|
||||
trivially comparable. In this case you will also need to substitute your own `HASH_FUNCTION`.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
struct Key {
|
||||
short s;
|
||||
/* 2 bytes of padding */
|
||||
float f;
|
||||
};
|
||||
/* do not compare the padding bytes; do not use memcmp on floats */
|
||||
unsigned key_hash(struct Key *s) { return s + (unsigned)f; }
|
||||
bool key_equal(struct Key *a, struct Key *b) { return a.s == b.s && a.f == b.f; }
|
||||
|
||||
#define HASH_FUNCTION(s,len,hashv) (hashv) = key_hash((struct Key *)s)
|
||||
#define HASH_KEYCMP(a,b,len) (!key_equal((struct Key *)a, (struct Key *)b))
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Another reason to substitute your own key comparison function is to trade off
|
||||
correctness for raw speed. During its linear search of a bucket, uthash always
|
||||
compares the 32-bit `hashv` first, and calls `HASH_KEYCMP` only if the `hashv`
|
||||
compares equal. This means that `HASH_KEYCMP` is called at least once per
|
||||
successful find. Given a good hash function, we expect the `hashv` comparison to
|
||||
produce a "false positive" equality only once in four billion times. Therefore,
|
||||
we expect `HASH_KEYCMP` to produce `0` most of the time. If we expect many
|
||||
successful finds, and our application doesn't mind the occasional false positive,
|
||||
we might substitute a no-op comparison function:
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#undef HASH_KEYCMP
|
||||
#define HASH_KEYCMP(a,b,len) 0 /* occasionally wrong, but very fast */
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Note: The global equality-comparison function `HASH_KEYCMP` has no relationship
|
||||
at all to the lessthan-comparison function passed as a parameter to `HASH_ADD_INORDER`.
|
||||
|
||||
[[hash_functions]]
|
||||
Built-in hash functions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Internally, a hash function transforms a key into a bucket number. You don't
|
||||
have to take any action to use the default hash function, currently Jenkin's.
|
||||
have to take any action to use the default hash function, currently Jenkins.
|
||||
|
||||
Some programs may benefit from using another of the built-in hash functions.
|
||||
There is a simple analysis utility included with uthash to help you determine
|
||||
@ -1296,17 +1354,8 @@ below. E.g.,
|
||||
|OAT | One-at-a-time
|
||||
|FNV | Fowler/Noll/Vo
|
||||
|SFH | Paul Hsieh
|
||||
|MUR | MurmurHash v3 (see note)
|
||||
|===============================================================================
|
||||
|
||||
[NOTE]
|
||||
.MurmurHash
|
||||
================================================================================
|
||||
A special symbol must be defined if you intend to use MurmurHash. To use it, add
|
||||
`-DHASH_USING_NO_STRICT_ALIASING` to your `CFLAGS`. And, if you are using
|
||||
the gcc compiler with optimization, add `-fno-strict-aliasing` to your `CFLAGS`.
|
||||
================================================================================
|
||||
|
||||
Which hash function is best?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
You can easily determine the best hash function for your key domain. To do so,
|
||||
@ -1531,6 +1580,31 @@ inhibited' flag remains in effect as long as the hash has items in it.
|
||||
Inhibited expansion may cause `HASH_FIND` to exhibit worse than constant-time
|
||||
performance.
|
||||
|
||||
Diagnostic hooks
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
There are two "notification" hooks which get executed if uthash is
|
||||
expanding buckets, or setting the 'bucket expansion inhibited' flag.
|
||||
There is no need for the application to set these hooks or take action in
|
||||
response to these events. They are mainly for diagnostic purposes.
|
||||
Normally both of these hooks are undefined and thus compile away to nothing.
|
||||
|
||||
The `uthash_expand_fyi` hook can be defined to execute code whenever
|
||||
uthash performs a bucket expansion.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#undef uthash_expand_fyi
|
||||
#define uthash_expand_fyi(tbl) printf("expanded to %u buckets\n", tbl->num_buckets)
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
The `uthash_noexpand_fyi` hook can be defined to execute code whenever
|
||||
uthash sets the 'bucket expansion inhibited' flag.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#undef uthash_noexpand_fyi
|
||||
#define uthash_noexpand_fyi(tbl) printf("warning: bucket expansion inhibited\n")
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Hooks
|
||||
~~~~~
|
||||
You don't need to use these hooks -- they are only here if you want to modify
|
||||
@ -1545,8 +1619,8 @@ example, by passing `-Duthash_malloc=my_malloc` on the command line.
|
||||
|
||||
Specifying alternate memory management functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
By default this hash implementation uses `malloc` and `free` to manage memory.
|
||||
If your application uses its own custom allocator, this hash can use them too.
|
||||
By default, uthash uses `malloc` and `free` to manage memory.
|
||||
If your application uses its own custom allocator, uthash can use them too.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#include "uthash.h"
|
||||
@ -1568,26 +1642,22 @@ convenience on embedded platforms that manage their own memory.
|
||||
Specifying alternate standard library functions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Uthash also uses `strlen` (in the `HASH_FIND_STR` convenience macro, for
|
||||
example), `memcmp` (as the method of comparing keys for equality), and `memset`
|
||||
(used only for zeroing memory). On platforms that do not provide these functions,
|
||||
you can substitute your own implementations.
|
||||
example) and `memset` (used only for zeroing memory). On platforms that do not
|
||||
provide these functions, you can substitute your own implementations.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#undef uthash_bzero
|
||||
#define uthash_bzero(a,len) my_bzero(a,len)
|
||||
|
||||
#undef uthash_memcmp
|
||||
#define uthash_memcmp(a,b,len) my_memcmp(a,b,len)
|
||||
|
||||
#undef uthash_strlen
|
||||
#define uthash_strlen(s) my_strlen(s)
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Out of memory
|
||||
^^^^^^^^^^^^^
|
||||
If memory allocation fails (i.e., the malloc function returned `NULL`), the
|
||||
default behavior is to terminate the process by calling `exit(-1)`. This can
|
||||
be modified by re-defining the `uthash_fatal` macro.
|
||||
If memory allocation fails (i.e., the `uthash_malloc` function returns `NULL`),
|
||||
the default behavior is to terminate the process by calling `exit(-1)`. This
|
||||
can be modified by re-defining the `uthash_fatal` macro.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#undef uthash_fatal
|
||||
@ -1595,36 +1665,36 @@ be modified by re-defining the `uthash_fatal` macro.
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
The fatal function should terminate the process or `longjmp` back to a safe
|
||||
place. Uthash does not support "returning a failure" if memory cannot be
|
||||
allocated.
|
||||
place. Note that an allocation failure may leave allocated memory that cannot
|
||||
be recovered. After `uthash_fatal`, the hash table object should be considered
|
||||
unusable; it might not be safe even to run `HASH_CLEAR` on the hash table
|
||||
when it is in this state.
|
||||
|
||||
Internal events
|
||||
^^^^^^^^^^^^^^^
|
||||
There is no need for the application to set these hooks or take action in
|
||||
response to these events. They are mainly for diagnostic purposes.
|
||||
|
||||
These two hooks are "notification" hooks which get executed if uthash is
|
||||
expanding buckets, or setting the 'bucket expansion inhibited' flag. Normally
|
||||
both of these hooks are undefined and thus compile away to nothing.
|
||||
|
||||
Expansion
|
||||
+++++++++
|
||||
There is a hook for the bucket expansion event.
|
||||
To enable "returning a failure" if memory cannot be allocated, define the
|
||||
macro `HASH_NONFATAL_OOM` before including the `uthash.h` header file. In this
|
||||
case, `uthash_fatal` is not used; instead, each allocation failure results in
|
||||
a single call to `uthash_nonfatal_oom(elt)` where `elt` is the address of the
|
||||
element whose insertion triggered the failure. The default behavior of
|
||||
`uthash_nonfatal_oom` is a no-op.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#undef uthash_expand_fyi
|
||||
#define uthash_expand_fyi(tbl) printf("expanded to %d buckets\n", tbl->num_buckets)
|
||||
#undef uthash_nonfatal_oom
|
||||
#define uthash_nonfatal_oom(elt) perhaps_recover((element_t *) elt)
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Expansion-inhibition
|
||||
++++++++++++++++++++
|
||||
This hook can be defined to code to execute in the event that uthash decides to
|
||||
set the 'bucket expansion inhibited' flag.
|
||||
Before the call to `uthash_nonfatal_oom`, the hash table is rolled back
|
||||
to the state it was in prior to the problematic insertion; no memory is
|
||||
leaked. It is safe to `throw` or `longjmp` out of the `uthash_nonfatal_oom`
|
||||
handler.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#undef uthash_noexpand_fyi
|
||||
#define uthash_noexpand_fyi printf("warning: bucket expansion inhibited\n")
|
||||
----------------------------------------------------------------------------
|
||||
The `elt` argument will be of the correct pointer-to-element type, unless
|
||||
`uthash_nonfatal_oom` is invoked from `HASH_SELECT`, in which case it will
|
||||
be of `void*` type and must be cast before using. In any case, `elt->hh.tbl`
|
||||
will be `NULL`.
|
||||
|
||||
Allocation failure is possible only when adding elements to the hash table
|
||||
(including the `ADD`, `REPLACE`, and `SELECT` operations).
|
||||
`uthash_free` is not allowed to fail.
|
||||
|
||||
Debug mode
|
||||
~~~~~~~~~~
|
||||
@ -1750,21 +1820,21 @@ than `hh`, or if your key's data type isn't `int` or `char[]`.
|
||||
|===============================================================================
|
||||
|macro | arguments
|
||||
|HASH_ADD | (hh_name, head, keyfield_name, key_len, item_ptr)
|
||||
|HASH_ADD_BYHASHVALUE | (hh_name, head, keyfield_name, key_len, key_hash, item_ptr)
|
||||
|HASH_ADD_BYHASHVALUE | (hh_name, head, keyfield_name, key_len, hashv, item_ptr)
|
||||
|HASH_ADD_KEYPTR | (hh_name, head, key_ptr, key_len, item_ptr)
|
||||
|HASH_ADD_KEYPTR_BYHASHVALUE | (hh_name, head, key_ptr, key_len, key_hash, item_ptr)
|
||||
|HASH_ADD_KEYPTR_BYHASHVALUE | (hh_name, head, key_ptr, key_len, hashv, item_ptr)
|
||||
|HASH_ADD_INORDER | (hh_name, head, keyfield_name, key_len, item_ptr, cmp)
|
||||
|HASH_ADD_BYHASHVALUE_INORDER | (hh_name, head, keyfield_name, key_len, key_hash, item_ptr, cmp)
|
||||
|HASH_ADD_BYHASHVALUE_INORDER | (hh_name, head, keyfield_name, key_len, hashv, item_ptr, cmp)
|
||||
|HASH_ADD_KEYPTR_INORDER | (hh_name, head, key_ptr, key_len, item_ptr, cmp)
|
||||
|HASH_ADD_KEYPTR_BYHASHVALUE_INORDER | (hh_name, head, key_ptr, key_len, key_hash, item_ptr, cmp)
|
||||
|HASH_ADD_KEYPTR_BYHASHVALUE_INORDER | (hh_name, head, key_ptr, key_len, hashv, item_ptr, cmp)
|
||||
|HASH_REPLACE | (hh_name, head, keyfield_name, key_len, item_ptr, replaced_item_ptr)
|
||||
|HASH_REPLACE_BYHASHVALUE | (hh_name, head, keyfield_name, key_len, key_hash, item_ptr, replaced_item_ptr)
|
||||
|HASH_REPLACE_BYHASHVALUE | (hh_name, head, keyfield_name, key_len, hashv, item_ptr, replaced_item_ptr)
|
||||
|HASH_REPLACE_INORDER | (hh_name, head, keyfield_name, key_len, item_ptr, replaced_item_ptr, cmp)
|
||||
|HASH_REPLACE_BYHASHVALUE_INORDER | (hh_name, head, keyfield_name, key_len, key_hash, item_ptr, replaced_item_ptr, cmp)
|
||||
|HASH_REPLACE_BYHASHVALUE_INORDER | (hh_name, head, keyfield_name, key_len, hashv, item_ptr, replaced_item_ptr, cmp)
|
||||
|HASH_FIND | (hh_name, head, key_ptr, key_len, item_ptr)
|
||||
|HASH_FIND_BYHASHVALUE | (hh_name, head, key_ptr, key_len, key_hash, item_ptr)
|
||||
|HASH_FIND_BYHASHVALUE | (hh_name, head, key_ptr, key_len, hashv, item_ptr)
|
||||
|HASH_DELETE | (hh_name, head, item_ptr)
|
||||
|HASH_VALUE | (key_ptr, key_len, key_hash)
|
||||
|HASH_VALUE | (key_ptr, key_len, hashv)
|
||||
|HASH_SRT | (hh_name, head, cmp)
|
||||
|HASH_CNT | (hh_name, head)
|
||||
|HASH_CLEAR | (hh_name, head)
|
||||
@ -1799,12 +1869,12 @@ keyfield_name::
|
||||
key_len::
|
||||
the length of the key field in bytes. E.g. for an integer key, this is
|
||||
`sizeof(int)`, while for a string key it's `strlen(key)`. (For a
|
||||
multi-field key, see the notes in this guide on calculating key length).
|
||||
multi-field key, see <<multifield_note,this note>>.)
|
||||
key_ptr::
|
||||
for `HASH_FIND`, this is a pointer to the key to look up in the hash
|
||||
(since it's a pointer, you can't directly pass a literal value here). For
|
||||
`HASH_ADD_KEYPTR`, this is the address of the key of the item being added.
|
||||
key_hash::
|
||||
hashv::
|
||||
the hash value of the provided key. This is an input parameter for the
|
||||
`..._BYHASHVALUE` macros, and an output parameter for `HASH_VALUE`.
|
||||
Reusing a cached hash value can be a performance optimization if
|
||||
@ -1823,9 +1893,9 @@ cmp::
|
||||
items to compare) and returns an int specifying whether the first item
|
||||
should sort before, equal to, or after the second item (like `strcmp`).
|
||||
condition::
|
||||
a function or macro which accepts a single argument-- a void pointer to a
|
||||
structure, which needs to be cast to the appropriate structure type. The
|
||||
function or macro should return (or evaluate to) a non-zero value if the
|
||||
a function or macro which accepts a single argument (a void pointer to a
|
||||
structure, which needs to be cast to the appropriate structure type). The
|
||||
function or macro should evaluate to a non-zero value if the
|
||||
structure should be "selected" for addition to the destination hash.
|
||||
|
||||
// vim: set tw=80 wm=2 syntax=asciidoc:
|
||||
|
||||
@ -1,374 +0,0 @@
|
||||
utarray: dynamic array macros for C
|
||||
===================================
|
||||
Troy D. Hanson <tdh@tkhanson.net>
|
||||
v2.0.2, March 2017
|
||||
|
||||
Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page].
|
||||
|
||||
Introduction
|
||||
------------
|
||||
A set of general-purpose dynamic array macros for C structures are included with
|
||||
uthash in `utarray.h`. To use these macros in your own C program, just
|
||||
copy `utarray.h` into your source directory and use it in your programs.
|
||||
|
||||
#include "utarray.h"
|
||||
|
||||
The dynamic array supports basic operations such as push, pop, and erase on the
|
||||
array elements. These array elements can be any simple datatype or structure.
|
||||
The array <<operations,operations>> are based loosely on the C++ STL vector methods.
|
||||
|
||||
Internally the dynamic array contains a contiguous memory region into which
|
||||
the elements are copied. This buffer is grown as needed using `realloc` to
|
||||
accommodate all the data that is pushed into it.
|
||||
|
||||
Download
|
||||
~~~~~~~~
|
||||
To download the `utarray.h` header file,
|
||||
follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file,
|
||||
then look in the src/ sub-directory.
|
||||
|
||||
BSD licensed
|
||||
~~~~~~~~~~~~
|
||||
This software is made available under the
|
||||
link:license.html[revised BSD license].
|
||||
It is free and open source.
|
||||
|
||||
Platforms
|
||||
~~~~~~~~~
|
||||
The 'utarray' macros have been tested on:
|
||||
|
||||
* Linux,
|
||||
* Mac OS X,
|
||||
* Windows, using Visual Studio 2008 and Visual Studio 2010
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Declaration
|
||||
~~~~~~~~~~~
|
||||
|
||||
The array itself has the data type `UT_array`, regardless of the type of
|
||||
elements to be stored in it. It is declared like,
|
||||
|
||||
UT_array *nums;
|
||||
|
||||
New and free
|
||||
~~~~~~~~~~~~
|
||||
The next step is to create the array using `utarray_new`. Later when you're
|
||||
done with the array, `utarray_free` will free it and all its elements.
|
||||
|
||||
Push, pop, etc
|
||||
~~~~~~~~~~~~~~
|
||||
The central features of the utarray involve putting elements into it, taking
|
||||
them out, and iterating over them. There are several <<operations,operations>>
|
||||
to pick from that deal with either single elements or ranges of elements at a
|
||||
time. In the examples below we will use only the push operation to insert
|
||||
elements.
|
||||
|
||||
Elements
|
||||
--------
|
||||
|
||||
Support for dynamic arrays of integers or strings is especially easy. These are
|
||||
best shown by example:
|
||||
|
||||
Integers
|
||||
~~~~~~~~
|
||||
This example makes a utarray of integers, pushes 0-9 into it, then prints it.
|
||||
Lastly it frees it.
|
||||
|
||||
.Integer elements
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utarray.h"
|
||||
|
||||
int main() {
|
||||
UT_array *nums;
|
||||
int i, *p;
|
||||
|
||||
utarray_new(nums,&ut_int_icd);
|
||||
for(i=0; i < 10; i++) utarray_push_back(nums,&i);
|
||||
|
||||
for(p=(int*)utarray_front(nums);
|
||||
p!=NULL;
|
||||
p=(int*)utarray_next(nums,p)) {
|
||||
printf("%d\n",*p);
|
||||
}
|
||||
|
||||
utarray_free(nums);
|
||||
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The second argument to `utarray_push_back` is always a 'pointer' to the type
|
||||
(so a literal cannot be used). So for integers, it is an `int*`.
|
||||
|
||||
Strings
|
||||
~~~~~~~
|
||||
In this example we make a utarray of strings, push two strings into it, print
|
||||
it and free it.
|
||||
|
||||
.String elements
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utarray.h"
|
||||
|
||||
int main() {
|
||||
UT_array *strs;
|
||||
char *s, **p;
|
||||
|
||||
utarray_new(strs,&ut_str_icd);
|
||||
|
||||
s = "hello"; utarray_push_back(strs, &s);
|
||||
s = "world"; utarray_push_back(strs, &s);
|
||||
p = NULL;
|
||||
while ( (p=(char**)utarray_next(strs,p))) {
|
||||
printf("%s\n",*p);
|
||||
}
|
||||
|
||||
utarray_free(strs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
In this example, since the element is a `char*`, we pass a pointer to it
|
||||
(`char**`) as the second argument to `utarray_push_back`. Note that "push" makes
|
||||
a copy of the source string and pushes that copy into the array.
|
||||
|
||||
About UT_icd
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Arrays be made of any type of element, not just integers and strings. The
|
||||
elements can be basic types or structures. Unless you're dealing with integers
|
||||
and strings (which use pre-defined `ut_int_icd` and `ut_str_icd`), you'll need
|
||||
to define a `UT_icd` helper structure. This structure contains everything that
|
||||
utarray needs to initialize, copy or destruct elements.
|
||||
|
||||
typedef struct {
|
||||
size_t sz;
|
||||
init_f *init;
|
||||
ctor_f *copy;
|
||||
dtor_f *dtor;
|
||||
} UT_icd;
|
||||
|
||||
The three function pointers `init`, `copy`, and `dtor` have these prototypes:
|
||||
|
||||
typedef void (ctor_f)(void *dst, const void *src);
|
||||
typedef void (dtor_f)(void *elt);
|
||||
typedef void (init_f)(void *elt);
|
||||
|
||||
The `sz` is just the size of the element being stored in the array.
|
||||
|
||||
The `init` function will be invoked whenever utarray needs to initialize an
|
||||
empty element. This only happens as a byproduct of `utarray_resize` or
|
||||
`utarray_extend_back`. If `init` is `NULL`, it defaults to zero filling the
|
||||
new element using memset.
|
||||
|
||||
The `copy` function is used whenever an element is copied into the array.
|
||||
It is invoked during `utarray_push_back`, `utarray_insert`, `utarray_inserta`,
|
||||
or `utarray_concat`. If `copy` is `NULL`, it defaults to a bitwise copy using
|
||||
memcpy.
|
||||
|
||||
The `dtor` function is used to clean up an element that is being removed from
|
||||
the array. It may be invoked due to `utarray_resize`, `utarray_pop_back`,
|
||||
`utarray_erase`, `utarray_clear`, `utarray_done` or `utarray_free`. If the
|
||||
elements need no cleanup upon destruction, `dtor` may be `NULL`.
|
||||
|
||||
Scalar types
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The next example uses `UT_icd` with all its defaults to make a utarray of
|
||||
`long` elements. This example pushes two longs, prints them, and frees the
|
||||
array.
|
||||
|
||||
.long elements
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utarray.h"
|
||||
|
||||
UT_icd long_icd = {sizeof(long), NULL, NULL, NULL };
|
||||
|
||||
int main() {
|
||||
UT_array *nums;
|
||||
long l, *p;
|
||||
utarray_new(nums, &long_icd);
|
||||
|
||||
l=1; utarray_push_back(nums, &l);
|
||||
l=2; utarray_push_back(nums, &l);
|
||||
|
||||
p=NULL;
|
||||
while( (p=(long*)utarray_next(nums,p))) printf("%ld\n", *p);
|
||||
|
||||
utarray_free(nums);
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Structures
|
||||
~~~~~~~~~~
|
||||
|
||||
Structures can be used as utarray elements. If the structure requires no
|
||||
special effort to initialize, copy or destruct, we can use `UT_icd` with all
|
||||
its defaults. This example shows a structure that consists of two integers. Here
|
||||
we push two values, print them and free the array.
|
||||
|
||||
.Structure (simple)
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utarray.h"
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
} intpair_t;
|
||||
|
||||
UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL};
|
||||
|
||||
int main() {
|
||||
|
||||
UT_array *pairs;
|
||||
intpair_t ip, *p;
|
||||
utarray_new(pairs,&intpair_icd);
|
||||
|
||||
ip.a=1; ip.b=2; utarray_push_back(pairs, &ip);
|
||||
ip.a=10; ip.b=20; utarray_push_back(pairs, &ip);
|
||||
|
||||
for(p=(intpair_t*)utarray_front(pairs);
|
||||
p!=NULL;
|
||||
p=(intpair_t*)utarray_next(pairs,p)) {
|
||||
printf("%d %d\n", p->a, p->b);
|
||||
}
|
||||
|
||||
utarray_free(pairs);
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The real utility of `UT_icd` is apparent when the elements of the utarray are
|
||||
structures that require special work to initialize, copy or destruct.
|
||||
|
||||
For example, when a structure contains pointers to related memory areas that
|
||||
need to be copied when the structure is copied (and freed when the structure is
|
||||
freed), we can use custom `init`, `copy`, and `dtor` members in the `UT_icd`.
|
||||
|
||||
Here we take an example of a structure that contains an integer and a string.
|
||||
When this element is copied (such as when an element is pushed into the array),
|
||||
we want to "deep copy" the `s` pointer (so the original element and the new
|
||||
element point to their own copies of `s`). When an element is destructed, we
|
||||
want to "deep free" its copy of `s`. Lastly, this example is written to work
|
||||
even if `s` has the value `NULL`.
|
||||
|
||||
.Structure (complex)
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "utarray.h"
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
char *s;
|
||||
} intchar_t;
|
||||
|
||||
void intchar_copy(void *_dst, const void *_src) {
|
||||
intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src;
|
||||
dst->a = src->a;
|
||||
dst->s = src->s ? strdup(src->s) : NULL;
|
||||
}
|
||||
|
||||
void intchar_dtor(void *_elt) {
|
||||
intchar_t *elt = (intchar_t*)_elt;
|
||||
if (elt->s) free(elt->s);
|
||||
}
|
||||
|
||||
UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor};
|
||||
|
||||
int main() {
|
||||
UT_array *intchars;
|
||||
intchar_t ic, *p;
|
||||
utarray_new(intchars, &intchar_icd);
|
||||
|
||||
ic.a=1; ic.s="hello"; utarray_push_back(intchars, &ic);
|
||||
ic.a=2; ic.s="world"; utarray_push_back(intchars, &ic);
|
||||
|
||||
p=NULL;
|
||||
while( (p=(intchar_t*)utarray_next(intchars,p))) {
|
||||
printf("%d %s\n", p->a, (p->s ? p->s : "null"));
|
||||
}
|
||||
|
||||
utarray_free(intchars);
|
||||
return 0;
|
||||
}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
[[operations]]
|
||||
Reference
|
||||
---------
|
||||
This table lists all the utarray operations. These are loosely based on the C++
|
||||
vector class.
|
||||
|
||||
Operations
|
||||
~~~~~~~~~~
|
||||
|
||||
[width="100%",cols="50<m,40<",grid="none",options="none"]
|
||||
|===============================================================================
|
||||
| utarray_new(UT_array *a, UT_icd *icd)| allocate a new array
|
||||
| utarray_free(UT_array *a) | free an allocated array
|
||||
| utarray_init(UT_array *a,UT_icd *icd)| init an array (non-alloc)
|
||||
| utarray_done(UT_array *a) | dispose of an array (non-allocd)
|
||||
| utarray_reserve(UT_array *a,int n) | ensure space available for 'n' more elements
|
||||
| utarray_push_back(UT_array *a,void *p) | push element p onto a
|
||||
| utarray_pop_back(UT_array *a) | pop last element from a
|
||||
| utarray_extend_back(UT_array *a) | push empty element onto a
|
||||
| utarray_len(UT_array *a) | get length of a
|
||||
| utarray_eltptr(UT_array *a,int j) | get pointer of element from index
|
||||
| utarray_eltidx(UT_array *a,void *e) | get index of element from pointer
|
||||
| utarray_insert(UT_array *a,void *p, int j) | insert element p to index j
|
||||
| utarray_inserta(UT_array *a,UT_array *w, int j) | insert array w into array a at index j
|
||||
| utarray_resize(UT_array *dst,int num) | extend or shrink array to num elements
|
||||
| utarray_concat(UT_array *dst,UT_array *src) | copy src to end of dst array
|
||||
| utarray_erase(UT_array *a,int pos,int len) | remove len elements from a[pos]..a[pos+len-1]
|
||||
| utarray_clear(UT_array *a) | clear all elements from a, setting its length to zero
|
||||
| utarray_sort(UT_array *a,cmpfcn *cmp) | sort elements of a using comparison function
|
||||
| utarray_find(UT_array *a,void *v, cmpfcn *cmp) | find element v in utarray (must be sorted)
|
||||
| utarray_front(UT_array *a) | get first element of a
|
||||
| utarray_next(UT_array *a,void *e) | get element of a following e (front if e is NULL)
|
||||
| utarray_prev(UT_array *a,void *e) | get element of a before e (back if e is NULL)
|
||||
| utarray_back(UT_array *a) | get last element of a
|
||||
|===============================================================================
|
||||
|
||||
Notes
|
||||
~~~~~
|
||||
|
||||
1. `utarray_new` and `utarray_free` are used to allocate a new array and free it,
|
||||
while `utarray_init` and `utarray_done` can be used if the UT_array is already
|
||||
allocated and just needs to be initialized or have its internal resources
|
||||
freed.
|
||||
2. `utarray_reserve` takes the "delta" of elements to reserve (not the total
|
||||
desired capacity of the array-- this differs from the C++ STL "reserve" notion)
|
||||
3. `utarray_sort` expects a comparison function having the usual `strcmp` -like
|
||||
convention where it accepts two elements (a and b) and returns a negative
|
||||
value if a precedes b, 0 if a and b sort equally, and positive if b precedes a.
|
||||
This is an example of a comparison function:
|
||||
|
||||
int intsort(const void *a, const void *b) {
|
||||
int _a = *(const int *)a;
|
||||
int _b = *(const int *)b;
|
||||
return (_a < _b) ? -1 : (_a > _b);
|
||||
}
|
||||
|
||||
4. `utarray_find` uses a binary search to locate an element having a certain value
|
||||
according to the given comparison function. The utarray must be first sorted
|
||||
using the same comparison function. An example of using `utarray_find` with
|
||||
a utarray of strings is included in `tests/test61.c`.
|
||||
|
||||
5. A 'pointer' to a particular element (obtained using `utarray_eltptr` or
|
||||
`utarray_front`, `utarray_next`, `utarray_prev`, `utarray_back`) becomes invalid whenever
|
||||
another element is inserted into the utarray. This is because the internal
|
||||
memory management may need to `realloc` the element storage to a new address.
|
||||
For this reason, it's usually better to refer to an element by its integer
|
||||
'index' in code whose duration may include element insertion.
|
||||
|
||||
// vim: set nowrap syntax=asciidoc:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 KiB |
@ -1,288 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="118.44112"
|
||||
height="22.655222"
|
||||
id="svg2018"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.44"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/home/thanson/code/uthash/trunk/doc/html/img"
|
||||
sodipodi:docname="uthash-mini.svg">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3964">
|
||||
<stop
|
||||
style="stop-color:#00eb00;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3966" />
|
||||
<stop
|
||||
style="stop-color:#00eb00;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3968" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3964"
|
||||
id="radialGradient3996"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.237347,0,36.5688)"
|
||||
cx="176.99219"
|
||||
cy="47.949429"
|
||||
fx="176.99219"
|
||||
fy="47.949429"
|
||||
r="78.257812" />
|
||||
<linearGradient
|
||||
id="linearGradient12743">
|
||||
<stop
|
||||
style="stop-color:#99e1fa;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop12745" />
|
||||
<stop
|
||||
id="stop12753"
|
||||
offset="0"
|
||||
style="stop-color:#99e1fa;stop-opacity:0.49803922;" />
|
||||
<stop
|
||||
style="stop-color:#99e1fa;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop12747" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient12743"
|
||||
id="radialGradient12751"
|
||||
cx="165.91866"
|
||||
cy="45.584854"
|
||||
fx="165.91866"
|
||||
fy="45.584854"
|
||||
r="56.51194"
|
||||
gradientTransform="matrix(0.268675,0,0,0.16215,17.28599,40.67469)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Send"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Send"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path7749"
|
||||
d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z "
|
||||
style="fill-rule:evenodd;stroke:black;stroke-width:1pt;marker-start:none"
|
||||
transform="scale(-0.2,-0.2)" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="StopM"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="StopM"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path7651"
|
||||
d="M 0,5.65 L 0,-5.65"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1pt"
|
||||
transform="scale(0.4,0.4)" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.2"
|
||||
inkscape:cx="160"
|
||||
inkscape:cy="90"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:window-width="916"
|
||||
inkscape:window-height="626"
|
||||
inkscape:window-x="5"
|
||||
inkscape:window-y="73" />
|
||||
<metadata
|
||||
id="metadata2022">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-17.9166,-36.67108)">
|
||||
<rect
|
||||
style="opacity:1;fill:#393be9;fill-opacity:1;stroke:#f18a00;stroke-width:1.51941979;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect3981"
|
||||
width="116.92171"
|
||||
height="21.135801"
|
||||
x="18.67631"
|
||||
y="37.430794"
|
||||
rx="7.8295798"
|
||||
ry="5.3735089"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/logo.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<flowRoot
|
||||
transform="matrix(0.449676,0,0,0.449676,-20.8252,25.84477)"
|
||||
style="font-size:47.99999619px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#faf599;fill-opacity:1;stroke:#f3bf33;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||
id="flowRoot3988"
|
||||
xml:space="preserve"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/logo.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"><flowRegion
|
||||
style="fill:url(#radialGradient3996);fill-opacity:1"
|
||||
id="flowRegion3990"><rect
|
||||
style="font-size:47.99999619px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#faf599;fill-opacity:1;stroke:#f3bf33;stroke-opacity:1;font-family:Bitstream Vera Sans"
|
||||
y="18"
|
||||
x="94.666664"
|
||||
height="61.333332"
|
||||
width="321.33334"
|
||||
id="rect3992" /></flowRegion><flowPara
|
||||
id="flowPara7831">ut hash</flowPara></flowRoot> <rect
|
||||
style="opacity:1;fill:url(#radialGradient12751);fill-opacity:1;stroke:none;stroke-width:2.82532263;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect10995"
|
||||
width="30.366741"
|
||||
height="18.326834"
|
||||
x="46.68087"
|
||||
y="38.902855"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/logo.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<g
|
||||
id="g7808"
|
||||
transform="matrix(0.217052,0,0,0.217052,-20.55641,38.41883)"
|
||||
inkscape:export-filename="/home/thanson/code/uthash/doc/html/img/logo.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<rect
|
||||
y="37.730064"
|
||||
x="382.39673"
|
||||
height="18.405188"
|
||||
width="23.206543"
|
||||
id="rect4882"
|
||||
style="opacity:1;fill:#9be5ea;fill-opacity:1;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#d48c21;fill-opacity:0.97777776;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect4886"
|
||||
width="23.206543"
|
||||
height="18.405188"
|
||||
x="416.39673"
|
||||
y="37.730064" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path4890"
|
||||
d="M 372.60327,46.932658 L 381.39673,46.932658"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path4892"
|
||||
d="M 406.60327,46.932658 L 415.39673,46.932658"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<rect
|
||||
y="9.7300644"
|
||||
x="348.39673"
|
||||
height="18.405188"
|
||||
width="23.206543"
|
||||
id="rect4896"
|
||||
style="opacity:1;fill:#79c71a;fill-opacity:1;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
style="opacity:1;fill:#f5e1a2;fill-opacity:1;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect4898"
|
||||
width="23.206543"
|
||||
height="18.405188"
|
||||
x="382.39673"
|
||||
y="9.7300644" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 372.60327,18.932658 L 381.39673,18.932658"
|
||||
id="path4902"
|
||||
inkscape:connector-type="polyline" />
|
||||
<rect
|
||||
y="14.207111"
|
||||
x="318.45328"
|
||||
height="10.1194"
|
||||
width="10.1194"
|
||||
id="rect4906"
|
||||
style="opacity:1;fill:#1336e6;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path5789"
|
||||
d="M 328.57268,19.220474 L 347.39673,19.048081"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 328.57268,19.220474 L 347.39673,19.048081"
|
||||
id="path5795"
|
||||
inkscape:connector-type="polyline" />
|
||||
<rect
|
||||
y="37.789951"
|
||||
x="348.20978"
|
||||
height="18.405188"
|
||||
width="23.206543"
|
||||
id="rect5803"
|
||||
style="opacity:1;fill:#e5e5e5;fill-opacity:1;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<rect
|
||||
y="42.267002"
|
||||
x="318.26633"
|
||||
height="10.1194"
|
||||
width="10.1194"
|
||||
id="rect5805"
|
||||
style="opacity:1;fill:#1336e6;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 328.38572,47.280365 L 347.20977,47.107972"
|
||||
id="path5807"
|
||||
inkscape:connector-type="polyline" />
|
||||
<rect
|
||||
style="opacity:1;fill:#ddf9ed;fill-opacity:1;stroke:black;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect5809"
|
||||
width="23.206543"
|
||||
height="18.405188"
|
||||
x="348.20978"
|
||||
y="63.720913" />
|
||||
<rect
|
||||
style="opacity:1;fill:#1336e6;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect5811"
|
||||
width="10.1194"
|
||||
height="10.1194"
|
||||
x="318.26633"
|
||||
y="68.197968" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path5813"
|
||||
d="M 328.38572,73.211328 L 347.20977,73.038935"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path5833"
|
||||
d="M 323.47927,24.326511 L 323.35974,42.267002"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#2f29df;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
inkscape:connector-type="polyline"
|
||||
id="path5835"
|
||||
d="M 323.32603,52.386402 L 323.32603,68.197968"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#2f29df;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path6716"
|
||||
d="M 429.08836,47.11641 L 394.37307,18.527349 L 394.37307,49.158485 L 359.65778,18.527349 L 359.65778,50.179523 L 359.65778,75.70547"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#f3bf33;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#StopM);marker-end:url(#Arrow1Send);stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
@ -1,317 +0,0 @@
|
||||
utlist: linked list macros for C structures
|
||||
===========================================
|
||||
Troy D. Hanson <tdh@tkhanson.net>
|
||||
v2.0.2, March 2017
|
||||
|
||||
Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page].
|
||||
|
||||
Introduction
|
||||
------------
|
||||
A set of general-purpose 'linked list' macros for C structures are included with
|
||||
uthash in `utlist.h`. To use these macros in your own C program, just
|
||||
copy `utlist.h` into your source directory and use it in your programs.
|
||||
|
||||
#include "utlist.h"
|
||||
|
||||
These macros support the basic linked list operations: adding and deleting
|
||||
elements, sorting them and iterating over them.
|
||||
|
||||
Download
|
||||
~~~~~~~~
|
||||
To download the `utlist.h` header file,
|
||||
follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file,
|
||||
then look in the src/ sub-directory.
|
||||
|
||||
BSD licensed
|
||||
~~~~~~~~~~~~
|
||||
This software is made available under the
|
||||
link:license.html[revised BSD license].
|
||||
It is free and open source.
|
||||
|
||||
Platforms
|
||||
~~~~~~~~~
|
||||
The 'utlist' macros have been tested on:
|
||||
|
||||
* Linux,
|
||||
* Mac OS X, and
|
||||
* Windows, using Visual Studio 2008, Visual Studio 2010, or Cygwin/MinGW.
|
||||
|
||||
Using utlist
|
||||
------------
|
||||
|
||||
Types of lists
|
||||
~~~~~~~~~~~~~~
|
||||
Three types of linked lists are supported:
|
||||
|
||||
- *singly-linked* lists,
|
||||
- *doubly-linked* lists, and
|
||||
- *circular, doubly-linked* lists
|
||||
|
||||
Efficiency
|
||||
^^^^^^^^^^
|
||||
Prepending elements::
|
||||
Constant-time on all list types.
|
||||
Appending::
|
||||
'O(n)' on singly-linked lists; constant-time on doubly-linked list.
|
||||
(The utlist implementation of the doubly-linked list keeps a tail pointer in
|
||||
`head->prev` so that append can be done in constant time).
|
||||
Deleting elements::
|
||||
'O(n)' on singly-linked lists; constant-time on doubly-linked list.
|
||||
Sorting::
|
||||
'O(n log(n))' for all list types.
|
||||
Insertion in order (for sorted lists)::
|
||||
'O(n)' for all list types.
|
||||
Iteration, counting and searching::
|
||||
'O(n)' for all list types.
|
||||
|
||||
List elements
|
||||
~~~~~~~~~~~~~
|
||||
You can use any structure with these macros, as long as the structure
|
||||
contains a `next` pointer. If you want to make a doubly-linked list,
|
||||
the element also needs to have a `prev` pointer.
|
||||
|
||||
typedef struct element {
|
||||
char *name;
|
||||
struct element *prev; /* needed for a doubly-linked list only */
|
||||
struct element *next; /* needed for singly- or doubly-linked lists */
|
||||
} element;
|
||||
|
||||
You can name your structure anything. In the example above it is called `element`.
|
||||
Within a particular list, all elements must be of the same type.
|
||||
|
||||
Flexible prev/next naming
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
You can name your `prev` and `next` pointers something else. If you do, there is
|
||||
a <<flex_names,family of macros>> that work identically but take these names as
|
||||
extra arguments.
|
||||
|
||||
List head
|
||||
~~~~~~~~~
|
||||
The list head is simply a pointer to your element structure. You can name it
|
||||
anything. *It must be initialized to `NULL`*.
|
||||
|
||||
element *head = NULL;
|
||||
|
||||
List operations
|
||||
~~~~~~~~~~~~~~~
|
||||
The lists support inserting or deleting elements, sorting the elements and
|
||||
iterating over them.
|
||||
|
||||
[width="100%",cols="10<m,10<m,10<m",grid="cols",options="header"]
|
||||
|===============================================================================
|
||||
|Singly-linked | Doubly-linked | Circular, doubly-linked
|
||||
|LL_PREPEND(head,add); | DL_PREPEND(head,add); | CDL_PREPEND(head,add);
|
||||
|LL_PREPEND_ELEM(head,ref,add); | DL_PREPEND_ELEM(head,ref,add); | CDL_PREPEND_ELEM(head,ref,add);
|
||||
|LL_APPEND_ELEM(head,ref,add); | DL_APPEND_ELEM(head,ref,add); | CDL_APPEND_ELEM(head,ref,add);
|
||||
|LL_REPLACE_ELEM(head,del,add); | DL_REPLACE_ELEM(head,del,add); | CDL_REPLACE_ELEM(head,del,add);
|
||||
|LL_APPEND(head,add); | DL_APPEND(head,add); | CDL_APPEND(head,add);
|
||||
|LL_INSERT_INORDER(head,add,cmp); | DL_INSERT_INORDER(head,add,cmp); | CDL_INSERT_INORDER(head,add,cmp);
|
||||
|LL_CONCAT(head1,head2); | DL_CONCAT(head1,head2); |
|
||||
|LL_DELETE(head,del); | DL_DELETE(head,del); | CDL_DELETE(head,del);
|
||||
|LL_SORT(head,cmp); | DL_SORT(head,cmp); | CDL_SORT(head,cmp);
|
||||
|LL_FOREACH(head,elt) {...}| DL_FOREACH(head,elt) {...} | CDL_FOREACH(head,elt) {...}
|
||||
|LL_FOREACH_SAFE(head,elt,tmp) {...}| DL_FOREACH_SAFE(head,elt,tmp) {...} | CDL_FOREACH_SAFE(head,elt,tmp1,tmp2) {...}
|
||||
|LL_SEARCH_SCALAR(head,elt,mbr,val);| DL_SEARCH_SCALAR(head,elt,mbr,val); | CDL_SEARCH_SCALAR(head,elt,mbr,val);
|
||||
|LL_SEARCH(head,elt,like,cmp);| DL_SEARCH(head,elt,like,cmp); | CDL_SEARCH(head,elt,like,cmp);
|
||||
|LL_LOWER_BOUND(head,elt,like,cmp); | DL_LOWER_BOUND(head,elt,like,cmp); | CDL_LOWER_BOUND(head,elt,like,cmp);
|
||||
|LL_COUNT(head,elt,count); | DL_COUNT(head,elt,count); | CDL_COUNT(head,elt,count);
|
||||
|===============================================================================
|
||||
|
||||
'Prepend' means to insert an element in front of the existing list head (if any),
|
||||
changing the list head to the new element. 'Append' means to add an element at the
|
||||
end of the list, so it becomes the new tail element. 'Concatenate' takes two
|
||||
properly constructed lists and appends the second list to the first. (Visual
|
||||
Studio 2008 does not support `LL_CONCAT` and `DL_CONCAT`, but VS2010 is ok.)
|
||||
To prepend before an arbitrary element instead of the list head, use the
|
||||
`_PREPEND_ELEM` macro family.
|
||||
To append after an arbitrary element element instead of the list head, use the
|
||||
`_APPEND_ELEM` macro family.
|
||||
To 'replace' an arbitrary list element with another element use the `_REPLACE_ELEM`
|
||||
family of macros.
|
||||
|
||||
The 'sort' operation never moves the elements in memory; rather it only adjusts
|
||||
the list order by altering the `prev` and `next` pointers in each element. Also
|
||||
the sort operation can change the list head to point to a new element.
|
||||
|
||||
The 'foreach' operation is for easy iteration over the list from the head to the
|
||||
tail. A usage example is shown below. You can of course just use the `prev` and
|
||||
`next` pointers directly instead of using the 'foreach' macros.
|
||||
The 'foreach_safe' operation should be used if you plan to delete any of the list
|
||||
elements while iterating.
|
||||
|
||||
The 'search' operation is a shortcut for iteration in search of a particular
|
||||
element. It is not any faster than manually iterating and testing each element.
|
||||
There are two forms: the "scalar" version searches for an element using a
|
||||
simple equality test on a given structure member, while the general version takes an
|
||||
element to which all others in the list will be compared using a `cmp` function.
|
||||
|
||||
The 'lower_bound' operation finds the first element of the list which is no greater
|
||||
than the provided `like` element, according to the provided `cmp` function.
|
||||
The 'lower_bound' operation sets `elt` to a suitable value for passing to
|
||||
`LL_APPEND_ELEM`; i.e., `elt=NULL` if the proper insertion point is at the front of
|
||||
the list, and `elt=p` if the proper insertion point is between `p` and `p->next`.
|
||||
|
||||
The 'count' operation iterates over the list and increments a supplied counter.
|
||||
|
||||
The parameters shown in the table above are explained here:
|
||||
|
||||
head::
|
||||
The list head (a pointer to your list element structure).
|
||||
add::
|
||||
A pointer to the list element structure you are adding to the list.
|
||||
del::
|
||||
A pointer to the list element structure you are replacing or
|
||||
deleting from the list.
|
||||
elt::
|
||||
A pointer that will be assigned to each list element in succession (see
|
||||
example) in the case of iteration macros; or, the output pointer from
|
||||
the search macros.
|
||||
ref::
|
||||
Reference element for prepend and append operations that will be
|
||||
prepended before or appended after.
|
||||
If `ref` is a pointer with value NULL, the new element will be appended to the
|
||||
list for _PREPEND_ELEM() operations and prepended for _APPEND_ELEM() operations.
|
||||
`ref` must be the name of a pointer variable and cannot be literally NULL,
|
||||
use _PREPEND() and _APPEND() macro family instead.
|
||||
like::
|
||||
An element pointer, having the same type as `elt`, for which the search macro
|
||||
seeks a match (if found, the match is stored in `elt`). A match is determined
|
||||
by the given `cmp` function.
|
||||
cmp::
|
||||
pointer to comparison function which accepts two arguments-- these are
|
||||
pointers to two element structures to be compared. The comparison function
|
||||
must return an `int` that is negative, zero, or positive, which specifies
|
||||
whether the first item should sort before, equal to, or after the second item,
|
||||
respectively. (In other words, the same convention that is used by `strcmp`).
|
||||
Note that under Visual Studio 2008 you may need to declare the two arguments
|
||||
as `void *` and then cast them back to their actual types.
|
||||
tmp::
|
||||
A pointer of the same type as `elt`. Used internally. Need not be initialized.
|
||||
mbr::
|
||||
In the scalar search macro, the name of a member within the `elt` structure which
|
||||
will be tested (using `==`) for equality with the value `val`.
|
||||
val::
|
||||
In the scalar search macro, specifies the value of (of structure member
|
||||
`field`) of the element being sought.
|
||||
count::
|
||||
integer which will be set to the length of the list
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
This example program reads names from a text file (one name per line), and
|
||||
appends each name to a doubly-linked list. Then it sorts and prints them.
|
||||
|
||||
.A doubly-linked list
|
||||
--------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "utlist.h"
|
||||
|
||||
#define BUFLEN 20
|
||||
|
||||
typedef struct el {
|
||||
char bname[BUFLEN];
|
||||
struct el *next, *prev;
|
||||
} el;
|
||||
|
||||
int namecmp(el *a, el *b) {
|
||||
return strcmp(a->bname,b->bname);
|
||||
}
|
||||
|
||||
el *head = NULL; /* important- initialize to NULL! */
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
el *name, *elt, *tmp, etmp;
|
||||
|
||||
char linebuf[BUFLEN];
|
||||
int count;
|
||||
FILE *file;
|
||||
|
||||
if ( (file = fopen( "test11.dat", "r" )) == NULL ) {
|
||||
perror("can't open: ");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
while (fgets(linebuf,BUFLEN,file) != NULL) {
|
||||
if ( (name = (el*)malloc(sizeof(el))) == NULL) exit(-1);
|
||||
strncpy(name->bname,linebuf,BUFLEN);
|
||||
DL_APPEND(head, name);
|
||||
}
|
||||
DL_SORT(head, namecmp);
|
||||
DL_FOREACH(head,elt) printf("%s", elt->bname);
|
||||
DL_COUNT(head, elt, count);
|
||||
printf("%d number of elements in list\n", count);
|
||||
|
||||
memcpy(&etmp.bname, "WES\n", 5);
|
||||
DL_SEARCH(head,elt,&etmp,namecmp);
|
||||
if (elt) printf("found %s\n", elt->bname);
|
||||
|
||||
/* now delete each element, use the safe iterator */
|
||||
DL_FOREACH_SAFE(head,elt,tmp) {
|
||||
DL_DELETE(head,elt);
|
||||
free(elt);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
[[flex_names]]
|
||||
Other names for prev and next
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
If the `prev` and `next` fields are named something else, a separate group of
|
||||
macros must be used. These work the same as the regular macros, but take the
|
||||
field names as extra parameters.
|
||||
|
||||
These "flexible field name" macros are shown below. They all end with "2". Each
|
||||
operates the same as its counterpart without the 2, but they take the name of
|
||||
the `prev` and `next` fields (as applicable) as trailing arguments.
|
||||
|
||||
.Flexible field name macros
|
||||
LL_SORT2(list, cmp, next);
|
||||
DL_SORT2(list, cmp, prev, next);
|
||||
CDL_SORT2(list, cmp, prev, next);
|
||||
LL_PREPEND2(head, add, next);
|
||||
LL_PREPEND_ELEM2(head, ref, add, next);
|
||||
LL_APPEND_ELEM2(head, ref, add, next);
|
||||
LL_REPLACE_ELEM(head, del, add, next);
|
||||
LL_CONCAT2(head1, head2, next);
|
||||
LL_APPEND2(head, add, next);
|
||||
LL_DELETE2(head, del, next);
|
||||
LL_FOREACH2(head, elt, next) {...}
|
||||
LL_FOREACH_SAFE2(head, elt, tmp, next) {...}
|
||||
LL_SEARCH_SCALAR2(head, elt, mbr, val, next);
|
||||
LL_SEARCH2(head, elt, like, cmp, next);
|
||||
LL_LOWER_BOUND2(head, elt, like, cmp, next);
|
||||
LL_COUNT2(head, elt, count, next);
|
||||
DL_PREPEND2(head, add, prev, next);
|
||||
DL_PREPEND_ELEM2(head, ref, add, prev, next);
|
||||
DL_APPEND_ELEM2(head, ref, add, prev, next);
|
||||
DL_REPLACE_ELEM2(head, del, add, prev, next);
|
||||
DL_CONCAT2(head1, head2, prev, next);
|
||||
DL_APPEND2(head, add, prev, next);
|
||||
DL_DELETE2(head, del, prev, next);
|
||||
DL_FOREACH2(head, elt, next) {...}
|
||||
DL_FOREACH_SAFE2(head, elt, tmp, next) {...}
|
||||
DL_SEARCH_SCALAR2(head, elt, mbr, val, next);
|
||||
DL_SEARCH2(head, elt, like, cmp, next);
|
||||
DL_LOWER_BOUND2(head, elt, like, cmp, next);
|
||||
DL_COUNT2(head, elt, count, next);
|
||||
CDL_PREPEND2(head, add, prev, next);
|
||||
CDL_PREPEND_ELEM2(head, ref, add, prev, next);
|
||||
CDL_APPEND_ELEM2(head, ref, add, prev, next);
|
||||
CDL_REPLACE_ELEM2(head, del, add, prev, next);
|
||||
CDL_APPEND2(head, add, prev, next);
|
||||
CDL_DELETE2(head, del, prev, next);
|
||||
CDL_FOREACH2(head, elt, next) {...}
|
||||
CDL_FOREACH_SAFE2(head, elt, tmp1, tmp2, prev, next) {...}
|
||||
CDL_SEARCH_SCALAR2(head, elt, mbr, val, next);
|
||||
CDL_SEARCH2(head, elt, like, cmp, next);
|
||||
CDL_LOWER_BOUND2(head, elt, like, cmp, next);
|
||||
CDL_COUNT2(head, elt, count, next);
|
||||
|
||||
// vim: set tw=80 wm=2 syntax=asciidoc:
|
||||
|
||||
@ -1,374 +0,0 @@
|
||||
utringbuffer: dynamic ring-buffer macros for C
|
||||
==============================================
|
||||
Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
|
||||
v2.0.2, March 2017
|
||||
|
||||
Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page].
|
||||
|
||||
Introduction
|
||||
------------
|
||||
The functions in `utringbuffer.h` are based on the general-purpose array macros
|
||||
provided in `utarray.h`, so before reading this page you should read
|
||||
link:utarray.html[that page] first.
|
||||
|
||||
To use these macros in your own C program, copy both `utarray.h` and `utringbuffer.h`
|
||||
into your source directory and use `utringbuffer.h` in your program.
|
||||
|
||||
#include "utringbuffer.h"
|
||||
|
||||
The provided <<operations,operations>> are based loosely on the C++ STL vector methods.
|
||||
The ring-buffer data type supports construction (with a specified capacity),
|
||||
destruction, iteration, and push, but not pop; once the ring-buffer reaches full
|
||||
capacity, pushing a new element automatically pops and destroys the oldest element.
|
||||
The elements contained in the ring-buffer can be any simple datatype or structure.
|
||||
|
||||
Internally the ring-buffer contains a pre-allocated memory region into which the
|
||||
elements are copied, starting at position 0. When the ring-buffer reaches full
|
||||
capacity, the next element to be pushed is pushed at position 0, overwriting the
|
||||
oldest element, and the internal index representing the "start" of the ring-buffer
|
||||
is incremented. A ring-buffer, once full, can never become un-full.
|
||||
|
||||
|
||||
Download
|
||||
~~~~~~~~
|
||||
To download the `utringbuffer.h` header file,
|
||||
follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file,
|
||||
then look in the src/ sub-directory.
|
||||
|
||||
BSD licensed
|
||||
~~~~~~~~~~~~
|
||||
This software is made available under the
|
||||
link:license.html[revised BSD license].
|
||||
It is free and open source.
|
||||
|
||||
Platforms
|
||||
~~~~~~~~~
|
||||
The 'utringbuffer' macros have been tested on:
|
||||
|
||||
* Linux,
|
||||
* Mac OS X,
|
||||
* Windows, using Visual Studio 2008 and Visual Studio 2010
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Declaration
|
||||
~~~~~~~~~~~
|
||||
|
||||
The ring-buffer itself has the data type `UT_ringbuffer`, regardless of the type of
|
||||
elements to be stored in it. It is declared like,
|
||||
|
||||
UT_ringbuffer *history;
|
||||
|
||||
New and free
|
||||
~~~~~~~~~~~~
|
||||
The next step is to create the ring-buffer using `utringbuffer_new`. Later when you're
|
||||
done with the ring-buffer, `utringbuffer_free` will free it and all its elements.
|
||||
|
||||
Push, etc
|
||||
~~~~~~~~~
|
||||
The central features of the ring-buffer involve putting elements into it
|
||||
and iterating over them. There are several <<operations,operations>>
|
||||
that deal with either single elements or ranges of elements at a
|
||||
time. In the examples below we will use only the push operation to insert
|
||||
elements.
|
||||
|
||||
Elements
|
||||
--------
|
||||
|
||||
Support for dynamic arrays of integers or strings is especially easy. These are
|
||||
best shown by example:
|
||||
|
||||
Integers
|
||||
~~~~~~~~
|
||||
This example makes a ring-buffer of integers, pushes 0-9 into it, then prints it
|
||||
two different ways. Lastly it frees it.
|
||||
|
||||
.Integer elements
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utringbuffer.h"
|
||||
|
||||
int main() {
|
||||
UT_ringbuffer *history;
|
||||
int i, *p;
|
||||
|
||||
utringbuffer_new(history, 7, &ut_int_icd);
|
||||
for(i=0; i < 10; i++) utringbuffer_push_back(history, &i);
|
||||
|
||||
for (p = (int*)utringbuffer_front(history);
|
||||
p != NULL;
|
||||
p = (int*)utringbuffer_next(history, p)) {
|
||||
printf("%d\n", *p); /* prints "3 4 5 6 7 8 9" */
|
||||
}
|
||||
|
||||
for (i=0; i < utringbuffer_len(history); i++) {
|
||||
p = utringbuffer_eltptr(history, i);
|
||||
printf("%d\n", *p); /* prints "3 4 5 6 7 8 9" */
|
||||
}
|
||||
|
||||
utringbuffer_free(history);
|
||||
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The second argument to `utringbuffer_push_back` is always a 'pointer' to the type
|
||||
(so a literal cannot be used). So for integers, it is an `int*`.
|
||||
|
||||
Strings
|
||||
~~~~~~~
|
||||
In this example we make a ring-buffer of strings, push two strings into it, print
|
||||
it and free it.
|
||||
|
||||
.String elements
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utringbuffer.h"
|
||||
|
||||
int main() {
|
||||
UT_ringbuffer *strs;
|
||||
char *s, **p;
|
||||
|
||||
utringbuffer_new(strs, 7, &ut_str_icd);
|
||||
|
||||
s = "hello"; utringbuffer_push_back(strs, &s);
|
||||
s = "world"; utringbuffer_push_back(strs, &s);
|
||||
p = NULL;
|
||||
while ( (p=(char**)utringbuffer_next(strs,p))) {
|
||||
printf("%s\n",*p);
|
||||
}
|
||||
|
||||
utringbuffer_free(strs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
In this example, since the element is a `char*`, we pass a pointer to it
|
||||
(`char**`) as the second argument to `utringbuffer_push_back`. Note that "push" makes
|
||||
a copy of the source string and pushes that copy into the array.
|
||||
|
||||
About UT_icd
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Arrays can be made of any type of element, not just integers and strings. The
|
||||
elements can be basic types or structures. Unless you're dealing with integers
|
||||
and strings (which use pre-defined `ut_int_icd` and `ut_str_icd`), you'll need
|
||||
to define a `UT_icd` helper structure. This structure contains everything that
|
||||
utringbuffer (or utarray) needs to initialize, copy or destruct elements.
|
||||
|
||||
typedef struct {
|
||||
size_t sz;
|
||||
init_f *init;
|
||||
ctor_f *copy;
|
||||
dtor_f *dtor;
|
||||
} UT_icd;
|
||||
|
||||
The three function pointers `init`, `copy`, and `dtor` have these prototypes:
|
||||
|
||||
typedef void (ctor_f)(void *dst, const void *src);
|
||||
typedef void (dtor_f)(void *elt);
|
||||
typedef void (init_f)(void *elt);
|
||||
|
||||
The `sz` is just the size of the element being stored in the array.
|
||||
|
||||
The `init` function is used by utarray but is never used by utringbuffer;
|
||||
you may safely set it to any value you want.
|
||||
|
||||
The `copy` function is used whenever an element is copied into the buffer.
|
||||
It is invoked during `utringbuffer_push_back`.
|
||||
If `copy` is `NULL`, it defaults to a bitwise copy using memcpy.
|
||||
|
||||
The `dtor` function is used to clean up an element that is being removed from
|
||||
the buffer. It may be invoked due to `utringbuffer_push_back` (on the oldest
|
||||
element in the buffer), `utringbuffer_clear`, `utringbuffer_done`, or
|
||||
`utringbuffer_free`.
|
||||
If the elements need no cleanup upon destruction, `dtor` may be `NULL`.
|
||||
|
||||
Scalar types
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The next example uses `UT_icd` with all its defaults to make a ring-buffer of
|
||||
`long` elements. This example pushes two longs into a buffer of capacity 1,
|
||||
prints the contents of the buffer (which is to say, the most recent value
|
||||
pushed), and then frees the buffer.
|
||||
|
||||
.long elements
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utringbuffer.h"
|
||||
|
||||
UT_icd long_icd = {sizeof(long), NULL, NULL, NULL };
|
||||
|
||||
int main() {
|
||||
UT_ringbuffer *nums;
|
||||
long l, *p;
|
||||
utringbuffer_new(nums, 1, &long_icd);
|
||||
|
||||
l=1; utringbuffer_push_back(nums, &l);
|
||||
l=2; utringbuffer_push_back(nums, &l);
|
||||
|
||||
p=NULL;
|
||||
while((p = (long*)utringbuffer_next(nums,p))) printf("%ld\n", *p);
|
||||
|
||||
utringbuffer_free(nums);
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Structures
|
||||
~~~~~~~~~~
|
||||
|
||||
Structures can be used as utringbuffer elements. If the structure requires no
|
||||
special effort to initialize, copy or destruct, we can use `UT_icd` with all
|
||||
its defaults. This example shows a structure that consists of two integers. Here
|
||||
we push two values, print them and free the buffer.
|
||||
|
||||
.Structure (simple)
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utringbuffer.h"
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
int b;
|
||||
} intpair_t;
|
||||
|
||||
UT_icd intpair_icd = {sizeof(intpair_t), NULL, NULL, NULL};
|
||||
|
||||
int main() {
|
||||
|
||||
UT_ringbuffer *pairs;
|
||||
intpair_t ip, *p;
|
||||
utringbuffer_new(pairs, 7, &intpair_icd);
|
||||
|
||||
ip.a=1; ip.b=2; utringbuffer_push_back(pairs, &ip);
|
||||
ip.a=10; ip.b=20; utringbuffer_push_back(pairs, &ip);
|
||||
|
||||
for(p=(intpair_t*)utringbuffer_front(pairs);
|
||||
p!=NULL;
|
||||
p=(intpair_t*)utringbuffer_next(pairs,p)) {
|
||||
printf("%d %d\n", p->a, p->b);
|
||||
}
|
||||
|
||||
utringbuffer_free(pairs);
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The real utility of `UT_icd` is apparent when the elements stored in the
|
||||
ring-buffer are structures that require special work to initialize, copy or
|
||||
destruct.
|
||||
|
||||
For example, when a structure contains pointers to related memory areas that
|
||||
need to be copied when the structure is copied (and freed when the structure is
|
||||
freed), we can use custom `init`, `copy`, and `dtor` members in the `UT_icd`.
|
||||
|
||||
Here we take an example of a structure that contains an integer and a string.
|
||||
When this element is copied (such as when an element is pushed),
|
||||
we want to "deep copy" the `s` pointer (so the original element and the new
|
||||
element point to their own copies of `s`). When an element is destructed, we
|
||||
want to "deep free" its copy of `s`. Lastly, this example is written to work
|
||||
even if `s` has the value `NULL`.
|
||||
|
||||
.Structure (complex)
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "utringbuffer.h"
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
char *s;
|
||||
} intchar_t;
|
||||
|
||||
void intchar_copy(void *_dst, const void *_src) {
|
||||
intchar_t *dst = (intchar_t*)_dst, *src = (intchar_t*)_src;
|
||||
dst->a = src->a;
|
||||
dst->s = src->s ? strdup(src->s) : NULL;
|
||||
}
|
||||
|
||||
void intchar_dtor(void *_elt) {
|
||||
intchar_t *elt = (intchar_t*)_elt;
|
||||
free(elt->s);
|
||||
}
|
||||
|
||||
UT_icd intchar_icd = {sizeof(intchar_t), NULL, intchar_copy, intchar_dtor};
|
||||
|
||||
int main() {
|
||||
UT_ringbuffer *intchars;
|
||||
intchar_t ic, *p;
|
||||
utringbuffer_new(intchars, 2, &intchar_icd);
|
||||
|
||||
ic.a=1; ic.s="hello"; utringbuffer_push_back(intchars, &ic);
|
||||
ic.a=2; ic.s="world"; utringbuffer_push_back(intchars, &ic);
|
||||
ic.a=3; ic.s="peace"; utringbuffer_push_back(intchars, &ic);
|
||||
|
||||
p=NULL;
|
||||
while( (p=(intchar_t*)utringbuffer_next(intchars,p))) {
|
||||
printf("%d %s\n", p->a, (p->s ? p->s : "null"));
|
||||
/* prints "2 world 3 peace" */
|
||||
}
|
||||
|
||||
utringbuffer_free(intchars);
|
||||
return 0;
|
||||
}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
[[operations]]
|
||||
Reference
|
||||
---------
|
||||
This table lists all the utringbuffer operations. These are loosely based on the C++
|
||||
vector class.
|
||||
|
||||
Operations
|
||||
~~~~~~~~~~
|
||||
|
||||
[width="100%",cols="50<m,40<",grid="none",options="none"]
|
||||
|===============================================================================
|
||||
| utringbuffer_new(UT_ringbuffer *a, int n, UT_icd *icd) | allocate a new ringbuffer
|
||||
| utringbuffer_free(UT_ringbuffer *a) | free an allocated ringbuffer
|
||||
| utringbuffer_init(UT_ringbuffer *a, int n, UT_icd *icd) | init a ringbuffer (non-alloc)
|
||||
| utringbuffer_done(UT_ringbuffer *a) | dispose of a ringbuffer (non-alloc)
|
||||
| utringbuffer_clear(UT_ringbuffer *a) | clear all elements from a, making it empty
|
||||
| utringbuffer_push_back(UT_ringbuffer *a, element *p) | push element p onto a
|
||||
| utringbuffer_len(UT_ringbuffer *a) | get length of a
|
||||
| utringbuffer_empty(UT_ringbuffer *a) | get whether a is empty
|
||||
| utringbuffer_full(UT_ringbuffer *a) | get whether a is full
|
||||
| utringbuffer_eltptr(UT_ringbuffer *a, int j) | get pointer of element from index
|
||||
| utringbuffer_eltidx(UT_ringbuffer *a, element *e) | get index of element from pointer
|
||||
| utringbuffer_front(UT_ringbuffer *a) | get oldest element of a
|
||||
| utringbuffer_next(UT_ringbuffer *a, element *e) | get element of a following e (front if e is NULL)
|
||||
| utringbuffer_prev(UT_ringbuffer *a, element *e) | get element of a before e (back if e is NULL)
|
||||
| utringbuffer_back(UT_ringbuffer *a) | get newest element of a
|
||||
|===============================================================================
|
||||
|
||||
Notes
|
||||
~~~~~
|
||||
|
||||
1. `utringbuffer_new` and `utringbuffer_free` are used to allocate a new ring-buffer
|
||||
and to free it,
|
||||
while `utringbuffer_init` and `utringbuffer_done` can be used if the UT_ringbuffer
|
||||
is already allocated and just needs to be initialized or have its internal resources
|
||||
freed.
|
||||
2. Both `utringbuffer_new` and `utringbuffer_init` take a second parameter `n` indicating
|
||||
the capacity of the ring-buffer, that is, the size at which the ring-buffer is considered
|
||||
"full" and begins to overwrite old elements with newly pushed ones.
|
||||
3. Once a ring-buffer has become full, it will never again become un-full except by
|
||||
means of `utringbuffer_clear`. There is no way to "pop" a single old item from the
|
||||
front of the ring-buffer. You can simulate this ability by maintaining a separate
|
||||
integer count of the number of "logically popped elements", and starting your iteration
|
||||
with `utringbuffer_eltptr(a, popped_count)` instead of with `utringbuffer_front(a)`.
|
||||
4. Pointers to elements (obtained using `utringbuffer_eltptr`, `utringbuffer_front`,
|
||||
`utringbuffer_next`, etc.) are not generally invalidated by `utringbuffer_push_back`,
|
||||
because utringbuffer does not perform reallocation; however, a pointer to the oldest
|
||||
element may suddenly turn into a pointer to the 'newest' element if
|
||||
`utringbuffer_push_back` is called while the buffer is full.
|
||||
5. The elements of a ring-buffer are stored in contiguous memory, but once the ring-buffer
|
||||
has become full, it is no longer true that the elements are contiguously in order from
|
||||
oldest to newest; i.e., `(element *)utringbuffer_front(a) + utringbuffer_len(a)-1` is
|
||||
not generally equal to `(element *)utringbuffer_back(a)`.
|
||||
|
||||
// vim: set nowrap syntax=asciidoc:
|
||||
@ -1,229 +0,0 @@
|
||||
utstring: dynamic string macros for C
|
||||
=====================================
|
||||
Troy D. Hanson <tdh@tkhanson.net>
|
||||
v2.0.2, March 2017
|
||||
|
||||
Here's a link back to the https://github.com/troydhanson/uthash[GitHub project page].
|
||||
|
||||
Introduction
|
||||
------------
|
||||
A set of basic dynamic string macros for C programs are included with
|
||||
uthash in `utstring.h`. To use these in your own C program, just copy
|
||||
`utstring.h` into your source directory and use it in your programs.
|
||||
|
||||
#include "utstring.h"
|
||||
|
||||
The dynamic string supports operations such as inserting data, concatenation,
|
||||
getting the length and content, substring search, and clear. It's ok to put
|
||||
binary data into a utstring too. The string <<operations,operations>> are
|
||||
listed below.
|
||||
|
||||
Some utstring operations are implemented as functions rather than macros.
|
||||
|
||||
Download
|
||||
~~~~~~~~
|
||||
To download the `utstring.h` header file,
|
||||
follow the links on https://github.com/troydhanson/uthash to clone uthash or get a zip file,
|
||||
then look in the src/ sub-directory.
|
||||
|
||||
BSD licensed
|
||||
~~~~~~~~~~~~
|
||||
This software is made available under the
|
||||
link:license.html[revised BSD license].
|
||||
It is free and open source.
|
||||
|
||||
Platforms
|
||||
~~~~~~~~~
|
||||
The 'utstring' macros have been tested on:
|
||||
|
||||
* Linux,
|
||||
* Windows, using Visual Studio 2008 and Visual Studio 2010
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Declaration
|
||||
~~~~~~~~~~~
|
||||
|
||||
The dynamic string itself has the data type `UT_string`. It is declared like,
|
||||
|
||||
UT_string *str;
|
||||
|
||||
New and free
|
||||
~~~~~~~~~~~~
|
||||
The next step is to create the string using `utstring_new`. Later when you're
|
||||
done with it, `utstring_free` will free it and all its content.
|
||||
|
||||
Manipulation
|
||||
~~~~~~~~~~~~
|
||||
The `utstring_printf` or `utstring_bincpy` operations insert (copy) data into
|
||||
the string. To concatenate one utstring to another, use `utstring_concat`. To
|
||||
clear the content of the string, use `utstring_clear`. The length of the string
|
||||
is available from `utstring_len`, and its content from `utstring_body`. This
|
||||
evaluates to a `char*`. The buffer it points to is always null-terminated.
|
||||
So, it can be used directly with external functions that expect a string.
|
||||
This automatic null terminator is not counted in the length of the string.
|
||||
|
||||
Samples
|
||||
~~~~~~~
|
||||
|
||||
These examples show how to use utstring.
|
||||
|
||||
.Sample 1
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utstring.h"
|
||||
|
||||
int main() {
|
||||
UT_string *s;
|
||||
|
||||
utstring_new(s);
|
||||
utstring_printf(s, "hello world!" );
|
||||
printf("%s\n", utstring_body(s));
|
||||
|
||||
utstring_free(s);
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The next example demonstrates that `utstring_printf` 'appends' to the string.
|
||||
It also shows concatenation.
|
||||
|
||||
.Sample 2
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utstring.h"
|
||||
|
||||
int main() {
|
||||
UT_string *s, *t;
|
||||
|
||||
utstring_new(s);
|
||||
utstring_new(t);
|
||||
|
||||
utstring_printf(s, "hello " );
|
||||
utstring_printf(s, "world " );
|
||||
|
||||
utstring_printf(t, "hi " );
|
||||
utstring_printf(t, "there " );
|
||||
|
||||
utstring_concat(s, t);
|
||||
printf("length: %u\n", utstring_len(s));
|
||||
printf("%s\n", utstring_body(s));
|
||||
|
||||
utstring_free(s);
|
||||
utstring_free(t);
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The next example shows how binary data can be inserted into the string. It also
|
||||
clears the string and prints new data into it.
|
||||
|
||||
.Sample 3
|
||||
-------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include "utstring.h"
|
||||
|
||||
int main() {
|
||||
UT_string *s;
|
||||
char binary[] = "\xff\xff";
|
||||
|
||||
utstring_new(s);
|
||||
utstring_bincpy(s, binary, sizeof(binary));
|
||||
printf("length is %u\n", utstring_len(s));
|
||||
|
||||
utstring_clear(s);
|
||||
utstring_printf(s,"number %d", 10);
|
||||
printf("%s\n", utstring_body(s));
|
||||
|
||||
utstring_free(s);
|
||||
return 0;
|
||||
}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
[[operations]]
|
||||
Reference
|
||||
---------
|
||||
These are the utstring operations.
|
||||
|
||||
Operations
|
||||
~~~~~~~~~~
|
||||
|
||||
[width="100%",cols="50<m,40<",grid="none",options="none"]
|
||||
|===============================================================================
|
||||
| utstring_new(s) | allocate a new utstring
|
||||
| utstring_renew(s) | allocate a new utstring (if s is `NULL`) otherwise clears it
|
||||
| utstring_free(s) | free an allocated utstring
|
||||
| utstring_init(s) | init a utstring (non-alloc)
|
||||
| utstring_done(s) | dispose of a utstring (non-alloc)
|
||||
| utstring_printf(s,fmt,...) | printf into a utstring (appends)
|
||||
| utstring_bincpy(s,bin,len) | insert binary data of length len (appends)
|
||||
| utstring_concat(dst,src) | concatenate src utstring to end of dst utstring
|
||||
| utstring_clear(s) | clear the content of s (setting its length to 0)
|
||||
| utstring_len(s) | obtain the length of s as an unsigned integer
|
||||
| utstring_body(s) | get `char*` to body of s (buffer is always null-terminated)
|
||||
| utstring_find(s,pos,str,len) | forward search from pos for a substring
|
||||
| utstring_findR(s,pos,str,len) | reverse search from pos for a substring
|
||||
|===============================================================================
|
||||
|
||||
New/free vs. init/done
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
Use `utstring_new` and `utstring_free` to allocate a new string or free it. If
|
||||
the UT_string is statically allocated, use `utstring_init` and `utstring_done`
|
||||
to initialize or free its internal memory.
|
||||
|
||||
Substring search
|
||||
~~~~~~~~~~~~~~~~
|
||||
Use `utstring_find` and `utstring_findR` to search for a substring in a utstring.
|
||||
It comes in forward and reverse varieties. The reverse search scans from the end of
|
||||
the string backward. These take a position to start searching from, measured from 0
|
||||
(the start of the utstring). A negative position is counted from the end of
|
||||
the string, so, -1 is the last position. Note that in the reverse search, the
|
||||
initial position anchors to the 'end' of the substring being searched for;
|
||||
e.g., the 't' in 'cat'. The return value always refers to the offset where the
|
||||
substring 'starts' in the utstring. When no substring match is found, -1 is
|
||||
returned.
|
||||
|
||||
For example if a utstring called `s` contains:
|
||||
|
||||
ABC ABCDAB ABCDABCDABDE
|
||||
|
||||
Then these forward and reverse substring searches for `ABC` produce these results:
|
||||
|
||||
utstring_find( s, -9, "ABC", 3 ) = 15
|
||||
utstring_find( s, 3, "ABC", 3 ) = 4
|
||||
utstring_find( s, 16, "ABC", 3 ) = -1
|
||||
utstring_findR( s, -9, "ABC", 3 ) = 11
|
||||
utstring_findR( s, 12, "ABC", 3 ) = 4
|
||||
utstring_findR( s, 2, "ABC", 3 ) = 0
|
||||
|
||||
"Multiple use" substring search
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The preceding examples show "single use" versions of substring matching, where
|
||||
the internal Knuth-Morris-Pratt (KMP) table is internally built and then freed
|
||||
after the search. If your program needs to run many searches for a given
|
||||
substring, it is more efficient to save the KMP table and reuse it.
|
||||
|
||||
To reuse the KMP table, build it manually and then pass it into the internal
|
||||
search functions. The functions involved are:
|
||||
|
||||
_utstring_BuildTable (build the KMP table for a forward search)
|
||||
_utstring_BuildTableR (build the KMP table for a reverse search)
|
||||
_utstring_find (forward search using a prebuilt KMP table)
|
||||
_utstring_findR (reverse search using a prebuilt KMP table)
|
||||
|
||||
This is an example of building a forward KMP table for the substring "ABC", and
|
||||
then using it in a search:
|
||||
|
||||
long *KPM_TABLE, offset;
|
||||
KPM_TABLE = (long *)malloc( sizeof(long) * (strlen("ABC")) + 1));
|
||||
_utstring_BuildTable("ABC", 3, KPM_TABLE);
|
||||
offset = _utstring_find(utstring_body(s), utstring_len(s), "ABC", 3, KPM_TABLE );
|
||||
free(KPM_TABLE);
|
||||
|
||||
Note that the internal `_utstring_find` has the length of the UT_string as its
|
||||
second argument, rather than the start position. You can emulate the position
|
||||
parameter by adding to the string start address and subtracting from its length.
|
||||
|
||||
// vim: set nowrap syntax=asciidoc:
|
||||
|
||||
@ -243,21 +243,9 @@ Source: Docs\Oniguruma_RE.txt; DestDir: {ap
|
||||
Source: Docs\Notepad3.txt; DestDir: {app}\Docs; Flags: ignoreversion
|
||||
Source: Docs\crypto\encryption-doc.txt; DestDir: {app}\Docs\crypto; Flags: ignoreversion
|
||||
Source: Docs\crypto\read_me.txt; DestDir: {app}\Docs\crypto; Flags: ignoreversion
|
||||
Source: Docs\uthash\banner.png; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\banner.svg; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\ChangeLog.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\index.html; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\license.html; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\rss.png; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\styles.css; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\license.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\userguide.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\utarray.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\uthash.png; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\uthash-mini.png; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\uthash-mini.svg; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\utlist.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\utringbuffer.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\utstring.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
|
||||
|
||||
[Dirs]
|
||||
|
||||
@ -181,21 +181,9 @@ Source: Docs\Oniguruma_RE.txt; DestDir: {ap
|
||||
Source: Docs\Notepad3.txt; DestDir: {app}\Docs; Flags: ignoreversion
|
||||
Source: Docs\crypto\encryption-doc.txt; DestDir: {app}\Docs\crypto; Flags: ignoreversion
|
||||
Source: Docs\crypto\read_me.txt; DestDir: {app}\Docs\crypto; Flags: ignoreversion
|
||||
Source: Docs\uthash\banner.png; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\banner.svg; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\ChangeLog.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\index.html; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\license.html; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\rss.png; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\styles.css; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\license.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\userguide.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\utarray.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\uthash.png; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\uthash-mini.png; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\uthash-mini.svg; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\utlist.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\utringbuffer.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
Source: Docs\uthash\utstring.txt; DestDir: {app}\Docs\uthash; Flags: ignoreversion
|
||||
|
||||
|
||||
[Dirs]
|
||||
|
||||
@ -1,27 +1,4 @@
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XTHML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||
<title>uthash: a hash table for C structures</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="banner">
|
||||
<img src="banner.png" alt="uthash: a hash table for C structures" />
|
||||
</div> <!-- banner -->
|
||||
|
||||
<div id="topnav">
|
||||
<a href="http://troydhanson.github.com/uthash/">uthash home</a> >
|
||||
BSD license
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<div id="mid">
|
||||
<div id="main">
|
||||
<pre>
|
||||
Copyright (c) 2005-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
Copyright (c) 2005-2018, Troy D. Hanson https://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -41,15 +18,4 @@ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
</pre>
|
||||
</div> <!-- mid -->
|
||||
</div> <!-- main -->
|
||||
|
||||
<hr />
|
||||
<div id="footer">
|
||||
</div> <!-- footer -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2008-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
Copyright (c) 2008-2018, Troy D. Hanson https://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2003-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
Copyright (c) 2003-2018, Troy D. Hanson https://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
[InternetShortcut]
|
||||
URL=https://troydhanson.github.io/uthash/index.html
|
||||
IDList=
|
||||
HotKey=0
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2007-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
Copyright (c) 2007-2018, Troy D. Hanson https://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2015-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
Copyright (c) 2015-2018, Troy D. Hanson https://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2018-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
Copyright (c) 2018-2018, Troy D. Hanson https://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2008-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
Copyright (c) 2008-2018, Troy D. Hanson https://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
Loading…
Reference in New Issue
Block a user