Program Listing for File types.cc#

↰ Return to documentation for file (src/types.cc)

#include <charconv>
#include <cstring>
#include "nodes-graph/types.h"


namespace ng {

const char* as_string(Status status) {
    switch (status) {
        case Status::Ok:                  return "Ok";
        case Status::NoOutputSocket:      return "NoOutputSocket";
        case Status::NoInputSocket:       return "NoInputSocket";
        case Status::IncompatibleTypes:   return "IncompatibleTypes";
        case Status::NotLinkable:         return "NotLinkable";
        case Status::CausesCycle:         return "CausesCycle";
        case Status::InvalidValue:        return "InvalidValue";
        case Status::NotAllowedValue:     return "NotAllowedValue";
        case Status::DuplicateAlias:      return "DuplicateAlias";
        case Status::NoWritableHead:      return "NoWritableHead";
        case Status::UnknownHead:         return "UnknownHead";
        case Status::NoQualifier:         return "NoQualifier";
        case Status::IncompleteQualifier: return "IncompleteQualifier";
        case Status::IOError:             return "IOError";
    }
    return "Unknown";
}


// ---


node_id_t as_node_id(const char* str, std::size_t unique) {
    if (unique > MAX_NODE_RANDOM_ID)
        throw std::out_of_range("Unique ID exceeds maximum allowed value");

    if (unique == 0)
        throw std::out_of_range("Unique ID must be greater than zero");

    node_id_t id = as_node_id(str);
    std::size_t start = 0;
    while (id[start] != 0) { start++; }

    // '#' + at most (LEN_MAX_NODE_RANDOM_ID - 1) digits + '\0'
    std::array<char, LEN_MAX_NODE_RANDOM_ID + 1> buffer{0};
    buffer[0] = '#';
    std::to_chars(
        buffer.data() + 1,
        buffer.data() + buffer.size() - 1,
        unique
    );
    std::size_t len = 0;
    while (buffer[len] != 0) { ++len; }

    std::size_t excess = (start + len) > (NODE_ID_SIZE - 1) ? (start + len) - (NODE_ID_SIZE - 1) : 0;
    start -= excess;

    std::memcpy(
        id.data() + start,
        buffer.data(),
        len
    );

    return id;
}


node_id_t as_node_id(const qualifier_t& q, std::size_t unique) {
    return as_node_id(
        q.chunks[qualifier_t::N_CHUNKS-1].data(),
        unique
    );
}


// ---


socket_uuid_t as_socket_uuid(const node_id_t& node, const socket_id_t& socket) {
    return std::make_pair(node, socket);
}


socket_uuid_t as_socket_uuid(const node_id_t& node, const char* str_socket) {
    return std::make_pair(node, as_socket_id(str_socket));
}


link_t as_link(const socket_uuid_t& from, const socket_uuid_t& to) {
    return std::make_pair(to, from);
}


// ---


qualifier_t::qualifier_t(std::initializer_list<const char*> init) {
    std::size_t i = 0;
    for (const char* str : init) {
        if (i >= N_CHUNKS) {
            throw std::out_of_range("Too many chunks in initializer list");
        }
        chunks[i] = as_qchunk(str);
        ++i;
    }
    while (i < N_CHUNKS) {
        chunks[i] = null_qchunk;
        ++i;
    }
}


qualifier_t::qualifier_t(std::initializer_list<qchunk_t> init) {
    std::size_t i = 0;
    for (const qchunk_t& chunk : init) {
        if (i >= N_CHUNKS) {
            throw std::out_of_range("Too many chunks in initializer list");
        }
        chunks[i] = chunk;
        ++i;
    }
    while (i < N_CHUNKS) {
        chunks[i] = null_qchunk;
        ++i;
    }
}


bool qualifier_t::is_complete() const {
    for (std::size_t i = 0; i < N_CHUNKS; ++i) {
        if (eq_qchunk(chunks[i], null_qchunk)) {
            return false;
        }
    }
    return true;
}


bool cmp_qualifier(const qualifier_t& a, const qualifier_t& b) {
    for (std::size_t i = 0; i < qualifier_t::N_CHUNKS; ++i) {
        if (cmp_qchunk(a.chunks[i], b.chunks[i])) {
            return true;
        } else if (cmp_qchunk(b.chunks[i], a.chunks[i])) {
            return false;
        }
    }
    return false;
}


bool eq_qualifier(const qualifier_t& a, const qualifier_t& b) {
    for (std::size_t i = 0; i < qualifier_t::N_CHUNKS; ++i) {
        if (!eq_qchunk(a.chunks[i], b.chunks[i])) {
            return false;
        }
    }
    return true;
}


std::filesystem::path as_filepath(const qualifier_t& q) {
    std::filesystem::path path = "";
    for (std::size_t i = 0; i < qualifier_t::N_CHUNKS; ++i) {
        path /= std::string(q.chunks[i].data());
    }
    path += ".graph";
    return path;
}


std::string as_string(const qualifier_t& q) {
    std::string result;
    for (std::size_t i = 0; i < qualifier_t::N_CHUNKS; ++i) {
        if (i > 0) { result += SPLIT_CHAR; }
        result += q.chunks[i].data();
    }
    return result;
}


qualifier_t as_qualifier(const char* c_str) {
    std::string str = c_str;
    std::size_t start = 0, next = 0, rank = 0;
    std::string s;
    qualifier_t qualifier;

    if (str.empty())
        return qualifier;

    while (true) {
        next = str.find(SPLIT_CHAR, start);
        s = str.substr(start, next - start);
        start = next + 1;
        if (s.empty())
            throw std::runtime_error("Empty chunk in qualifier");
        qualifier.chunks[rank++] = as_qchunk(s.c_str());
        if (next == std::string::npos || rank >= qualifier_t::N_CHUNKS) break;
    }

    if (rank < qualifier_t::N_CHUNKS)
        throw std::runtime_error("Not enough chunks in qualifier");

    if (next != std::string::npos)
        throw std::runtime_error("Too many chunks in qualifier");

    return qualifier;
}

} // namespace ng