parselink-old/include/parselink/utility/ctstring.h

125 lines
3.9 KiB
C++

//-----------------------------------------------------------------------------
// ___ __ _ _
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
// / ___/ (_| | | \__ \ __/ /__| | | | | <
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
//
//-----------------------------------------------------------------------------
// Author: Kurt Sassenrath
// Module: Utility
//
// Compile-time string class, which can be used as template parameters and
// enable compile-time hashing/lookup of literals and so forth.
//
// Copyright (c) 2023 Kurt Sassenrath.
//
// License TBD.
//-----------------------------------------------------------------------------
#ifndef ct_string_4fab12ca46f0d931
#define ct_string_4fab12ca46f0d931
#include <array>
#include <string_view>
namespace parselink {
namespace ct {
template <std::size_t N>
struct string {
using char_type = char; // Maybe allow templatization in the future?
using storage_type = std::array<char, N + 1>;
storage_type data_ = {};
static constexpr auto npos = std::string_view::npos;
constexpr string() noexcept = default;
constexpr string(storage_type const& str) noexcept {
std::copy(std::begin(str), std::end(str), std::begin(data_));
}
constexpr string(char const (&str)[N + 1]) noexcept {
std::copy(std::begin(str), std::end(str), std::begin(data_));
}
constexpr string(string const& other) noexcept {
std::copy(std::begin(other), std::end(other), std::begin(data_));
}
constexpr string& operator=(string const& other) noexcept {
std::copy(std::begin(other), std::end(other), std::begin(data_));
return *this;
}
constexpr operator std::string_view() const noexcept {
return std::string_view{data_.data(), N};
}
// We save ourselves some headache by forwarding std::array's methods here.
constexpr auto data() noexcept { return data_.data(); }
constexpr auto data() const noexcept { return data_.data(); }
constexpr auto size() const noexcept { return N; }
constexpr auto begin() noexcept { return data_.begin(); }
constexpr auto begin() const noexcept { return data_.begin(); }
constexpr auto end() noexcept { return data_.end() - 1; }
constexpr auto end() const noexcept { return data_.end() - 1; }
constexpr auto cbegin() const noexcept { return data_.cbegin(); }
constexpr auto cend() const noexcept { return data_.cend() - 1; }
constexpr auto find(char_type c) noexcept {
return std::string_view{*this}.find(c);
}
constexpr auto find(char_type c) const noexcept {
return std::string_view{*this}.find(c);
}
};
template <size_t N>
string(char const (&)[N]) -> string<N - 1>;
template <std::size_t N1, std::size_t N2>
constexpr bool operator==(string<N1> const& a, string<N2> const& b) noexcept {
if constexpr (N1 != N2) return false;
return std::string_view{a} == std::string_view{b};
}
template <std::size_t N>
constexpr bool operator==(string<N> const& a, std::string_view b) noexcept {
return std::string_view{a} == b;
}
template <std::size_t N>
constexpr bool operator==(std::string_view a, string<N> const& b) noexcept {
return b == a;
}
template <std::size_t N1, std::size_t N2>
consteval string<N1 + N2> operator+(
string<N1> const& a, string<N2> const& b) noexcept {
using char_type = typename std::decay_t<decltype(a)>::char_type;
char_type buff[N1 + N2 + 1]{};
std::copy(std::begin(a), std::end(a), std::begin(buff));
std::copy(
std::begin(b), std::end(b), std::next(std::begin(buff), a.size()));
return string<N1 + N2>(buff);
}
// Sanity test for construction and concatenation at compile time.
static_assert(string("hello") + string(" world") == string("hello world"));
} // namespace ct
} // namespace parselink
#endif // ct_string_4fab12ca46f0d931