Program Listing for File ct_string.inl

Return to documentation for file (include/ct_string.inl)

#pragma once

#include <array>
#include <cstddef>
#include <functional> // std::invoke
#include <string_view>
#include <utility>    // std::move, std::index_sequence_for


namespace ctql {

    template <std::size_t N>
    struct ct_string {
        std::array<char, N + 1> data{};

        constexpr ct_string() = default;

        constexpr ct_string(const char (&str)[N + 1]) {
            for (std::size_t i = 0; i < N + 1; ++i)
                data[i] = str[i];
        }

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

        constexpr std::size_t size() const { return N; }

        constexpr operator std::string_view() const { return {data.data(), N}; }
    };

    template <std::size_t N>
    ct_string(const char (&)[N]) -> ct_string<N - 1>;

    template <std::size_t N1, std::size_t N2>
    constexpr auto operator+(const ct_string<N1>& lhs, const ct_string<N2>& rhs) {
        ct_string<N1 + N2> result;
        for (std::size_t i = 0; i < N1; ++i)
            result.data[i] = lhs.data[i];
        for (std::size_t i = 0; i < N2; ++i)
            result.data[N1 + i] = rhs.data[i];
        result.data[N1 + N2] = '\0';
        return result;
    }

    template <std::size_t N1, std::size_t N2>
    constexpr bool operator==(const ct_string<N1>& lhs, const ct_string<N2>& rhs) {
        if constexpr (N1 != N2)
            return false;
        else {
            for (std::size_t i = 0; i < N1; ++i) {
                if (lhs.data[i] != rhs.data[i])
                    return false;
            }
            return true;
        }
    }

    consteval std::size_t count_digits(std::size_t n) {
        std::size_t digits = 1;
        while (n /= 10)
            ++digits;
        return digits;
    }

    template <std::size_t N>
    consteval auto to_ct_string() {
        constexpr std::size_t digits = count_digits(N);
        ct_string<digits> result;
        std::size_t n = N;
        for (std::size_t i = 0; i < digits; ++i)
            result.data[digits - 1 - i] = char('0' + (n % 10)), n /= 10;
        result.data[digits] = '\0';
        return result;
    }

    template <ct_string str>
    constexpr auto operator""_ct() {
        return str;
    }

    template <typename... Lambda_t>
    struct match : Lambda_t... {
        using Lambda_t::operator()...;
        constexpr match(Lambda_t... lambda)
            : Lambda_t(std::move(lambda))... {}
    };

#define $match(arg, ...) std::invoke(ctql::match{__VA_ARGS__}, arg)

    template <class... Ts, class Fn>
    constexpr void foreach_indexed(Fn&& fn) {
        [&]<std::size_t... Is>(std::index_sequence<Is...>) {
            (std::forward<Fn>(fn).template operator()<Ts, Is>(), ...);
        }(std::index_sequence_for<Ts...>{});
    }
}