rexylib/include/rexy/cx/string.hpp

240 lines
8.5 KiB
C++

/**
This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU 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
#include <cstddef> //ptrdiff_t, size_t
namespace rexy::cx{
template<std::size_t N, class Char>
class string;
}
#include "../string_base.hpp" //string_cat_expr
#include "../string_view.hpp"
#include "../utility.hpp" //strlen, strcmp
#include "../detail/string_appender.hpp"
#include "../traits.hpp" //remove_cvref
#include <type_traits> //nothrow_invocable, integral_constant, declval
#include <iterator> //reverse_iterator
#include "../compat/standard.hpp"
//This is different from rexy::string_view 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. string_view is
//designed to be a thin wrapper around a raw char*, this is designed to allow compile time string concatenation
namespace rexy::cx{
template<std::size_t N, class Char = char>
class string
{
public:
using value_type = Char;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
public:
static constexpr size_type max_size = N;
static constexpr size_type npos = size_type{-1};
public:
value_type m_data[N] = {};
size_type m_length = 0;
public:
constexpr string(void) = default;
template<size_type M>
constexpr string(const value_type(&data)[M])noexcept:
m_length(M)
{
static_assert(M <= N);
for(size_type i = 0;i < M;++i){
m_data[i] = data[i];
}
if(m_data[m_length - 1] == 0){
--m_length; //exclude null terminator in length
}
}
constexpr string(const_pointer data)noexcept:
m_length(rexy::strlen(data))
{
for(size_type i = 0;i < m_length;++i){
m_data[i] = data[i];
}
}
constexpr string(const_pointer data, size_type len)noexcept:
m_length(len)
{
for(size_type i = 0;i < m_length;++i){
m_data[i] = data[i];
}
}
constexpr string(const rexy::basic_string_view<value_type>& str)noexcept:
m_length(str.length())
{
for(size_type 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,Char>>, decltype(expr)>::value)
{
rexy::detail::string_appender<cx::string<N,value_type>> append(*this);
append(expr);
}
constexpr string(const string&)noexcept = default;
constexpr string(string&&)noexcept = default;
REXY_CPP20_CONSTEXPR ~string(void)noexcept = default;
constexpr string& operator=(const_pointer c)noexcept{
m_length = rexy::strlen(c);
for(size_type 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 bool operator==(const string& s)noexcept{return !rexy::strcmp(m_data, s.m_data);}
constexpr bool operator!=(const string& s)noexcept{return rexy::strcmp(m_data, s.m_data);}
constexpr size_type length(void)const noexcept{return m_length;}
constexpr size_type size(void)const noexcept{return m_length;}
constexpr size_type capacity(void)const noexcept{return max_size;}
constexpr bool empty(void)const noexcept{return m_length == 0;}
constexpr pointer c_str(void)noexcept{return m_data;}
constexpr const_pointer c_str(void)const noexcept{return m_data;}
constexpr pointer get(void)noexcept{return m_data;}
constexpr const_pointer get(void)const noexcept{return m_data;}
constexpr operator pointer(void)noexcept{return m_data;}
constexpr operator const_pointer(void)const noexcept{return m_data;}
constexpr reference operator[](size_type i)noexcept{return m_data[i];}
constexpr const_reference operator[](size_type i)const noexcept{return m_data[i];}
constexpr reference at(size_type i)noexcept{return m_data[i];}
constexpr const_reference at(size_type i)const noexcept{return m_data[i];}
constexpr const_reference front(size_type i)const noexcept{return m_data[0];}
constexpr const_reference back(size_type i)const noexcept{return m_data[m_length-1];}
constexpr const_iterator search(const basic_string_view<value_type>& s)const{
return two_way_search(cbegin(), cend(), s.cbegin(), s.cend());
}
constexpr const_iterator search(const_pointer c)const{
return search(basic_string_view<value_type>{c});
}
template<class Searcher>
constexpr const_iterator search(const basic_string_view<value_type>& s, Searcher&& searcher)const{
return searcher(cbegin(), cend(), s.cbegin(), s.cend());
}
template<class Searcher>
constexpr const_iterator search(const_pointer c, Searcher&& searcher)const{
return search(basic_string_view<value_type>{c}, searcher);
}
constexpr iterator begin(void)noexcept{return m_data;}
constexpr const_iterator begin(void)const noexcept{return m_data;}
constexpr const_iterator cbegin(void)const noexcept{return m_data;}
constexpr iterator end(void)noexcept{return m_data+m_length;}
constexpr const_iterator end(void)const noexcept{return m_data+m_length;}
constexpr const_iterator cend(void)const noexcept{return m_data+m_length;}
constexpr const_reverse_iterator rbegin(void)const{return const_reverse_iterator(m_data+m_length);}
constexpr const_reverse_iterator rend(void)const{return const_reverse_iterator(m_data-1);}
constexpr const_reverse_iterator crbegin(void)const{return rbegin();}
constexpr const_reverse_iterator crend(void)const{return rend();}
constexpr bool valid(void)const noexcept{return m_length > 0;}
constexpr bool compare(const string& s)const{return *this == s;}
constexpr bool compare(const_pointer c)const{return *this == c;}
constexpr bool resize(size_type i)noexcept{
if(i >= capacity()){
return false;
}
m_length = i;
m_data[m_length] = 0;
return true;
}
constexpr void append(const_pointer data, size_type len)noexcept{
for(size_type i = 0;i < len;++i){
m_data[m_length++] = data[i];
}
}
constexpr void append(const_pointer data)noexcept{append(data, rexy::strlen(data));}
constexpr void append(const string& s)noexcept{append(s.get(), s.length());}
constexpr void append(const rexy::basic_string_view<value_type>& s)noexcept{append(s.get(), s.length());}
constexpr size_type find_first_of(value_type v, size_type start = 0)const{
return rexy::find_first_of(*this, &v, start, 1);
}
constexpr size_type find_first_of(const_pointer c, size_type pos = 0)const{
return rexy::find_first_of(*this, c, pos, rexy::strlen(c));
}
constexpr size_type find_first_of(const_pointer c, size_type start, size_type size)const{
return rexy::find_first_of(*this, c, start, size);
}
constexpr size_type find_last_of(value_type v, size_type start = 0)const{
return rexy::find_last_of(*this, &v, start, 1);
}
constexpr size_type find_last_of(const_pointer c, size_type start = 0)const{
return rexy::find_last_of(*this, c, start, rexy::strlen(c));
}
constexpr size_type find_last_of(const_pointer c, size_type start, size_type size)const{
return rexy::find_last_of(*this, c, start, size);
}
};
template<class Char, std::size_t N>
string(const Char(&data)[N]) -> string<N, Char>;
template<class... Ts>
struct is_cx_string{
template<class Char, std::size_t N>
static std::true_type check(cx::string<N,Char>);
static std::false_type check(...);
static constexpr bool value = (decltype(check(std::declval<rexy::remove_cvref_t<Ts>>()))::value && ...);
};
}
#ifdef __cpp_concepts
#include "../compat/cpp20/cx/string.hpp"
#else //__cpp_concepts
#include "../compat/cpp17/cx/string.hpp"
#endif //__cpp_concepts
#endif