HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
attractivechaos
klib
C2013–2023
attractivechaos / klib

klib

A standalone and lightweight C library

24Distinct people
25Mentions
3Explicit recommenders
4.7KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

A standalone and lightweight C library

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

I recommend looking at the khash implementation https://github.com/attractivechaos/klib/blob/master/khash.h It's very competitive to optimized implementations like abseil and…

bufo used a recommendation phrase. 3 indexed comments match. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:56:07 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year25 dated mentions

Observed mentions: 2013-10-26 22:33:58 UTC to 2023-11-12 14:58:17 UTC.

0123452013-01-01 00:00:00 UTC to 2014-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments20132014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 1 mentions; 1 submissions, 0 comments2015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 2 mentions; 1 submissions, 1 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments20182019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 4 mentions; 0 submissions, 4 comments2023

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20132013-01-01 00:00:00 UTC2014-01-01 00:00:00 UTC202
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC110
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC211
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC101
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC202
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC505
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC101
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC202
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC505
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC000
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC404

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
Klib: a Generic Library in C Overview Klib is a standalone and lightweight C library distributed under MIT/X11 license. Most components are independent of external libraries, except the standard C library, and independent of each other. To use a component of this library, you only need to copy a couple of files to your source code tree without worrying about library dependencies. Klib strives for efficiency and a small memory footprint. Some components, such as khash.h, kbtree.h, ksort.h and kvec.h, are among the most efficient implementations of similar algorithms or data structures in all programming languages, in terms of both speed and memory use. A new documentation is available here which includes most information in this README file. Common components khash.h: generic hash table with open addressing. kbtree.h: generic search tree based on B-tree. kavl.h: generic intrusive AVL tree. ksort.h: generic sort, including introsort, merge sort, heap sort, comb sort, Knuth shuffle and the k-small algorithm. kseq.h: generic stream buffer and a FASTA/FASTQ format parser. kvec.h: generic dynamic array. klist.h: generic single-linked list and memory pool. kstring.{h,c}: basic string library. kmath.{h,c}: numerical routines including MT19937-64 pseudorandom generator, basic nonlinear programming and a few special math functions. ketopt.h: portable command-line argument parser with getopt_long-like API. Components for more specific use cases ksa.c: constructing suffix arrays for strings with multiple sentinels, based on a revised SAIS algorithm. knetfile.{h,c}: random access to remote files on HTTP or FTP. kopen.c: smart stream opening. khmm.{h,c}: basic HMM library. ksw.(h,c}: Striped Smith-Waterman algorithm. knhx.{h,c}: Newick tree format parser. Methodology For the implementation of generic containers, klib extensively uses C macros. To use these data structures, we usually need to instantiate methods by expanding a long macro. This makes the source code look unusual or even ugly and adds difficulty to debugging. Unfortunately, for efficient generic programming in C that lacks template, using macros is the only solution. Only with macros, we can write a generic container which, once instantiated, compete with a type-specific container in efficiency. Some generic libraries in C, such as Glib, use the void* type to implement containers. These implementations are usually slower and use more memory than klib (see this benchmark). To effectively use klib, it is important to understand how it achieves generic programming. We will use the hash table library as an example: #include "khash.h" KHASH_MAP_INIT_INT(m32, char) // instantiate structs and methods int main() { int ret, is_missing; khint_t k; khash_t(m32) *h = kh_init(m32); // allocate a hash table k = kh_put(m32, h, 5, &ret); // insert a key to the hash table if (!ret) kh_del(m32, h, k); kh_value(h, k) = 10; // set the value k = kh_get(m32, h, 10); // query the hash table is_missing = (k == kh_end(h)); // test if the key is present k = kh_get(m32, h, 5); kh_del(m32, h, k); // remove a key-value pair for (k = kh_begin(h); k != kh_end(h); ++k) // traverse if (kh_exist(h, k)) // test if a bucket contains data kh_value(h, k) = 1; kh_destroy(m32, h); // deallocate the hash table return 0; } In this example, the second line instantiates a hash table with unsigned as the key type and char as the value type. m32 names such a type of hash table. All types and functions associated with this name are macros, 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. An immediate question is this piece of code does not look like a valid C program (e.g. lacking semicolon, assignment to an apparent function call and apparent undefined m32 'variable'). To understand why the code is correct, let's go a bit further into the source code of khash.h, whose skeleton looks like: #define KHASH_INIT(name, SCOPE, 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; \ SCOPE inline kh_##name##_t *init_##name() { \ return (kh_##name##_t*)calloc(1, sizeof(kh_##name##_t)); \ } \ SCOPE inline int get_##name(kh_##name##_t *h, key_t k) \ ... \ SCOPE 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_value(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, static, unsigned, val_t, is_map, _int_hf, _int_heq) KHASH_INIT() is a huge macro defining all the structs and methods. When this macro is called, all the code inside it will be inserted by the C preprocess to the place where it is called. If the macro is called multiple times, multiple copies of the code will be inserted. To avoid naming conflict of hash tables with different key-value types, the library uses token concatenation, which is a preprocessor feature whereby we can substitute part of a symbol based on the parameter of the macro. In the end, the C preprocessor will generate the following code and feed it to the compiler (macro kh_exist(h,k) is a little complex and not expanded for simplicity): typedef struct { int n_buckets, size, n_occupied,
Read the full README on GitHub

What Hacker News says

25 sources
In my example the table stores the hash codes themselves instead of the keys (because the hash function is invertible) Oh, I see, right. If determining the home bucket is trivial, then the back-shifting method is great. The issue is just that it’s not as much of a general-purpose solution as it may initially seem. In the bad cases, it's really bad. With a different algorithm (Robin Hood or bidirectional linear probing), the load factor can be kept well over 90% with good performance, as the benchmarks in the same repo demonstrate. I’ve seen the 90% claim made several times in literature on Robin Hood hash tables. In my experience, the claim is a bit exaggerated, although I suppose it depends on what our idea of “good performance” is. See these benchmarks, which again go up to a maximum load factor of 0.95 (although boost and Absl forcibly
Read the rest
grow/rehash at 0.85-0.9): https://strong-starlight-4ea0ed.netlify.app/ Tsl, Martinus, and CC are all Robin Hood tables (https://github.com/Tessil/robin-map, https://github.com/martinus/robin-hood-hashing, and https://github.com/JacksonAllan/CC, respectively). Absl (from Google) and Boost are well-known C++ SIMD-based hash tables. Khash (https://github.com/attractivechaos/klib/blob/master/khash.h) is, I think, an ordinary open-addressing table using quadratic probing. Fastmap is a new, yet-to-be-published design that is fundamentally similar to bytell (https://www.youtube.com/watch?v=M2fKMP47slQ) but also incorporates some aspects of the aforementioned SIMD maps (in particular, it stores a 4-bit fragment of the hash code to avoid most false key comparisons). As you can see, all the Robin Hood maps spike upwards dramatically as the load factor gets high, becoming as much as 5-6 times slower at 0.95 vs 0.5 in one of the benchmarks (uint64_t key, 256-bit struct value: Total time to erase 1000 existing elements with N elements in map). Only the SIMD maps (with Boost being the clear better performer of the two) and Fastmap appear mostly immune to load factor in all benchmarks, although the SIMD maps do - I believe - use tombstones for deletion in at least some cases. I’ve only read briefly about bi-directional linear probing – never experimented with it.
In Hashmaps in Factor are faster than in Zig
Smart pointers in C, wow, who would imagine? Although I must say, I'll probably never use this in a project because: - Using C for anything but systems programming is either malevolence or for fun, there's no pratical reason for it. In this case you probably don't want to have external dependencies only to have data structures. - Having dependencies in C is an absolute pain in the ass unless it's a single header file (such as sqlite). It also makes it much harder to make the codebase portable. I might try it out though just for gigs and laughs. Tangentially, I wonder why more C developers don't use self-contained dependencies such as GNULib [0], Klib [1], or APR [2] instead of reimplementing base primitives. It's so common for C projects to reimplement every single thing from scratch. "If you want to make a pie from scratch, you must firs
Read the rest
t invent the universe" kind of thing. Managing packages is a pain, but reimplementing an efficient battle-tested hash table is even worse IMO. Would be happy to hear it from people who worked (professionally) with C about this. [0]: https://www.gnu.org/software/gnulib/ [1]: https://github.com/attractivechaos/klib [2]: https://apr.apache.org/
In STC – Smart Template Containers for C
I’m actually implementing that right now for my own use, as a pre-processor. There is a much more advanced design and implementation at “A defer mechanism for C” (December 2020): https://gustedt.wordpress.com/2020/12/14/a-defer-mechanism-f... For my own purposes, I think I can live without handling stack unwinding so I continue working on my pre-processor. Since the pre-processor is not yet finished, there I use a vector¹ of {.pointer, .destructor} where I put objects after initialization, with one macro at the end of each managed scope that calls the destructors for that scope in reverse order, then another macro meant for the function exit points that calls all the destructors in that vector. This has been built many times before by other people of course, it’s just an exercise to see which difficulties arise. ¹ Vector, growable array:
Read the rest
I did my own trivial type-generic growable array, with the classic {.capacity, .len, .items}, but again there are many previous implementations. The two I’ve found more interesting are: - “C Template Library (CTL)”: https://github.com/glouw/ctl - “Klib: a Generic Library in C”: https://github.com/attractivechaos/klib/
In Beej’s Guide to C Programming [pdf]
Anyone who does too much C would know that manually implementing associative array (dictionary) is not fun. I started to use two implementations for my work, both worked pretty well for the things they are good at (and all of them are as "generic" as you can get from C): khash: https://github.com/attractivechaos/klib/blob/master/khash.h The interface I really liked, and you can customize the hash equality functions. rb from jemalloc: https://github.com/jemalloc/jemalloc/blob/dev/include/jemall... The interface is a bit wacky, but it is flexible enough for my needs. rb shines when you need range queries (keys less than, more than etc.)
In Show HN: libcodr7 – fundamental collections in the spirit of C
For C vectors, look at stb's[1] stretchy_buffer[2] or klib's[3] kvec[4]. The basic concept of these is they use macros to specify the type/size of the elements so you can have generic containers in C. For hash's, you can also look at klib's khash [5] [1] https://github.com/nothings/stb [2] https://github.com/attractivechaos/klib [3] https://github.com/nothings/stb/blob/master/stretchy_buffer.... [4] https://github.com/attractivechaos/klib/blob/master/kvec.h [5] http://attractivechaos.github.io/klib/#Khash%3A%20generic%20...
In One year of C

Showing the 15 most recent of 25 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.