20#include <unordered_map>
29constexpr std::uint64_t kFnvOffset = 14695981039346656037ull;
30constexpr std::uint64_t kFnvPrime = 1099511628211ull;
32std::uint64_t fnv1a(
const std::string &bytes) {
33 std::uint64_t h = kFnvOffset;
34 for (
unsigned char c : bytes) {
35 h ^=
static_cast<std::uint64_t
>(c);
38 return h == 0 ? 1 : h;
41std::filesystem::path corpus_dir(
const std::filesystem::path &con_path) {
42 namespace fs = std::filesystem;
44 fs::path cur = fs::weakly_canonical(con_path, ec);
46 cur = fs::absolute(con_path);
48 cur = cur.parent_path();
49 for (
int i = 0; i < 8; ++i) {
50 if (fs::is_regular_file(cur /
"config.ini")) {
51 return cur /
"readcon.db";
53 const fs::path parent = cur.parent_path();
59 fs::path beside = fs::weakly_canonical(con_path, ec);
61 beside = fs::absolute(con_path);
63 return beside.parent_path() /
"readcon.db";
67using OpenFn = int (*)(
const char *, std::size_t *);
68using AppendFn = int (*)(std::size_t, std::uint64_t,
const char *,
const char *,
73 OpenFn open =
nullptr;
74 AppendFn append_str =
nullptr;
80 if (out.lib !=
nullptr || out.missing) {
83 const char *names[] = {
"libreadcon_db.so",
"libreadcon_db.so.0",
84 "libreadcon_db.dylib"};
85 for (
const char *name : names) {
86 out.lib = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
87 if (out.lib !=
nullptr) {
91 if (out.lib ==
nullptr) {
95 out.open =
reinterpret_cast<OpenFn
>(dlsym(out.lib,
"rkrdb_open"));
97 reinterpret_cast<AppendFn
>(dlsym(out.lib,
"rkrdb_append_trajectory_str"));
98 if (out.open ==
nullptr || out.append_str ==
nullptr) {
106std::mutex &handles_mu() {
107 static std::mutex mu;
111std::unordered_map<std::string, std::size_t> &handles() {
112 static std::unordered_map<std::string, std::size_t> map;
116std::size_t corpus_handle(
const std::filesystem::path &dir) {
119 return static_cast<std::size_t
>(-1);
121 const std::string key = dir.string();
122 std::lock_guard<std::mutex> guard(handles_mu());
123 const auto found = handles().find(key);
124 if (found != handles().end()) {
125 return found->second;
128 if (fns.open(key.c_str(), &
id) != 0) {
129 return static_cast<std::size_t
>(-1);
131 handles().emplace(key,
id);
140 namespace fs = std::filesystem;
142 if (!fs::is_regular_file(path, ec) || ec) {
145 std::ifstream in(path);
149 std::ostringstream buf;
151 const std::string text = buf.str();
152 if (text.find_first_not_of(
" \t\r\n") == std::string::npos) {
155 fs::path canonical = fs::weakly_canonical(path, ec);
157 canonical = fs::absolute(path);
159 const std::string resolved = canonical.string();
160 const std::size_t
id = corpus_handle(corpus_dir(canonical));
161 if (
id ==
static_cast<std::size_t
>(-1)) {
164 const std::uint64_t tid = fnv1a(resolved +
'\0' + text);
165 std::uint32_t nframes = 0;
166 api().append_str(
id, tid, text.c_str(), resolved.c_str(), &nframes);
void mirror_con_corpus(const std::string &path)
Copy a con file into the run readcon-db corpus when libreadcon_db loads.