<!--{{{--> <link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' /> <!--}}}-->
Background: #fff Foreground: #000 PrimaryPale: #8cf PrimaryLight: #18f PrimaryMid: #04b PrimaryDark: #014 SecondaryPale: #ffc SecondaryLight: #fe8 SecondaryMid: #db4 SecondaryDark: #841 TertiaryPale: #eee TertiaryLight: #ccc TertiaryMid: #999 TertiaryDark: #666 Error: #f88
/*{{{*/ body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];} a {color:[[ColorPalette::PrimaryMid]];} a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];} a img {border:0;} h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;} h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];} h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];} .button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];} .button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];} .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];} .header {background:[[ColorPalette::PrimaryMid]];} .headerShadow {color:[[ColorPalette::Foreground]];} .headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];} .headerForeground {color:[[ColorPalette::Background]];} .headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];} .tabSelected{color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border-left:1px solid [[ColorPalette::TertiaryLight]]; border-top:1px solid [[ColorPalette::TertiaryLight]]; border-right:1px solid [[ColorPalette::TertiaryLight]]; } .tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];} .tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];} .tabContents .button {border:0;} #sidebar {} #sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];} #sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];} #sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];} #sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];} #sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];} .wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];} .wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;} .wizard h2 {color:[[ColorPalette::Foreground]]; border:none;} .wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]]; border:1px solid [[ColorPalette::PrimaryMid]];} .wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];} .wizardFooter {background:[[ColorPalette::PrimaryPale]];} .wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];} .wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid; border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];} .wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];} .wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid; border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];} .wizard .notChanged {background:transparent;} .wizard .changedLocally {background:#80ff80;} .wizard .changedServer {background:#8080ff;} .wizard .changedBoth {background:#ff8080;} .wizard .notFound {background:#ffff80;} .wizard .putToServer {background:#ff80ff;} .wizard .gotFromServer {background:#80ffff;} #messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];} #messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;} .popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];} .popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];} .popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;} .popup li.disabled {color:[[ColorPalette::TertiaryMid]];} .popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;} .popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;} .popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;} .popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];} .listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];} .tiddler .defaultCommand {font-weight:bold;} .shadow .title {color:[[ColorPalette::TertiaryDark]];} .title {color:[[ColorPalette::SecondaryDark]];} .subtitle {color:[[ColorPalette::TertiaryDark]];} .toolbar {color:[[ColorPalette::PrimaryMid]];} .toolbar a {color:[[ColorPalette::TertiaryLight]];} .selected .toolbar a {color:[[ColorPalette::TertiaryMid]];} .selected .toolbar a:hover {color:[[ColorPalette::Foreground]];} .tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];} .selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];} .tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];} .tagging .button, .tagged .button {border:none;} .footer {color:[[ColorPalette::TertiaryLight]];} .selected .footer {color:[[ColorPalette::TertiaryMid]];} .sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;} .sparktick {background:[[ColorPalette::PrimaryDark]];} .error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];} .warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];} .lowlight {background:[[ColorPalette::TertiaryLight]];} .zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];} .imageLink, #displayArea .imageLink {background:transparent;} .annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];} .viewer .listTitle {list-style-type:none; margin-left:-2em;} .viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];} .viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];} .viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];} .viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];} .viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];} .viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];} .viewer code {color:[[ColorPalette::SecondaryDark]];} .viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];} .highlight, .marked {background:[[ColorPalette::SecondaryLight]];} .editor input {border:1px solid [[ColorPalette::PrimaryMid]];} .editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;} .editorFooter {color:[[ColorPalette::TertiaryMid]];} #backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];} #backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;} #backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; } #backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];} #backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;} #backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;} #backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];} .backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];} .backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];} #backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity=60)';} /*}}}*/
/*{{{*/ * html .tiddler {height:1%;} body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;} h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;} h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;} h4,h5,h6 {margin-top:1em;} h1 {font-size:1.35em;} h2 {font-size:1.25em;} h3 {font-size:1.1em;} h4 {font-size:1em;} h5 {font-size:.9em;} hr {height:1px;} a {text-decoration:none;} dt {font-weight:bold;} ol {list-style-type:decimal;} ol ol {list-style-type:lower-alpha;} ol ol ol {list-style-type:lower-roman;} ol ol ol ol {list-style-type:decimal;} ol ol ol ol ol {list-style-type:lower-alpha;} ol ol ol ol ol ol {list-style-type:lower-roman;} ol ol ol ol ol ol ol {list-style-type:decimal;} .txtOptionInput {width:11em;} #contentWrapper .chkOptionInput {border:0;} .externalLink {text-decoration:underline;} .indent {margin-left:3em;} .outdent {margin-left:3em; text-indent:-3em;} code.escaped {white-space:nowrap;} .tiddlyLinkExisting {font-weight:bold;} .tiddlyLinkNonExisting {font-style:italic;} /* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */ a.tiddlyLinkNonExisting.shadow {font-weight:bold;} #mainMenu .tiddlyLinkExisting, #mainMenu .tiddlyLinkNonExisting, #sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;} #sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;} .header {position:relative;} .header a:hover {background:transparent;} .headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;} .headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0px; top:0px;} .siteTitle {font-size:3em;} .siteSubtitle {font-size:1.2em;} #mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;} #sidebar {position:absolute; right:3px; width:16em; font-size:.9em;} #sidebarOptions {padding-top:0.3em;} #sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;} #sidebarOptions input {margin:0.4em 0.5em;} #sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;} #sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;} #sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;} #sidebarTabs .tabContents {width:15em; overflow:hidden;} .wizard {padding:0.1em 1em 0 2em;} .wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;} .wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;} .wizardStep {padding:1em 1em 1em 1em;} .wizard .button {margin:0.5em 0 0; font-size:1.2em;} .wizardFooter {padding:0.8em 0.4em 0.8em 0;} .wizardFooter .status {padding:0 0.4em; margin-left:1em;} .wizard .button {padding:0.1em 0.2em;} #messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;} .messageToolbar {display:block; text-align:right; padding:0.2em;} #messageArea a {text-decoration:underline;} .tiddlerPopupButton {padding:0.2em;} .popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;} .popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;} .popup .popupMessage {padding:0.4em;} .popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;} .popup li.disabled {padding:0.4em;} .popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;} .listBreak {font-size:1px; line-height:1px;} .listBreak div {margin:2px 0;} .tabset {padding:1em 0 0 0.5em;} .tab {margin:0 0 0 0.25em; padding:2px;} .tabContents {padding:0.5em;} .tabContents ul, .tabContents ol {margin:0; padding:0;} .txtMainTab .tabContents li {list-style:none;} .tabContents li.listLink { margin-left:.75em;} #contentWrapper {display:block;} #splashScreen {display:none;} #displayArea {margin:1em 17em 0 14em;} .toolbar {text-align:right; font-size:.9em;} .tiddler {padding:1em 1em 0;} .missing .viewer,.missing .title {font-style:italic;} .title {font-size:1.6em; font-weight:bold;} .missing .subtitle {display:none;} .subtitle {font-size:1.1em;} .tiddler .button {padding:0.2em 0.4em;} .tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;} .isTag .tagging {display:block;} .tagged {margin:0.5em; float:right;} .tagging, .tagged {font-size:0.9em; padding:0.25em;} .tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;} .tagClear {clear:both;} .footer {font-size:.9em;} .footer li {display:inline;} .annotation {padding:0.5em; margin:0.5em;} * html .viewer pre {width:99%; padding:0 0 1em 0;} .viewer {line-height:1.4em; padding-top:0.5em;} .viewer .button {margin:0 0.25em; padding:0 0.25em;} .viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;} .viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;} .viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;} .viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;} table.listView {font-size:0.85em; margin:0.8em 1.0em;} table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;} .viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;} .viewer code {font-size:1.2em; line-height:1.4em;} .editor {font-size:1.1em;} .editor input, .editor textarea {display:block; width:100%; font:inherit;} .editorFooter {padding:0.25em 0; font-size:.9em;} .editorFooter .button {padding-top:0px; padding-bottom:0px;} .fieldsetFix {border:0; padding:0; margin:1px 0px;} .sparkline {line-height:1em;} .sparktick {outline:0;} .zoomer {font-size:1.1em; position:absolute; overflow:hidden;} .zoomer div {padding:1em;} * html #backstage {width:99%;} * html #backstageArea {width:99%;} #backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;} #backstageToolbar {position:relative;} #backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;} #backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;} #backstageButton a {padding:0.1em 0.4em; margin:0.1em;} #backstage {position:relative; width:100%; z-index:50;} #backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;} .backstagePanelFooter {padding-top:0.2em; float:right;} .backstagePanelFooter a {padding:0.2em 0.4em;} #backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;} .whenBackstage {display:none;} .backstageVisible .whenBackstage {display:block;} /*}}}*/
/*** StyleSheet for use when a translation requires any css style changes. This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes. ***/ /*{{{*/ body {font-size:0.8em;} #sidebarOptions {font-size:1.05em;} #sidebarOptions a {font-style:normal;} #sidebarOptions .sliderPanel {font-size:0.95em;} .subtitle {font-size:0.8em;} .viewer table.listView {font-size:0.95em;} /*}}}*/
/*{{{*/ @media print { #mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;} #displayArea {margin: 1em 1em 0em;} noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */ } /*}}}*/
<!--{{{--> <div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'> <div class='headerShadow'> <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span> </div> <div class='headerForeground'> <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span> <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span> </div> </div> <div id='mainMenu' refresh='content' tiddler='MainMenu'></div> <div id='sidebar'> <div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div> <div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div> </div> <div id='displayArea'> <div id='messageArea'></div> <div id='tiddlerDisplay'></div> </div> <!--}}}-->
<!--{{{--> <div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div> <div class='title' macro='view title'></div> <div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div> <div class='tagging' macro='tagging'></div> <div class='tagged' macro='tags'></div> <div class='viewer' macro='view text wikified'></div> <div class='tagClear'></div> <!--}}}-->
<!--{{{--> <div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div> <div class='title' macro='view title'></div> <div class='editor' macro='edit title'></div> <div macro='annotations'></div> <div class='editor' macro='edit text'></div> <div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div> <!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers: * [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar) * [[MainMenu]]: The menu (usually on the left) * [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened You'll also need to enter your username for signing your edits: <<option txtUserName>>
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]]) <<option txtUserName>> <<option chkSaveBackups>> [[SaveBackups]] <<option chkAutoSave>> [[AutoSave]] <<option chkRegExpSearch>> [[RegExpSearch]] <<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]] <<option chkAnimate>> [[EnableAnimations]] ---- Also see [[AdvancedOptions]]
<<importTiddlers>>
The Standard Template Library (STL) in C++ offers a highly efficient implementation of a variety of generic data structures and algorithms, which are proved to be one of the most prominent strength of C++. In C, unfortunately, most generic libraries such as [[GLIB|http://library.gnome.org/devel/glib/]] and [[GDSL|http://home.gna.org/gdsl/]] do not match STL in efficiency, largely due to the use of void* pointers which add considerable overhead on instantiation. In C, the only way to achieve the efficiency of STL is to use macro. Offering a generic marco library as efficient as STL is the ultimate goal of the klib project. In addition to using macros, klib also differs from other libraries in that each data structure or algorithm is implemented in one or two files, independent of all the other files in the library. To use klib, a developer only needs to copy one or two files to the source code tree without installing the library at all. Code dependency is never a problem with klib. Currently, klib implements the following components: * Data structures: vector, [[hash table|khash]] and B-tree * Algorithms: sorting, generic stream buffer and ~Hooke-Jeeves algorithm for nonlinear minimization * Miscellaneous: string, file operation over HTTP/FTP and FASTA/FASTQ format parser
[[About]] [[Download]]
* [[khash]]: a hash table library
The klib source code is only available from the [[SourceForge SVN|http://sourceforge.net/scm/?type=svn&group_id=240772]] for the time being. You can check out with: {{{ svn co https://klib.svn.sourceforge.net/svnroot/klib/trunk/klib klib }}} Alternatively, you may directly grab source code from [[SVN browse|http://klib.svn.sourceforge.net/viewvc/klib/trunk/klib/]] where files with different prefix are indenpendent of each other. Furthermore, if you plan to use klib, you will probably be interested in [[this benchmark|http://lh3lh3.users.sourceforge.net/udb.shtml]]. Source code of the benchmark is available from that page as well as from the klib SVN: {{{ svn co https://klib.svn.sourceforge.net/svnroot/klib/trunk/udb udb }}}
[[About]] [[Download]] [[Methodology]] [[Documentation]] [[Project Page|http://sourceforge.net/projects/klib/]] [[Developer Home|http://sourceforge.net/projects/klib/]]
To use klib effectively, it is very important to understand the methodology behind. This pages uses the [[khash]] library as an example to explain how to achieve generic programming in C. !!Example first Here is an example of using the [[khash]] library: {{{ #include "khash.h" KHASH_MAP_INIT_INT(32, char) int main() { int ret, is_missing; khiter_t k; khash_t(32) *h = kh_init(32); k = kh_put(32, h, 5, &ret); if (!ret) kh_del(32, h, k); kh_value(h, k) = 10; k = kh_get(32, h, 10); is_missing = (k == kh_end(h)); k = kh_get(32, h, 5); kh_del(32, h, k); for (k = kh_begin(h); k != kh_end(h); ++k) if (kh_exist(h, k)) kh_value(h, k) = 1; kh_destroy(32, h); return 0; } }}} The second line instantiates a hash table with {{{uint32_t}}} as the key type and {{{char}}} as the value type. {{{32}}} is the unique name of this type of hash table and all types and functions associated with this name are macro, which will be explained later. Macro {{{kh_init()}}} initiates a hash table and {{{kh_destroy()}}} frees it. {{{kh_put()}}} inserts a key and returns the iterator (or the position) in the hash table. {{{kh_get()}}} and {{{kh_del()}}} get a key and delete an element, respectively. Macro {{{kh_exist()}}} tests if an iterator (or a position) is filled with data. All ~APIs bear some similarity to C++'s {{{std::map}}}. !!Behind the library The skeleton of {{{khash.h}}} looks like this: {{{ #define KHASH_INIT(name, key_t, val_t, is_map, _hashf, _hasheq) \ typedef struct { \ int n_buckets, size, n_occupied, upper_bound; \ unsigned *flags; \ key_t *keys; \ val_t *vals; \ } kh_##name##_t; \ static inline kh_##name##_t *init_##name() { \ return (kh_##name##_t*)calloc(1, sizeof(kh_##name##_t)); \ } \ static inline int get_##name(kh_##name##_t *h, key_t k) \ ... \ static inline void destroy_##name(kh_##name##_t *h) { \ if (h) { \ free(h->keys); free(h->flags); free(h->vals); free(h); \ } \ } #define _int_hf(key) (unsigned)(key) #define _int_heq(a, b) (a == b) #define khash_t(name) kh_##name##_t #define kh_val(h, k) ((h)->vals[k]) #define kh_begin(h, k) 0 #define kh_end(h) ((h)->n_buckets) #define kh_init(name) init_##name() #define kh_get(name, h, k) get_##name(h, k) #define kh_destroy(name, h) destroy_##name(h) ... #define KHASH_MAP_INIT_INT(name, val_t) \ KHASH_INIT(name, unsigned, val_t, is_map, _int_hf, _int_heq) }}} {{{KHASH_INIT()}}} is a huge macro defining all the methods operating the hash table. It utilizes [[token concatenation|http://en.wikipedia.org/wiki/C_preprocessor#Token_concatenation]] to distinguish types and functions for hash tables with a different {{{name}}}. When {{{KHASH_MAP_INIT_INT(32, char)}}} is called, the C preprocessor will replace it with the following code: {{{ typedef struct { int n_buckets, size, n_occupied, upper_bound; unsigned *flags; unsigned *keys; char *vals; } kh_32_t; static inline kh_32_t *init_32() { return (kh_32_t*)calloc(1, sizeof(kh_32_t)); } static inline int get_32(kh_32_t *h, unsigned k) ... static inline void destroy_32(kh_32_t *h) { if (h) { free(h->keys); free(h->flags); free(h->vals); free(h); } } }}} The C preprocessor will also change the {{{main()}}} function into (macro {{{kh_exist(h,k)}}} is a little complex and not expanded for simplicity): {{{ int main() { int ret, is_missing; khiter_t k; kh_32_t *h = init_32(); k = put_32(h, 5, &ret); if (!ret) del_32(h, k); h->vals[k] = 10; k = get_32(h, 10); is_missing = (k == h->n_buckets); k = get_32(h, 5); del_32(h, k); for (k = 0; k != h->n_buckets; ++k) if (kh_exist(h, k)) h->vals[k] = 1; destroy_32(h); return 0; } }}} After the macro expansion, the example looks more like a standard C program. !!Macro vs. {{{void*}}} in generic programming Another way to realize generic programming is to store both keys and values as {{{void*}}}. However, in this case retrieving the value pointed by a pointer takes time and is likely to cause a cache miss. The compiler also has troubles with the {{{void}}} type and will not optimize the source code at best. In addition, a pointer itself costs typically 4 or 8 bytes of memory and this waste is significant if we are working with keys or values of small sizes such as integers. In contrast, generic programming with macro does not have all these problems. For example in this hash table implementation, each time a hash table is claimed with {{{KHASH_INIT()}}}, a complete set of operations of different names are inserted by the C preprocessor. These operations are as fast as what we can implement separately for each key-value types, and therefore we pay no overhead at all. Memory is not wasted, either, as we directly store keys and values in two separate arrays. The disadvantages of macro programming comes in three aspects. Firstly, when multiple types of hash tables are in use, source code with identical functionality but working for different types will all be included. However, this is really how efficiency is achieved and even C++ template cannot escape. Secondly, huge macros may cause a big headache in debugging as the C preprocessor will expand all the content in one line and a debugger is nearly useless in this case. Fortunately, we may {{{indent}}} the source code after preprocessing to make it debuggable. Thirdly, a macro library is less comprehensible at the first sight, but once we get used to it, a macro library actually provides a cleaner interface than {{{void*}}} libraries in my view. !!Conclusion In C, the best way to achieve generic programming is to use macros, with which a generic library can be as efficient as type-specific libraries.
a generic macro library in C
Klib
!!Synopsis * Functionality: generic hash table library (open address double hashing) * Library source code: {{{khash.h}}} * Testing program: {{{khash_test.c}}} * Dependency: none !!Basic Instantiation * {{{KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)}}}, where {{{name}}} is the unique name of the hash table, {{{khkey_t}}} is the key type, {{{khval_t}}} the value type, {{{kh_is_map}}} is false when value is ignored, {{{__hash_func}}} is a function or macro that hashes a key into a 32-bit integer, and {{{__hash_equal}}} tests if two keys are equal. !!Derived instantiation * {{{KHASH_SET_INIT_INT(name)}}} defines a set with {{{uint32_t}}} as the key type. * {{{KHASH_MAP_INIT_INT(name, khval_t)}}} defines a map with {{{uint32_t}}} as the key type and {{{khval_t}}} as the value type. * {{{KHASH_SET_INIT_INT64(name)}}} and {{{KHASH_MAP_INIT_INT64(name, khval_t)}}} define a set and a map, respectively, with {{{uint64_t}}} as the key type. * {{{KHASH_SET_INIT_STR(name)}}} and {{{KHASH_MAP_INIT_STR(name, khval_t)}}} define a set and a map, respectively, with {{{const char*}}} as the key type. !!Methods, Macros and Typedefs * {{{khint_t}}}: an alias of {{{uint32_t}}} at the moment. * {{{khash_t(sym)}}}: type of a hash table named as {{{sym}}}. * {{{khash_t(sym) *kh_init(sym)}}}: initiate a hash table named as {{{sym}}} and return the pointer to the hash table. * {{{void kh_destroy(sym, khash_t(sym) *h)}}}: destroy {{{h}}}. * {{{void kh_clear(sym, khash_t(sym) *h)}}}: empty {{{h}}} without freeing memory or changing the capacity. * {{{void kh_resize(sym, khash_t(sym) *h, khint_t s)}}}: enlarge the capacity of {{{h}}} to at least {{{s}}}. * {{{khint_t kh_size(khash_t(sym) *h)}}}: return the number of elements stored in {{{h}}}. * {{{khint_t kh_n_buckets(khash_t(sym) *h)}}}: return the number of buckets (or capacity) of {{{h}}}. * {{{khint_t kh_begin(khash_t(sym) *h)}}}: return the start iterator of {{{h}}}. Return value always equals zero. * {{{khint_t kh_end(kash_t(sym) *h)}}}: return the end iterator of {{{h}}}. Return value always equals {{{kh_n_bucket(h)}}}. * {{{int kh_exist(khash_t(sym) *h, khint_t i)}}}: test if iterator {{{i}}} of {{{h}}} contains an element. This macro is usually used in the traversal of hash table. See the example in [[Methodology]]. * {{{khint_t kh_get(sym, khash_t(sym) *h, khkey_t k)}}}: get a key {{{k}}} from {{{h}}} and returns the position (iterator) upon success or {{{kh_end(h)}}} upon failure. * {{{khint_t kh_put(sym, khash_t(sym) *h, khkey_t k, int *r)}}}: insert a key {{{k}}} into {{{h}}} and return the position (iterator) of the inserted element. {{{*r}}} is changed to 0 if the key is already present, or non-zero otherwise. * {{{void kh_del(sym, khash_t(sym) *h, khint_t i)}}}: delete elemented at position {{{i}}} from {{{h}}}. * {{{khkey_t kh_key(khash_t(sym) *h, khint_t i)}}}: return the key at position {{{i}}}. Modifying key will lead to unexpected errors. * {{{khval_t kh_value(khash_t(sym) *h, khint_t i)}}}: return the value at position {{{i}}}. The value can appear as L-value (i.e. be modified). Using this macro on a hash set will lead to segfault. * {{{khval_t kh_val(khash_t(sym) *h, khint_t i)}}}: an alias of {{{kh_value(h, i)}}}. !!Important notice * When pointers are inserted to the hash table either as keys or values, it is the user's responsibility to manage the memory for these pointers. In particular, for a hash table with {{{const char*}}} keys, memory used for strings must not be modified once they are inserted; when the hash table is destroyed, the user must manually free the memory of the keys.