243 lines
11 KiB
C++
243 lines
11 KiB
C++
#pragma once
|
|
// Step 1961: OperationTaxonomy
|
|
// Full domain tree with 40+ entries. classify(text) -> domain key via keyword matching.
|
|
// Domains are checked most-specific first (more dots = higher priority).
|
|
|
|
#include "OperationDomain.h"
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace whetstone {
|
|
|
|
class OperationTaxonomy {
|
|
public:
|
|
// A matcher maps a domain key to a list of keyword sets.
|
|
// A domain matches if ANY keyword set fully appears in the lowercased text.
|
|
// Within a keyword set, ALL keywords must appear as substrings.
|
|
struct DomainMatcher {
|
|
std::string domainKey;
|
|
std::vector<std::vector<std::string>> keywordSets;
|
|
};
|
|
|
|
// Build the default taxonomy with 40+ domains across 8 top-level categories.
|
|
static OperationTaxonomy buildDefault() {
|
|
OperationTaxonomy t;
|
|
|
|
// --- 2-dot domains (most specific, checked first) ---
|
|
|
|
// serialization.*.*
|
|
t.add("serialization.protobuf", "Protocol Buffers",
|
|
{{"protobuf"}, {"proto buffer"}});
|
|
t.add("serialization.msgpack", "MessagePack",
|
|
{{"msgpack"}, {"messagepack"}});
|
|
|
|
// compute.*.*
|
|
t.add("compute.ml.training", "ML Training",
|
|
{{"training", "model"}, {"backprop"}, {"gradient", "descent"}, {"train", "neural"}});
|
|
t.add("compute.ml.inference", "ML Inference",
|
|
{{"inference", "model"}, {"forward pass"}, {"predict", "neural"}});
|
|
|
|
// network.*.*
|
|
t.add("network.http.client", "HTTP Client",
|
|
{{"http", "client"}, {"rest", "client"}, {"curl"}, {"api", "client"}, {"http request"},
|
|
{"requests"}, {"axios"}});
|
|
t.add("network.http.server", "HTTP Server",
|
|
{{"http", "server"}, {"web server"}, {"rest", "server"}, {"http", "listen"},
|
|
{"api", "endpoint"}, {"api", "route"}, {"backend", "api"},
|
|
{"fastapi"}, {"express"}, {"gin"}, {"axum"}, {"spring-boot"}});
|
|
|
|
// io.*.*
|
|
t.add("io.stream.audio", "Audio Stream IO",
|
|
{{"audio", "stream"}, {"audio", "buffer"}, {"pcm"}});
|
|
t.add("io.stream.video", "Video Stream IO",
|
|
{{"video", "stream"}, {"frame", "capture"}, {"video", "buffer"}});
|
|
|
|
// db.*.*
|
|
t.add("db.query.sql", "SQL Query",
|
|
{{"sql"}, {"select", "from"}, {"insert", "into"}, {"query", "table"}});
|
|
t.add("db.query.nosql", "NoSQL Query",
|
|
{{"nosql"}, {"mongodb"}, {"document", "store"}, {"couchdb"}});
|
|
|
|
// --- 1-dot domains ---
|
|
|
|
// serialization.*
|
|
t.add("serialization.json", "JSON Serialization",
|
|
{{"json"}});
|
|
t.add("serialization.binary", "Binary Serialization",
|
|
{{"binary", "serial"}, {"binary", "encode"}, {"flatbuffer"}, {"capnproto"}});
|
|
t.add("serialization.xml", "XML Serialization",
|
|
{{"xml"}, {"xslt"}});
|
|
t.add("serialization.csv", "CSV Serialization",
|
|
{{"csv"}, {"comma", "separated"}});
|
|
t.add("serialization.yaml", "YAML Serialization",
|
|
{{"yaml"}});
|
|
|
|
// compute.*
|
|
t.add("compute.matrix", "Matrix Computation",
|
|
{{"matrix"}, {"matmul"}, {"gemm"}, {"linear algebra"}});
|
|
t.add("compute.parallel", "Parallel Computation",
|
|
{{"parallel"}, {"simd"}, {"vectorize"}});
|
|
t.add("compute.statistics", "Statistical Computation",
|
|
{{"statistic"}, {"mean"}, {"variance"}, {"distribution"}});
|
|
t.add("compute.fft", "Fast Fourier Transform",
|
|
{{"fft"}, {"fourier"}, {"frequency domain"}});
|
|
t.add("compute.graph", "Graph Computation",
|
|
{{"graph", "algorithm"}, {"shortest path"}, {"bfs"}, {"dfs"}});
|
|
t.add("compute.sort", "Sorting",
|
|
{{"sort"}, {"order", "elements"}});
|
|
t.add("compute.hash_map", "Hash Map",
|
|
{{"hash map"}, {"hash table"}, {"hashmap"}, {"unordered map"}});
|
|
|
|
// network.*
|
|
t.add("network.websocket", "WebSocket",
|
|
{{"websocket"}, {"ws://"}, {"realtime", "socket"}, {"live", "notifications"}});
|
|
t.add("network.async", "Async Network IO",
|
|
{{"async", "io"}, {"async", "network"}, {"event loop"}, {"non-blocking", "io"}});
|
|
t.add("network.grpc", "gRPC",
|
|
{{"grpc"}, {"rpc", "proto"}});
|
|
t.add("network.tcp", "TCP",
|
|
{{"tcp"}, {"transmission control"}});
|
|
t.add("network.udp", "UDP",
|
|
{{"udp"}, {"datagram"}});
|
|
|
|
// io.*
|
|
t.add("io.stream", "Stream IO",
|
|
{{"stream"}});
|
|
t.add("io.file", "File IO",
|
|
{{"file", "read"}, {"file", "write"}, {"filesystem"}, {"file io"}});
|
|
t.add("io.file.mmap", "Memory-Mapped IO",
|
|
{{"mmap"}, {"memory map"}, {"memory mapped"}});
|
|
t.add("io.database", "Database IO",
|
|
{{"database", "read"}, {"database", "write"}});
|
|
|
|
// crypto.*
|
|
t.add("crypto.hash", "Cryptographic Hash",
|
|
{{"sha256"}, {"sha512"}, {"sha1"}, {"md5"}, {"checksum"}, {"hash", "file"}});
|
|
t.add("crypto.symmetric", "Symmetric Encryption",
|
|
{{"aes"}, {"symmetric", "encrypt"}, {"chacha20"}, {"blowfish"}});
|
|
t.add("crypto.asymmetric", "Asymmetric Encryption",
|
|
{{"rsa"}, {"ecdsa"}, {"public key"}, {"private key"}});
|
|
t.add("crypto.tls", "TLS/SSL",
|
|
{{"tls"}, {"ssl"}, {"certificate"}});
|
|
t.add("crypto.random", "Cryptographic Random",
|
|
{{"csprng"}, {"secure random"}, {"random bytes"}, {"secure", "rand"}});
|
|
|
|
// db.*
|
|
t.add("db.transaction", "Database Transaction",
|
|
{{"transaction"}, {"commit"}, {"rollback"}});
|
|
t.add("db.orm", "ORM",
|
|
{{"orm"}, {"object relational"}, {"entity", "mapping"}, {"data model"}, {"schema", "model"},
|
|
{"sqlalchemy"}, {"prisma"}, {"jooq"}, {"sqlx"}});
|
|
t.add("db.migration", "Database Migration",
|
|
{{"migration"}, {"schema change"}, {"db upgrade"}, {"db", "migrate"}});
|
|
|
|
// auth.*
|
|
t.add("auth.oauth", "OAuth",
|
|
{{"oauth"}});
|
|
t.add("auth.jwt", "JWT",
|
|
{{"jwt"}, {"json web token"}, {"auth", "token"}});
|
|
t.add("auth.session", "Session Auth",
|
|
{{"session"}, {"cookie", "auth"}});
|
|
t.add("auth.mfa", "Multi-Factor Auth",
|
|
{{"mfa"}, {"2fa"}, {"totp"}, {"two factor"}});
|
|
|
|
// storage.*
|
|
t.add("storage.object", "Object Storage",
|
|
{{"object storage"}, {"s3"}, {"blob storage"}});
|
|
t.add("storage.cache", "Cache Storage",
|
|
{{"cache"}, {"redis"}, {"memcache"}, {"rate limit"}});
|
|
t.add("storage.queue", "Message Queue",
|
|
{{"kafka"}, {"rabbitmq"}, {"message queue"}, {"message broker"},
|
|
{"job queue"}, {"background worker"}, {"queue worker"}, {"bullmq"}, {"kafka-go"}});
|
|
|
|
// validation.*
|
|
t.add("validation.schema", "Schema Validation",
|
|
{{"schema", "validation"}, {"validate", "input"}, {"request", "validation"},
|
|
{"type validation"}, {"runtime validation"}, {"zod"}, {"pydantic"}});
|
|
|
|
// --- 0-dot (top-level, checked last) ---
|
|
t.add("serialization", "Serialization",
|
|
{{"serial"}, {"marshal"}, {"encode", "data"}});
|
|
t.add("compute", "Compute",
|
|
{{"compute"}, {"calculation"}});
|
|
t.add("network", "Network",
|
|
{{"network"}, {"socket"}});
|
|
t.add("io", "IO",
|
|
{{"file io"}, {"io stream"}});
|
|
t.add("crypto", "Cryptography",
|
|
{{"crypto"}, {"encrypt"}, {"decrypt"}});
|
|
t.add("db", "Database",
|
|
{{"database"}});
|
|
t.add("auth", "Authentication",
|
|
{{"authenticate"}, {"authorization"}});
|
|
t.add("storage", "Storage",
|
|
{{"store data"}, {"persist data"}});
|
|
|
|
// Sort matchers: more dots first, then longer key first.
|
|
std::stable_sort(
|
|
t.matchers_.begin(), t.matchers_.end(),
|
|
[](const DomainMatcher& a, const DomainMatcher& b) {
|
|
auto dots = [](const std::string& s) {
|
|
return std::count(s.begin(), s.end(), '.');
|
|
};
|
|
auto da = dots(a.domainKey), db = dots(b.domainKey);
|
|
if (da != db) return da > db;
|
|
return a.domainKey.size() > b.domainKey.size();
|
|
});
|
|
|
|
return t;
|
|
}
|
|
|
|
// Classify text to a domain key. Returns "unknown" if no match.
|
|
std::string classify(const std::string& text) const {
|
|
std::string lower = text;
|
|
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
|
|
for (const auto& m : matchers_) {
|
|
if (matches(lower, m.keywordSets)) return m.domainKey;
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
std::vector<OperationDomain> allDomains() const { return registry_.all(); }
|
|
size_t domainCount() const { return registry_.size(); }
|
|
const OperationDomainRegistry& registry() const { return registry_; }
|
|
|
|
// Unique top-level category keys (domains with no dot)
|
|
std::vector<std::string> topLevelCategories() const {
|
|
std::vector<std::string> result;
|
|
for (const auto& d : registry_.all()) {
|
|
if (d.isTopLevel()) result.push_back(d.key);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
OperationDomainRegistry registry_;
|
|
std::vector<DomainMatcher> matchers_;
|
|
|
|
void add(const std::string& key, const std::string& displayName,
|
|
std::vector<std::vector<std::string>> keywordSets) {
|
|
registry_.registerDomain({key, displayName});
|
|
matchers_.push_back({key, std::move(keywordSets)});
|
|
}
|
|
|
|
// Returns true if ANY keyword set fully appears in lowerText.
|
|
static bool matches(const std::string& lowerText,
|
|
const std::vector<std::vector<std::string>>& sets) {
|
|
for (const auto& kwSet : sets) {
|
|
bool allFound = true;
|
|
for (const auto& kw : kwSet) {
|
|
if (lowerText.find(kw) == std::string::npos) {
|
|
allFound = false;
|
|
break;
|
|
}
|
|
}
|
|
if (allFound) return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
} // namespace whetstone
|