//----------------------------------------------------------------------------- // ___ __ _ _ // / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ // / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / // / ___/ (_| | | \__ \ __/ /__| | | | | < // \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . // //----------------------------------------------------------------------------- // 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. //----------------------------------------------------------------------------- #include #include namespace parselink { namespace ct { template struct string { using char_type = char; // Maybe allow templatization in the future? using storage_type = std::array; 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 string(char const (&)[N]) -> string; template constexpr bool operator==(string const& a, string const& b) noexcept { if constexpr (N1 != N2) return false; return std::string_view{a} == std::string_view{b}; } template constexpr bool operator==(string const& a, std::string_view b) noexcept { return std::string_view{a} == b; } template constexpr bool operator==(std::string_view a, string const& b) noexcept { return b == a; } template consteval string operator+( string const& a, string const& b) noexcept { using char_type = typename std::decay_t::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(buff); } // Sanity test for construction and concatenation at compile time. static_assert(string("hello") + string(" world") == string("hello world")); } // namespace ct } // namespace parselink