HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
dzaima
CBQN
C2023–2026
dzaima / CBQN

CBQN

a BQN implementation in C

2Distinct people
13Mentions
0Explicit recommenders
412GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

a BQN implementation in C

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

No recommendation phrase was found in the indexed comments.

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

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 8–Nov 15 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/15/2026, 10:49:33 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 year13 dated mentions

Observed mentions: 2023-05-07 19:04:57 UTC to 2026-05-26 12:25:19 UTC.

0123452023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments20232024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments20242025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 4 mentions; 0 submissions, 4 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

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
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC505
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC303
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC404
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC101

What Hacker News says

5 sources
Worth pointing out that this can depend a lot more on fiddly details than you might expect. In particular, you're dealing with a small fixed width allowing the hash to be stored in the table instead of the key. The article emphasizes variable-length keys, and I don't see any specialization on key sizes (if 4- and 8-byte keys aren't common then this makes sense; if they are then I'd expect dedicated table code for those sizes to be valuable). And set lookups are also just a bit different from value lookups. I think these cases are different enough that I have no idea if the results would carry over, although I can see how the bidirectional approach would reduce probing more than RH which seems good. ...and since I've done a lot of work with Robin Hood on small-key lookups, I can point out some little tweaks that have made a big difference
Read the rest
for me. I have 8-byte lookups at just over 3ns/lookup[0], albeit at a very low load factor, typically <50%. A key step was to use the maximum possible hash as a sentinel value, handling it specially in case it shows up in the data. This way, instead of probing until finding an empty bucket or greater hash, probing just finds the first slot that's greater than or equal to the requested key's hash. So the lookup code[1] is very simple (the rest, not so much). The while loop is only needed on a hash collision, so at a low load factor a lookup is effectively branchless. However, these choices are specialized for a batched search where the number of insertions never has to be higher than the number of searches, and all the insertions can be done first. And focused on small-ish (under a million entries) tables. [0] https://mlochbaum.github.io/bencharray/pages/search.html [1] https://github.com/dzaima/CBQN/blob/5c7ab3f/src/singeli/src/...
In Building a faster hash table for high performance SQL joins
The kind of things you can use direct SIMD for is a reasonably-different space than array languages; while some things can translate reasonably, APL-likes get much less pretty on operations where elements don't have homogeneous meaning/mapping, e.g.: the base64 conversion of OP. (for reference, I work on https://github.com/dzaima/CBQN, an implementation of BQN, an APL derivative, and we have a DSL for implementing SIMD primitives for it (and sometimes scalar ones too): https://github.com/mlochbaum/Singeli)
In Designing a SIMD Algorithm from Scratch
In a project I'm working on[0], there's an array object type used throughout, which can sometimes point to arbitrary data elsewhere. In a funky edge-case[1], such an array can be built with an unaligned data pointer. Thus, if gcc/clang started seriously utilizing aligned pointer accesses everywhere, nearly every single load & store in the entire project would have to be replaced with something significantly more verbose. Maybe in a more fancy language you could have ptr<int> vs unaligned_ptr<int> or similar, but in C you kinda just have compiler flags, and maybe __attribute__-s if you can spare some verbosity. C UB is often genuinely useful, but imo having an opt-out option for certain things is, regardless, a very reasonable request. [0]: https://github.com/dzaima/CBQN [1]: Any regularly allocated array has appropriate alignment. But the
Read the rest
re are some functions that take a slice of the array "virtually" (i.e. pointing to it instead of copying), and another one that bitwise-reinterprets an array to one with a different element type (again, operating virtually). This leads to a problem when e.g. taking i8 elements [3;7) and reinterpreting as an i32 array. A workaround would be to make the reinterpret copy memory if necessary (and this would have to be done if targeting something without unaligned load/store), but that'd ruin it being a nice O(1).
In GCC always assumes aligned pointer accesses (2020)
> An algorithm which works well for hardware implementing 128-bit vectors might be quite bad for one implementing 2048-bit vectors Yeah, that's definitely a concern. I do wish that RVV had some built-in way to cap the width in a request (of course emulatable by doing a min() manually), but beyond that it's up to the hardware I guess. > but they are likely to also have many loops which cannot be vectorised performance-portably Such would also likely not be autovectorizable either, making whether it can be done performance-portably much less significant due to the much lower frequency of manually-vectorized things. In most situations, if you're at the point of manually vectorizing some piece of code, it's enough of a bottleneck that you can tune it for whatever (set of) hardware you're targeting. I, as someone who enjoys writing manually ve
Read the rest
ctorized stuff, don't particularly like that added burden, but it's a pretty reasonable decision. > I have some half-written code to use vector shuffles in place of loads for indexing small arrays in the j interpreter Marshall has written that for CBQN[0] for AVX2, primarily tuned for Intel[1], but yeah the boundary is pretty sketchy to have to hard-code and RVV could definitely make it worse. But base 128-bit RVV, with LMUL=8 provides 1024-bit lookup tables in a single instruction, which should at least mostly negate the desire of manually blending multiple, which is where you'd start desiring tuning. Though, I wouldn't be surprised if an LMUL=8 in-register shuffle on some hardware would be slower than a memory gather for some element widths, which'd suck. > but n/4 starts to cause problems The existence of LMUL=8 means that hardware will necessarily have to figure out some way to split single instructions across many cycles. Arguably that's by itself pretty bad, but at least I'd imagine that further splitting up should be largely free, though the register file size problem of course persists. > sve would effectively standardise on 256 bits Yeah, I feel like 256 is a pretty nice sweet spot too. In regards to higher-level hardware interfacing, I'd worry that what it'd do would be making everything uniformly slow, instead of making everything uniformly fast, thus potentially not actually being any better than status quo. And such would be at a very significantly worse spot in terms of performance-portable tuning than RVV. Not to mention that nicer array operation behavior wouldn't help the vast majority of code which is very scalar & dispatchy. And an equivalent of this would be to just share programs in IR and not machine code form, which we can already do, but don't really for whatever reason (if requiring near-native speed; otherwise there's JS/WASM/JVM. Then there's LLVM IR/MLIR but I haven't heard of it being used as a shared binary format. Maybe Julia would count with it compiling LLVM IR at runtime, and it having high-level array ops?) [0]: https://github.com/dzaima/CBQN/blob/a67a19dd0bf6be5eb765cac8... - wd is bit width of the table elements, xl - number of such elements in the table. Beyond that, it just does the expected thing of blending permutes & shuffles via some Singeli that not even I have bothered to particularly understand [1]: "Select" section at https://mlochbaum.github.io/bencharray/pages/summary.html on Tiger Lake i5-1135G7, with similarly scaling results on haswell & skylake
In Vector ALU Patterns
By "large" I mean compared to the fraction of needs-slow-emulation things present currently in C (which is currently approximately zero, other than using integer/float types unsupported on the target hardware (and maybe multiplication/division), but that's comparatively extremely easy to determine). Maybe my use-case - implementing an array language - is unusually unfit for being done in a generic way, but I just don't see how it (or much of anything outside of very trivial things) would be reasonable to figure out how to do performantly with anything other than either manually using intrinsics, or with custom-written abstractions around such with known worst-case emulation amount (we're doing[0] the latter with a DSL[1] that's basically a basic compile-time code generator; that just leaves unsupported things undefined on any given archit
Read the rest
ecture, and in most occurrences of hitting that I've found ways to write things avoiding expensive emulation). [0]: https://github.com/dzaima/CBQN/tree/master/src/singeli/src [1]: https://github.com/mlochbaum/Singeli
In Ask HN: Why are there no traditional language compilers that target the JVM?

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.