Program Listing for File fixed_name.hpp

Return to documentation for file (utils/fixed_name.hpp)

#pragma once

#include <string_view>
#include <array>
#include <optional>
#include <glaze/glaze.hpp>

template <size_t N>
struct FixedName {
    std::array<char, N> buf{};
    size_t len{};

    FixedName() = default;

    template <size_t M>
    requires(M <= N)
    constexpr FixedName(const char(&str)[M]) {
        std::copy_n(str, M, buf.begin());
        len = M - 1; // Exclude the null terminator from the length
    }

    struct glaze {
        static constexpr auto value = [](const FixedName& self) -> auto { return std::string_view(self.buf.data(), self.len); };
    };

    bool operator==(const FixedName &other) const {
        return std::string_view(other.buf.data(), other.len) == std::string_view(buf.data(), len);
    }

    auto operator<=>(const FixedName &other) const {
        return std::string_view(buf.data(), len) <=> std::string_view(other.buf.data(), other.len);
    }

    explicit operator std::string_view() const {
        return std::string_view(buf.data(), len);
    }

    const char* c_str() const {
        return buf.data();
    }

    std::optional<FixedName> operator+(std::string_view other) const {
        if (len + other.size() >= N) { // >= N because we need space for null terminato
            return std::nullopt;
        }

        FixedName result;
        result.len = len + other.size();
        std::copy(buf.begin(), buf.begin() + len, result.buf.begin());
        std::copy(other.begin(), other.end(), result.buf.begin() + len);
        result.buf[result.len] = '\0'; // Ensure null-termination

        return result;
    }

    bool operator+=(std::string_view other) {
        if (len + other.size() >= N) { // >= N because we need space for null terminator
            return false;
        }
        std::copy(other.begin(), other.end(), buf.begin() + len);
        len += other.size();
        buf[len] = '\0'; // Ensure null-termination
        return true;
    }

    static std::optional<FixedName> init(std::string_view str) {
        if (str.size() + 1 > N) { // +1 for the null terminator
            return std::nullopt;
        }

        FixedName fn;
        fn.len = str.size();
        std::copy(str.begin(), str.end(), fn.buf.begin());
        fn.buf[fn.len] = '\0'; // Ensure null-termination

        return fn;
    }
};

template <size_t N>
struct std::hash<FixedName<N>> {
    std::size_t operator()(const FixedName<N>& k) const {
        return hash(std::string_view(k));
    }
};