C++ Client
The C++ client is a header-only, C++17 driver with no dependencies beyond POSIX sockets. There is no package to install — you copy one header into your project.
Install
Copy cpp/include/veltrixdb.hpp into your project. That's it — no package manager, no build-system integration required.
bash#include "veltrixdb.hpp"
If you'd rather wire it in via CMake as an interface target:
cmake# CMakeLists.txt add_library(veltrixdb INTERFACE) target_include_directories(veltrixdb INTERFACE ${CMAKE_SOURCE_DIR}/cpp/include)
Requires C++17 and POSIX sockets (Linux and macOS). For Windows, the header's own comments note you'd need to swap the socket calls for WinSock2 — that port doesn't exist yet.
Quick start
From the header's own quick-start and the bundled cpp/examples/smoke.cpp:
cpp#include <cassert> #include <cstdio> #include <iostream> #include <vector> #include "veltrixdb.hpp" int main() { using namespace veltrixdb; Client c("127.0.0.1", 19000); c.put("hello", {'w','o','r','l','d'}); auto v = c.get("hello"); if (!v) { std::cerr << "get hello returned not-found\n"; return 1; } assert(*v == std::vector<uint8_t>({'w','o','r','l','d'})); std::printf("get hello -> %.*s\n", static_cast<int>(v->size()), reinterpret_cast<const char*>(v->data())); auto n = c.incr("counter", 5); assert(n == 5); n = c.incr("counter", 3); assert(n == 8); n = c.decr("counter", 2); assert(n == 6); std::printf("counter = %lld\n", static_cast<long long>(n)); auto r = c.cas("hello", {'w','o','r','l','d'}, {'e','a','r','t','h'}); assert(r == CasOutcome::Swapped); r = c.cas("hello", {'w','o','r','l','d'}, {'m','a','r','s'}); assert(r == CasOutcome::Mismatch); auto a = c.setnx("lock", {'A'}); assert(a == SetNxOutcome::Created); auto b = c.setnx("lock", {'B'}); assert(b == SetNxOutcome::Existed); std::printf("all smoke tests passed\n"); return 0; }
Compile and run against a live server:
bash# Start a server go run ../VeltrixDB/cmd/server -addr :19000 -data /tmp/veltrix-cpp-smoke # Compile and run c++ -std=c++17 -O2 -I cpp/include cpp/examples/smoke.cpp -o smoke ./smoke
API surface
veltrixdb::Client wraps a single blocking POSIX socket, opened in its constructor via getaddrinfo/connect with TCP_NODELAY set. It's move-constructible but not copyable.
| Method | Description |
|---|---|
Client(host, port) | Resolve and connect; throws veltrixdb::Error on failure |
put(key, value) | value is a std::vector<uint8_t> |
get(key) | Returns std::optional<std::vector<uint8_t>> — empty on NOT_FOUND |
del(key) | Delete a key |
ping() | Check connection health |
cas(key, expected, new_value, ttl=-1) | Compare-and-swap; returns a CasOutcome |
incr(key, delta, ttl=-1) / decr(key, delta, ttl=-1) | Atomic signed int64_t delta; returns the new value |
setnx(key, value, ttl=-1) | Set only if absent; returns a SetNxOutcome |
Outcome types
cppenum class CasOutcome { Swapped, Mismatch, NotFound }; enum class SetNxOutcome { Created, Existed };
Error handling
Failures throw veltrixdb::Error (a std::runtime_error subclass). get() is the one exception-shy method — it returns std::nullopt for a missing key instead of throwing:
cpptry { veltrixdb::Client c("127.0.0.1", 9000); c.put("key", {'v','a','l'}); auto v = c.get("key"); if (!v) { // not found — normal, no exception } auto r = c.cas("key", {'v','a','l'}, {'n','e','w'}); // r == CasOutcome::Mismatch is a normal return value, not an exception } catch (const veltrixdb::Error& e) { std::cerr << "veltrixdb error: " << e.what() << "\n"; }
Internally, a NOT_FOUND status on cas is folded into CasOutcome::NotFound rather than an exception; only genuine protocol/server errors (ST_ERR or an unrecognized status byte) throw.
MultiPut/MultiGet batch framing (CMD 0x06/0x07), TLS (would require linking OpenSSL), and connection pooling. It is a minimal, single-connection, blocking client — layer any of the above on top in your own code.
veltrixdb.hpp directly into your source tree and track upstream changes via your own diffing process (e.g. a vendored-file check in CI) rather than a package manager.