rexylib/include/rexy/cx/string.hpp
2020-05-06 15:23:58 -07:00

186 lines
5.0 KiB
C++

/**
This file is a part of rexy's general purpose library
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_CX_STRING_HPP
#define REXY_CX_STRING_HPP
namespace rexy::cx{
template<size_t N>
class string;
}
#include "../string_base.hpp"
#include "utility.hpp"
#include <type_traits>
//This is different from rexy::static_string in that this doesn't hold a pointer to a constant string array.
//This holds a mutable array of data which can be modified during compile time. static_string is
//designed to be a thin wrapper around a raw char*, this is designed to allow compile time string concatenation
namespace rexy::cx{
template<size_t N>
class string
{
public:
static constexpr size_t max_size = N;
private:
char m_data[N] = {};
size_t m_length = 0;
public:
constexpr string(void) = default;
template<size_t M>
constexpr string(const char(&data)[M])noexcept:
m_length(M)
{
static_assert(M <= N);
for(size_t i = 0;i < M;++i){
m_data[i] = data[i];
}
}
constexpr string(const char* data)noexcept:
m_length(cx::strlen(data))
{
for(size_t i = 0;i < m_length;++i){
m_data[i] = data[i];
}
}
constexpr string(const char* data, size_t len)noexcept:
m_length(len)
{
for(size_t i = 0;i < m_length;++i){
m_data[i] = data[i];
}
}
constexpr string(const rexy::static_string& str)noexcept:
m_length(str.length())
{
for(size_t i = 0;i < m_length;++i){
m_data[i] = str[i];
}
}
template<class Left, class Right>
constexpr string(const rexy::string_cat_expr<Left,Right>& expr)
noexcept(std::is_nothrow_invocable<rexy::detail::string_appender<cx::string<N>>, decltype(expr)>::value)
{
rexy::detail::string_appender<cx::string<N>> append(*this);
append(expr);
}
constexpr string(const string&)noexcept = default;
constexpr string(string&&)noexcept = default;
~string(void)noexcept = default;
constexpr string& operator=(const char* c)noexcept{
m_length = cx::strlen(c);
for(size_t i = 0;i < m_length;++i){
m_data[i] = c[i];
}
return *this;
}
constexpr string& operator=(const string&)noexcept = default;
constexpr string& operator=(string&&)noexcept = default;
constexpr size_t length(void)const noexcept{
return m_length;
}
constexpr size_t capacity(void)const noexcept{
return max_size;
}
constexpr char* get(void)noexcept{
return m_data;
}
constexpr const char* get(void)const noexcept{
return m_data;
}
constexpr operator char*(void)noexcept{
return m_data;
}
constexpr operator const char*(void)const noexcept{
return m_data;
}
constexpr bool valid(void)const noexcept{
return m_length > 0;
}
constexpr char& operator[](size_t i)noexcept{
return m_data[i];
}
constexpr const char& operator[](size_t i)const noexcept{
return m_data[i];
}
constexpr bool resize(size_t i)noexcept{
if(i >= capacity())
return false;
m_length = i;
m_data[m_length] = 0;
return true;
}
constexpr void append(const char* data, size_t len)noexcept{
for(size_t i = 0;i < len;++i){
m_data[m_length++] = data[i];
}
}
constexpr void append(const char* data)noexcept{
append(data, cx::strlen(data));
}
constexpr void append(const string& s)noexcept{
append(s.get(), s.length());
}
constexpr void append(const rexy::static_string& s)noexcept{
append(s.get(), s.length());
}
};
namespace detail{
template<class T>
struct is_cx_string_helper{
static constexpr bool value = false;
};
template<size_t N>
struct is_cx_string_helper<cx::string<N>>{
static constexpr bool value = true;
};
template<class... Ts>
struct is_cx_string{
static constexpr bool value = (is_cx_string_helper<std::decay_t<Ts>>::value && ...);
};
}
template<class Str1, class Str2, std::enable_if_t<detail::is_cx_string<Str1,Str2>::value,int> = 0>
constexpr auto operator+(Str1&& l, Str2&& r)noexcept{
return string_cat_expr(std::forward<Str1>(l), std::forward<Str2>(r));
}
template<class Str1, std::enable_if_t<detail::is_cx_string<Str1>::value,int> = 0>
constexpr auto operator+(Str1&& l, const char* r)noexcept{
return string_cat_expr(std::forward<Str1>(l), rexy::static_string(r));
}
template<class Str1, std::enable_if_t<detail::is_cx_string<Str1>::value,int> = 0>
constexpr auto operator+(const char* l, Str1&& r)noexcept{
return string_cat_expr(rexy::static_string(l), std::forward<Str1>(r));
}
}
#endif