|
FlatCityBuf C++ reader 0.8.0
Native C++17 reader for FlatCityBuf, the cloud-optimized CityJSON format
|
A native C++17 reader and writer. No Rust toolchain, no CXX bridge, no TLS dependency.
| Dependency | Required? | Why |
|---|---|---|
flatbuffers | yes | the on-disk format |
nlohmann-json | FCB_WITH_JSON=ON (default) | CityJSON emission, and the writer |
libcurl | FCB_WITH_CURL=ON (default OFF) | HTTP range requests |
doctest | FCB_BUILD_TESTS=ON (default) | tests only, never installed |
The default build links neither curl nor any TLS library — CI asserts this. When you do enable the HTTP adapter, libcurl brings its own platform TLS (Schannel / SecureTransport / system OpenSSL), so this library still never link-depends on a TLS stack.
The port lives in a custom vcpkg registry (not the built-in microsoft/vcpkg one). Next to your project's vcpkg.json, add a vcpkg-configuration.json:
and declare the dependency in vcpkg.json:
Use { "name": "flatcitybuf", "features": ["curl"] } instead to get the HTTP range-request reader. Configure with vcpkg's toolchain file (-DCMAKE_TOOLCHAIN_FILE=<vcpkg>/scripts/buildsystems/vcpkg.cmake) and integrate exactly as in Use from CMake below — the port installs the same flatcitybuf::flatcitybuf target the manual build does.
The port builds this directory from the cpp-v0.9.0 tag (C++ releases are tagged cpp-v<version>; bare v<version> names the Rust crate releases) with tests and examples off, JSON on. One packaging note: vcpkg ships a newer FlatBuffers than the generated headers' exact-version assert expects, so the port patches the assert to major-version-only.
Useful options: -DFCB_WITH_CURL=ON (HTTP), -DFCB_WITH_JSON=OFF (drop CityJSON emission, the writer, and the nlohmann dependency), -DFCB_BUILD_TESTS=OFF, -DFCB_BUILD_EXAMPLES=OFF.
That is the whole integration. There is no generated bridge source to compile alongside your code, unlike the retired FFI bindings.
Build with -DFCB_WITH_CURL=ON:
Only the intersecting features are fetched, not the whole file.
fcb::RangeReader is the extension point — implement it to read from an engine VFS, an object store, memory, or anything else:
The interface is deliberately synchronous: batching, not asynchrony, is the concurrency primitive. A blocking interface is trivially wrapped by whatever threading model your application already has, whereas an imposed async runtime is not. Read the contract comment in include/fcb/range_reader.hpp before implementing — short reads, error reporting, ordering and representation stability are all specified there.
fcb::FcbWriter produces .fcb natively — no Rust toolchain here either. Needs FCB_WITH_JSON (on by default). Parse each CityJSONSeq line as nlohmann::ordered_json, never plain nlohmann::json — the latter stores object members alphabetically, which silently renumbers the columns. The attribute schema must reflect every feature you will add, so scan them once before constructing the writer:
Both indices are the writer's own: options.write_index / index_node_size control the packed Hilbert R-tree, options.attribute_indices names the columns that get a static B+tree. add_feature spools each encoded feature to a temp file and write(std::ostream&) streams the result out in chunks, so peak memory does not grow with the number of features — the std::vector-returning write() overload is a convenience for small files and does not have that property. The output is checked byte-for-byte against real Rust-written files, not merely for decoding correctly (tests/test_writer_oracle.cpp).
Column numbering is the order add_attributes first sees a name — document order, never alphabetical — so visit CityObjects deterministically (the example sorts by id, as the Rust CLI does) if the columns must line up with a Rust-written file. examples/write_cityjson.cpp is the full version of the above, including the separate schema semantic-surface attributes need.
fcb_write_cityjson in examples/ is a demonstration, not a conversion tool. The Rust CLI still covers that ground, and more.