/** 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 . */ #ifndef REXY_CX_STRING_HPP #define REXY_CX_STRING_HPP #include //ptrdiff_t, size_t namespace rexy::cx{ template 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 //nothrow_invocable, integral_constant, declval #include //reverse_iterator #include "../compat/standard.hpp" #include "../compat/string_base.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 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; using const_reverse_iterator = std::reverse_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 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& str)noexcept: m_length(str.length()) { for(size_type i = 0;i < m_length;++i){ m_data[i] = str[i]; } } template constexpr string(const rexy::string_cat_expr& expr) noexcept(std::is_nothrow_invocable>, decltype(expr)>::value) { rexy::detail::string_appender> 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& 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{c}); } template constexpr const_iterator search(const basic_string_view& s, Searcher&& searcher)const{ return searcher(cbegin(), cend(), s.cbegin(), s.cend()); } template constexpr const_iterator search(const_pointer c, Searcher&& searcher)const{ return search(basic_string_view{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& 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 string(const Char(&data)[N]) -> string; template struct is_cx_string{ template static std::true_type check(cx::string); static std::false_type check(...); static constexpr bool value = (decltype(check(std::declval>()))::value && ...); }; } #ifdef __cpp_concepts #include "../compat/cpp20/cx/string.hpp" #else //__cpp_concepts #include "../compat/cpp17/cx/string.hpp" #endif //__cpp_concepts #ifdef REXY_CX_HASH_HPP #include "cx_string_hash.hpp" #endif #endif