C++ and C ABI guide¶
The core (core/) is a self-contained C++17/20 static library — no external
dependencies (SHA-256, AES-128, and CRC-32 are built in). Both the Python
extension and the MATLAB MEX are thin layers over it, and it can be used
directly.
Consuming with CMake¶
add_subdirectory(mef3io/core) # or FetchContent on the repo
target_link_libraries(your_app PRIVATE mef3io_core)
The target exports its include directory; the library version (from the
repo-root VERSION file) is available as mef3io::version()
(mef3io/version.hpp).
Reading¶
#include "mef3io/reader.hpp"
mef3io::Reader r("session.mefd", /*password=*/"", /*n_threads=*/0);
for (const auto& ch : r.channels()) { ... }
const mef3io::ChannelInfo& ci = r.info("ch1"); // fs, ufact, times, counts,
// section-3 subject metadata
// Float64 on the fs grid over [t0, t1) (defaults: whole channel);
// gaps = NaN, values scaled by the conversion factor.
std::vector<double> x = r.read("ch1", t0, t1);
// Or the raw form: int32 counts + validity mask (0 in gaps).
mef3io::RawData raw = r.read_raw("ch1", t0, t1);
auto segs = r.segments("ch1"); // per-segment map: what data is where
auto toc = r.toc("ch1"); // per-RED-block index entries
auto recs = r.records("ch1"); // annotations (std::nullopt -> session level)
Reader wraps mef3io::Session (session.hpp), which exposes the lower
level: lazy .mefd/.timd/.segd traversal, read_runs (decoded contiguous
runs), collect_blocks (undecoded block gathering for custom parallel
pipelines).
Writing¶
#include "mef3io/session_writer.hpp"
mef3io::SessionWriter w("session.mefd", /*overwrite=*/true,
/*password_1=*/"", /*password_2=*/"");
w.set_units("uV");
// Float path: NaN = discontinuity gap; precision < 0 -> inferred
// (reused on append). Non-first writes append IN-SEGMENT;
// new_segment=true forces a fresh segment.
mef3io::WriteSummary s = w.write_float("ch1", data, start_uutc, 256.0);
// Primitive path: int32 counts stored verbatim + conversion factor;
// optional validity mask marks gaps.
w.write_int32("ch2", counts, /*ufact=*/0.01, start_uutc, 256.0, valid_mask);
// Records (annotations); std::nullopt -> session level.
w.write_records("ch1", {{.type = "Note", .time = t, .text = "marker"}});
Appends are validated against the on-disk segment (fs, conversion factor,
start after the segment end) and throw WriteConflictError on violation.
Errors¶
Everything throws from the mef3io::MefError hierarchy (errors.hpp):
IoError, FormatError, CrcError, PasswordError, WriteConflictError.
Module map¶
| Header | What it is |
|---|---|
types.hpp |
meflib-style type aliases + all format constants/offsets |
byteio.hpp |
little-endian field IO (no packed-struct casts) |
crc.hpp |
CRC-32 Koopman |
crypto.hpp |
SHA-256, AES-128-ECB, the two-level password scheme |
headers.hpp |
universal header, metadata sections, index entries, RED block header — parse/serialize by explicit offset |
metadata.hpp |
.tmet loader: CRC → password → decrypt |
red.hpp |
RED block decode + encode (lossless) |
session.hpp |
session tree, indexed reads, block gathering |
reader.hpp |
gridded reads, NaN fill, scaling, parallel decode |
writer.hpp |
low-level segment write + in-segment append |
session_writer.hpp |
precision inference, quantization, NaN splitting, segments, records |
records.hpp |
record (.rdat/.ridx) read + write |
parallel.hpp |
deterministic parallel_for |
version.hpp |
mef3io::version() |
c_api.h |
the flat C ABI (below) |
The flat C ABI¶
core/include/mef3io/c_api.h + core/src/c_api.cpp expose the full
reader/writer surface as extern "C" functions for FFI consumers (the
MATLAB MEX is built on it). Conventions:
- every fallible call returns
MEF3IO_OK(0) or an error code (MEF3IO_ERR_IO/FORMAT/CRC/PASSWORD/CONFLICT/ARGUMENT); the message is inmef3io_last_error()(thread-local); - handles are opaque (
mef3io_reader*,mef3io_writer*); close functions accept NULL; - reads use a deterministic size query + caller-allocated buffer:
mef3io_reader* r = NULL;
mef3io_reader_open("session.mefd", "", 0, &r);
int64_t n;
mef3io_reader_read_size(r, "ch1", MEF3IO_TIME_UNSET, MEF3IO_TIME_UNSET, &n);
double* buf = malloc(n * sizeof(double));
mef3io_reader_read(r, "ch1", MEF3IO_TIME_UNSET, MEF3IO_TIME_UNSET, buf, n, &n);
mef3io_reader_close(r);
The header is self-documenting; the Catch2 suite covers a full round trip through it.