Library / SDK
Tracktion/choc avatar
Tracktion/choc

CHOC: header-only C++ utilities you copy into your project

A collection of header only classes, permissively licensed, to provide basic useful tasks with the bare-minimum of dependencies.

862 stars87 forksC++NOASSERTION

At a glance

What is it?
CHOC is a grab bag of dependency-free, header-only C++ classes, from a string trimming utility and an xxHash implementation to a zlib wrapper, a zip reader and an HTTP and WebSocket server. The README is explicit about the rules, strictly header-only, permissively licensed, self-contained files you can cherry-pick, and clean modern C++ that is easy to skim.
Who is it for?
Adopt CHOC when you keep rewriting the same small helpers, a string trimmer, a base64 encoder, a file watcher, an HTTP server, and you would rather copy one header than take on a dependency, because every file in it is designed to be self-contained and to compile with nothing added to your build system.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The standard library has holes, and filling them is repetitive

CHOC stands for Classy Header Only Classes, and the README describes it as a random grab-bag of header-only, dependency-free C++ classes.

The problem it is written against is stated plainly. When you start trying to write a C++ project of any size, you soon find gaping holes in what the standard library provides, and to fill them you either write lots of helper functions yourself or trawl the web for third-party libraries that come with baggage, messy build requirements, scads of compiler warnings, awkward licences and so on.

The author's framing is personal, that they got tired of reimplementing the same little helper classes in different projects, and CHOC is an attempt at preventing future wheel reinvention.

Then come the rules, and they are the design. Everything is strictly header-only, so you include the file you want and nothing needs adding to your build system. Everything is permissively ISC licensed, so it should pass silently under the noses of even the most zealous legal teams. Each file is as self-contained as possible, so if you only need a couple of the classes you can cherry-pick a few headers into your project rather than drag the whole repository along. And the code should be clean, consistent, concise, modern C++, not too simple, not too over-generic or fancy, easy to skim-read and find what you are looking for, self-documenting where possible with decent comments.

The stated audience is in the last line: people who just want to use some decent library code without also spending their afternoon fighting CMake or looking up the right compiler flags.

Header-only means a file, not a dependency

The first rule has consequences that are worth spelling out, because they are the reason the library is shaped this way.

A conventional third-party library arrives with a package manager, a version constraint, a build integration and a transitive dependency tree, and every one of those is a thing that can break. CHOC's answer is that there is no package, no version constraint in your build, and no transitive tree. You copy choc/text/choc_StringUtilities.h into your source tree, you include it, and it compiles.

The third rule, that each file is as self-contained as possible, is what makes that work in practice. A file that is self-contained has no dependency on another CHOC header, so copying it is a single-file operation rather than a subtree copy. The README frames this as being able to cherry-pick at most a few CHOC headers into your project and not need to drag the whole repo along.

The cost of that model is the other side of the coin. Because there is no version, there is no upgrade path: when the author fixes something in a header you have copied, your copy does not change. And because the code lives in your repository, it becomes your code to maintain, which for a header that is 100 lines of obvious code is a reasonable trade and for a header that is a thousand lines of subtle code is not.

So the practical test for CHOC is the size of the file. For the small utilities, copying is the cheapest option available. For the larger ones, the HTTP server or the WebView, the question is whether you would rather vendor that much code than take on a dependency.

Text and file utilities, and the things you always rewrite

The text and files section is the part of CHOC that most obviously saves time, because it covers exactly the operations that every project ends up writing for itself.

The string utilities handle trimming, splitting, joining and comparisons, and the README's complaint about them is that for the sake of god you should not need to write your own library just to trim a string. The same header also carries the more esoteric operations, pretty-printing durations and sizes, URI encoding and similar. There is a separate UTF-8 header with validation and iteration classes, which is the kind of thing that looks simple until you meet malformed input.

The file utilities provide single-call ways to do obvious things, loading a file's content, saving a string into a file, creating self-deleting temporary files. A file watcher class monitors changes to a file or a folder. A CodePrinter class helps create indented code listings, which is a small tool that is genuinely annoying to write well. An HTML generator builds a tree of DOM objects and produces HTML text from it. A text table generator takes an array of strings and tabulates it so the columns line up. A file wildcard matcher, which the author claims is the cleanest possible implementation of the algorithm and invites you to prove them wrong. And a command-line argument helper that simplifies a lot of basic argument parsing.

Taken together that is a header per topic rather than a header per function, which is the right granularity for the cherry-picking model.

Containers, typed values and memory utilities

The containers section fills three specific gaps.

The first is a span class, described as filling the gap until we can finally use std::span, which is the kind of item that exists in every codebase that was written before its standard library equivalent arrived and that nobody ever deletes. The second is a SmallVector, which offers a std::vector interface but has pre-allocated internal storage, for the case where you know the size at compile time and want the vector's ergonomics without the allocation. The third is the type and value classes, which can represent typed values but also build them dynamically and serialise them to a compact binary format or as JSON, which is a genuinely awkward thing to need and a reasonable thing to have found once.

There is also a set of COM helper classes, and the README's comment on them is that everyone hates COM but sometimes you need some.

The memory section is the most conventional part, and it is the part you will find in any utility library. An aligned memory block, one of those classes you always end up needing for some reason. A fast memory pool allocator. Helpers for reading and writing data with different endianness. Integer compression and zigzag encoding functions. A base64 encoder and decoder. And an implementation of the xxHash very-fast-but-pretty-secure hash algorithm, which is the author's phrasing and which is also the reason to prefer it to the standard library's hash in a hot path.

The unit test framework, at about 100 lines, sits in the platform section and was written so that CHOC could self-host its own unit tests without any external dependency. The author adds that it turned out surprisingly useful, which is the usual outcome for a test harness you wrote for yourself.

The heavier headers: zlib, zip, HTTP and WebSocket

Further down the list the headers stop being small utilities and start being real components, which changes the trade-off.

There is a one-file header-only encapsulation of zlib that exposes std::iostream compatible classes for compressing and decompressing data, so you can treat a compressed stream like any other stream. There is a Zip file reader and a decompressor class. And there is an HTTP and WebSocket server class, which the README introduces with a sentence that tells you its purpose: life is too short to learn how boost::beast works and write all the boilerplate required just to serve some content and talk down a web-socket, so this class hides all the horribleness behind a very simple API.

The platform section has cross-platform dynamic library loading, and beside it an in-memory DLL loader, which the README calls tempting but probably perilous and describes as loading a DLL from memory instead of a file, on Windows only. That description is a warning rather than a recommendation, and it is the one header in the library where the caution is the author's own.

There is also a small platform-detection header, headers that disable and re-enable warnings for when you have to include messy third-party code in an otherwise faultless codebase, and a system for collecting all the open-source licences your project uses into a single string for display to a user, which is a licence compliance tool rather than a programming convenience.

The theme running through all of these is the one the author states: no build system to configure, no dependencies to resolve, and code you can read in an afternoon.

GUI headers and the single-header WebView

The GUI section is the smallest, with bare-bones message loop control functions, a timer class for cross-platform message loop timer callbacks, and what the README calls the world's most hassle-free single-header WebView class.

What the WebView gives you is an embedded browser view, either as a desktop window or added to an existing one, and a way to interact with it by invoking JavaScript and binding callback C++ functions to be called from JavaScript. The example files in the repository include webview_desktop_app.cpp and javascript_integration.cpp, which are the two halves of that.

The detail the README singles out is specific to Windows: the class provides the modern Edge browser without you needing to install extra SDKs to compile it, and without any need to link or redistribute the Microsoft loader, and the sentence is cut off in the text available here.

That is the interesting engineering claim, because the usual way to embed a browser on Windows is to use the WebView2 runtime and to ship the loader, and a header-only library that hides that has to do something unusual to make it work. The README's own framing, hassle-free, is the author's characterisation rather than a measured result, and the examples directory is where you would look to see how much of it is real.

The dependency question is worth flagging for a header-only library, because a WebView on any platform is not dependency-free in the strict sense. It is dependency-free in the build-system sense, which is the sense the rules are written in.

The licence question, and the parts the README does not list

Two things about the repository itself are worth checking before you copy anything.

The first is the licence. The README says everything in CHOC is permissively ISC licensed, and there is a LICENSE.md in the repository. The repository metadata, however, records the licence as a custom one that GitHub cannot classify, which is what happens when a file is present but its contents do not match a licence the site recognises. The README's statement is clear and the file is there to be read, so this is a formality, but reading LICENSE.md is the correct move rather than relying on a badge.

The second is that the README's highlights are not the whole library. The examples directory lists audio_beep_player.cpp, audio_operations.cpp, audio_sine_wave.cpp, midi_file_processing.cpp, threading_patterns.cpp and fifo_producer_consumer.cpp, none of which appear in the feature list in the text available here. So there is an audio and MIDI component, a threading component and a FIFO example that the highlights do not mention, and the examples directory is the better guide to the actual surface area.

The rest of the tree is conventional and tells you the project is actively worked on. There is a CMakeLists.txt at the root, an examples/CMakeLists.txt, a tests/ directory, VERSION.txt, CONTRIBUTING.md, a CLAUDE.md, a tidy_whitespace.py script, and a .github/ directory. The README itself gives no build or install commands, which is consistent with the whole design: the documented way to use CHOC is to take the header you need and include it, and the build system in the repository exists for the tests and the examples rather than for consumers.

There are no GitHub releases, so the version lives in VERSION.txt and in the repository itself, and the last push was on 2026-10-16, with the repository not archived.

Editorial conclusion

Adopt CHOC when you keep rewriting the same small helpers, a string trimmer, a base64 encoder, a file watcher, an HTTP server, and you would rather copy one header than take on a dependency, because every file in it is designed to be self-contained and to compile with nothing added to your build system. Do not adopt it as a package-managed dependency, since the whole premise is that you vendor the files, and treat the heavier headers with more care, since the in-memory DLL loader is described by its own author as tempting but probably perilous. Before you copy anything, read the licence file rather than the badge, because the repository's licence classification is custom while the README states the terms are ISC, and check which C++ standard your project needs, since some of these utilities exist only to fill gaps that later standards closed.

Frequently asked questions

What is CHOC and how do I use it?

CHOC is a collection of header-only, dependency-free C++ classes. The README states that you just include the file you want and nothing needs adding to your build system, and that each file is self-contained enough to cherry-pick into a project.

What is in the CHOC library?

The highlights cover string and file utilities, UTF-8 handling, a file watcher, a CodePrinter, an HTML generator, a text table generator, a wildcard matcher, a span class, a SmallVector, typed value classes with JSON and binary serialisation, aligned memory blocks, a pool allocator, endianness helpers, base64, xxHash, a zlib wrapper, a zip reader, an HTTP and WebSocket server, dynamic library loading and a single-header WebView.

What licence does CHOC use?

The README says everything in CHOC is permissively ISC licensed, and a LICENSE.md file sits in the repository root, although the repository's own licence metadata is recorded as a custom classification. Read the LICENSE file before reusing the code.

Does CHOC need a build system or dependencies?

No, and that is the point of the first rule in the README: everything is strictly header-only, so including the file is all that is needed. The repository does contain a CMakeLists.txt, a tests directory and an examples directory with its own CMakeLists.txt, but those serve the project itself rather than consumers.

Official sources

  1. Issues
  2. README
  3. Tracktion/choc on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tracktion-choc.svg)](https://hysenlabs.com/projects/tracktion-choc)

Was this useful?