A tiny, URL-friendly, unique string ID generator for C++, implementation of ai's nanoid!
Safe. By default it uses the operating system's cryptographically secure random source: getrandom on Linux, arc4random_buf on macOS, BSD and Android, BCryptGenRandom on Windows. You can plug in a source of your choice (OpenSSL, Crypto++, Botan, LibCrypto, ...) using the API.
Thread-safe. The default generator can be used from any number of threads at once. See Thread Safety for custom generators.
Compact. It uses more symbols than UUID (A-Za-z0-9_-)
and has the same number of unique options in just 21 symbols instead of 36.
Fast. An ID with default settings takes about 0.1 µs on Linux (measured on a Ryzen 9 5950X).
nanoid needs CMake 3.10 or newer. Whichever way you add it, link the nanoid::nanoid target:
target_link_libraries(your_target PRIVATE nanoid::nanoid)Installed package:
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build && cmake --install buildfind_package(nanoid 4 CONFIG REQUIRED)Subproject or git submodule:
add_subdirectory(external/nanoid_cpp)FetchContent (CMake 3.14+):
include(FetchContent)
FetchContent_Declare(nanoid GIT_REPOSITORY https://github.com/mykolamor/nanoid_cpp GIT_TAG 4.0.1)
FetchContent_MakeAvailable(nanoid)CPM.cmake:
CPMAddPackage(NAME nanoid GITHUB_REPOSITORY mykolamor/nanoid_cpp GIT_TAG 4.0.1)vcpkg: the port is in this repository, so point vcpkg at its ports folder
(--overlay-ports=<nanoid_cpp>/ports, or VCPKG_OVERLAY_PORTS) and depend on nanoid-cpp.
Then use find_package(nanoid CONFIG REQUIRED) as above.
As a subproject, nanoid's examples, command-line tool and install rules are off by default.
Set NANOID_INSTALL=ON if your project installs targets that link nanoid.
The default method uses URL-friendly symbols (A-Za-z0-9_-) and returns an ID
with 21 characters (to have a collision probability similar to UUID v4).
std::string id = nanoid::generate();
//id := "Uakgb_J5m9g-0JDMbcJqLJ"Symbols -,.() are not encoded in the URL. If used at the end of a link
they could be identified as a punctuation symbol.
If you want to reduce ID length (and increase collisions probability), you can pass the size as an argument:
std::string id = nanoid::generate(10);
//id := "IRFa-VaY2b"If you want to change the ID's alphabet or length you can pass alphabet and size.
std::string id = nanoid::generate("1234567890abcdef", 10);
//id := "4f90d13a42"The alphabet must contain 1 to 256 symbols. Multi-byte UTF-8 characters can't be used. Repeated symbols are allowed but make those symbols more likely.
To generate many IDs with the same alphabet, create a generator once. It checks the alphabet when constructed:
nanoid::custom_alphabet generate_id("1234567890abcdef", 10);
std::string id = generate_id(); // 10 symbols
std::string short_id = generate_id(5); // 5 symbolsThe default alphabet is available as nanoid::url_alphabet.
You can replace the default generator in two ways:
- Derive from
nanoid::crypto_random_baseand implementnext_bytes. See examples/openssl. - Wrap a standard random engine with
nanoid::engine_random<G>. See examples/mt19937.
For instance, to use a seed-based generator:
nanoid::engine_random<std::mt19937> random(10);
auto id = nanoid::generate(random, "abcdef", 10);
//id := "dddffadeab"engine_random<G> takes only uniformly random bytes from each output.
The engine has to produce at least 8 random bits per call.
Seed-based engines like std::mt19937 are not cryptographically secure:
their output can be predicted after observing enough IDs.
Use them only where IDs don't have to be unguessable, e.g. reproducible IDs in tests.
The default generator is thread-safe: generate() can be called from any number of threads at once.
When you pass your own generator, thread safety is up to that generator.
nanoid::engine_random<G> is not thread-safe, because standard engines keep internal state.
Give each thread its own instance (e.g. with thread_local), or guard a shared one with a mutex.
Don't share one instance between concurrent generate calls.
On Linux, the default generator buffers random bytes per thread, which is faster on average, but some calls are slower when the buffer refills.
For more uniform call times, build with -DNANOID_RANDOM_BUFFER=OFF (or define NANOID_DISABLE_RANDOM_BUFFER without CMake).
To put the API in another namespace than nanoid, set -DNANOID_NAMESPACE=your_namespace.
CMake passes it on to everything that links nanoid::nanoid.
Without CMake, define NANOID_NAMESPACE identically for nanoid and all code using it, or linking fails.
nanoid also builds a nanoid command-line tool (NANOID_BUILD_CLI, on when nanoid is built on its own):
$ nanoid
Uakgb_J5m9g-0JDMbcJqLJ
$ nanoid --size 10 --alphabet abc
aabaccbbabRun nanoid --help for all options.
The tests are off by default. They use Catch2, which is downloaded if it isn't installed:
cmake -B build -DNANOID_BUILD_TESTS=ON && cmake --build build && cd build && ctest- ai - nanoid
- codeyu - nanoid-net
The MIT License (MIT). Please see License File for more information.