Language: C++

#pragma once
#include <iostream>
#include <map>
#include <memory>
#include <vector>

#include "misc/types.hpp"
class patricia
{
public:
    struct node_t;
    using ptr_t       = std::shared_ptr<node_t>;
    using const_ptr_t = std::shared_ptr<const node_t>;

private:
    using pair = std::pair<std::shared_ptr<node_t>, usize>;

public:
    struct node_t
    {
        node_t() = default;
        node_t(const std::string& prefix, const usize sub = 0, const usize count = 0) : prefix{prefix}, sub{sub}, count{count} {}
        std::string prefix{};
        usize sub = 0, count = 0;
        std::map<char, ptr_t> child{};
        friend std::ostream& operator<<(std::ostream& os, const node_t& node) { return os << "[" << node.prefix << "," << node.sub << "," << node.count << "]"; }
        static const pair next(const pair q, const std::string& s, const bool create = false)
        {
            const auto p     = q.first;
            const auto index = q.second;
            const auto c     = s[index];
            if (p->child.find(c) == p->child.end()) {
                if (not create) { return pair{p, index}; }
                return p->child[c] = std::make_shared<node_t>(s.substr(index)), pair{p->child[c], s.size()};
            }
            const auto prefix = p->child.at(c)->prefix;
            const usize n = s.size(), m = prefix.size();
            usize lcp = 0;
            for (; index + lcp < n and lcp < m and s[index + lcp] == prefix[lcp]; lcp++) {}
            if (lcp == m) { return pair{p->child.at(c), index + lcp}; }
            if (not create) { return pair{p, index}; }
            const ptr_t nxt = p->child.at(c), mid = std::make_shared<node_t>(s.substr(index, lcp), nxt->sub);
            return mid->child[nxt->prefix[lcp]] = nxt, nxt->prefix = nxt->prefix.substr(lcp), p->child.at(c) = mid, pair{mid, index + lcp};
        }
    };
    patricia() : root{std::make_shared<node_t>()} {}
    void add(const std::string& s)
    {
        const usize n = s.size();
        pair p{root, 0};
        for (; p.second < n;) { p.first->sub++, p = node_t::next(p, s, true); }
        p.first->sub++, p.first->count++;
    }
    usize count(const std::string& s) const
    {
        const auto p = tail(s);
        return p.second == s.size() ? p.first->count : 0UL;
    }
    usize sub(const std::string& s) const
    {
        const auto p = tail(s);
        if (p.second == s.size()) { return p.first->sub; }
        const char c = s[p.second];
        if (p.first->child.find(c) == p.first->child.end()) { return 0UL; }
        return p.first->child.at(c)->prefix.substr(0, s.size() - p.second) == s.substr(p.second) ? p.first->child.at(c)->sub : 0UL;
    }
    friend std::ostream& operator<<(std::ostream& os, const patricia& pat)
    {
        auto rec = [&](auto&& self, const auto p) {
            if (not p) { return; }
            os << "(" << *p;
            for (const auto& q : p->child) { self(self, q.second); }
            os << ")";
        };
        return rec(rec, pat.root), os;
    }
    const std::vector<const_ptr_t> path_to(const std::string& s) const
    {
        std::vector<const_ptr_t> ans;
        const usize n = s.size();
        pair p{root, 0};
        for (; p.second < n;) {
            ans.push_back(p.first);
            const auto prev = p.second;
            p               = node_t::next(p, s, false);
            if (p.second == prev) { break; }
        }
        return ans.push_back(p.first), ans;
    }

private:
    const pair tail(const std::string& s) const
    {
        const usize n = s.size();
        pair p{root, 0};
        for (; p.second < n;) {
            const auto prev = p.second;
            p               = node_t::next(p, s, false);
            if (p.second == prev) { break; }
        }
        return p;
    }
    ptr_t root;
};


Compiler output:
a.cc:1:9: warning: #pragma once in main file
    1 | #pragma once
      |         ^~~~
a.cc:7:10: fatal error: misc/types.hpp: No such file or directory
    7 | #include "misc/types.hpp"
      |          ^~~~~~~~~~~~~~~~
compilation terminated.