E-MailRelay
gstringview.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gstringview.h
19///
20
21#ifndef G_STRING_VIEW_H
22#define G_STRING_VIEW_H
23
24#include "gdef.h"
25#include <algorithm>
26#include <stdexcept>
27#include <ostream>
28#include <cstring>
29
30namespace G
31{
32 template <typename Tchar> class basic_string_view ;
33 using string_view = basic_string_view<char> ;
34 using wstring_view = basic_string_view<wchar_t> ;
35
36 namespace StringViewImp /// An implementation namespace for G::basic_string_view.
37 {
38 constexpr unsigned int strlen_constexpr( const char * p ) noexcept
39 {
40 return *p ? (strlen_constexpr(p+1)+1U) : 0U ;
41 }
42 constexpr unsigned int strlen_constexpr( const wchar_t * p ) noexcept
43 {
44 return *p ? (strlen_constexpr(p+1)+1U) : 0U ;
45 }
46 inline std::size_t strlen( const char * p ) noexcept
47 {
48 return std::strlen( p ) ;
49 }
50 inline std::size_t strlen( const wchar_t * p ) noexcept
51 {
52 return std::wcslen( p ) ;
53 }
54 constexpr bool same( std::size_t n , const char * p1 , const char * p2 ) noexcept
55 {
56 return n == 0U ? true : ( *p1 == *p2 && same( n-1U , p1+1 , p2+1 ) ) ;
57 }
58 }
59}
60
61//| \class G::basic_string_view
62/// A class template like c++17's std::basic_string_view.
63///
64/// Compared to std::basic_string_view there is an extra free function
65/// for conversion to std::basic_string (G::sv_to_string()) and an
66/// extra constructor overload for constinit initialisation:
67/// \code
68/// static constinit G::string_view sv( "foo" , nullptr ) ;
69/// \endcode
70///
71template <typename Tchar>
73{
74public:
75 using traits = std::char_traits<Tchar> ;
76 using iterator = const Tchar * ;
77 using const_iterator = const Tchar * ;
78 using size_type = std::size_t ;
79 using difference_type = std::ptrdiff_t ;
80 using value_type = Tchar ;
81 static constexpr std::size_t npos = std::size_t(-1) ;
82 basic_string_view() noexcept = default ;
83 constexpr basic_string_view( const Tchar * p , std::size_t n ) noexcept :
84 m_p(p) ,
85 m_n(n)
86 {
87 }
88 basic_string_view( const Tchar * p ) noexcept /*implicit*/ :
89 m_p(p) ,
90 m_n(p?StringViewImp::strlen(p):0U)
91 {
92 }
93 constexpr basic_string_view( const Tchar * p , std::nullptr_t ) noexcept :
94 m_p(p) ,
95 m_n(p?StringViewImp::strlen_constexpr(p):0U)
96 {
97 }
98 constexpr static bool same( basic_string_view a , basic_string_view b ) noexcept
99 {
100 return a.size() == b.size() && ( a.empty() || StringViewImp::same( a.size() , a.data() , b.data() ) ) ;
101 }
102 constexpr std::size_t size() const noexcept { return m_n ; }
103 constexpr std::size_t length() const noexcept { return m_n ; }
104 constexpr const Tchar * data() const noexcept { return m_p ; }
105 constexpr bool empty() const noexcept { return m_n == 0U ; }
106 void swap( basic_string_view<Tchar> & other ) noexcept { std::swap(m_p,other.m_p) ; std::swap(m_n,other.m_n) ; }
107 constexpr const Tchar & operator[]( std::size_t i ) const { return m_p[i] ; }
108 const Tchar & at( std::size_t i ) const { if( i >= m_n ) throw std::out_of_range("string_view") ; return m_p[i] ; }
109 const Tchar * begin() const noexcept { return empty() ? nullptr : m_p ; }
110 const Tchar * cbegin() const noexcept { return empty() ? nullptr : m_p ; }
111 const Tchar * end() const noexcept { return empty() ? nullptr : (m_p+m_n) ; }
112 const Tchar * cend() const noexcept { return empty() ? nullptr : (m_p+m_n) ; }
113 bool operator==( const basic_string_view<Tchar> & other ) const noexcept { return compare(other) == 0 ; }
114 bool operator!=( const basic_string_view<Tchar> & other ) const noexcept { return compare(other) != 0 ; }
115 bool operator<( const basic_string_view<Tchar> & other ) const noexcept { return compare(other) < 0 ; }
116 bool operator<=( const basic_string_view<Tchar> & other ) const noexcept { return compare(other) <= 0 ; }
117 bool operator>( const basic_string_view<Tchar> & other ) const noexcept { return compare(other) > 0 ; }
118 bool operator>=( const basic_string_view<Tchar> & other ) const noexcept { return compare(other) >= 0 ; }
119 int compare( const basic_string_view<Tchar> & other ) const noexcept
120 {
121 int rc = ( empty() || other.empty() ) ? 0 : std::char_traits<Tchar>::compare( m_p , other.m_p , std::min(m_n,other.m_n) ) ;
122 return rc == 0 ? ( m_n < other.m_n ? -1 : (m_n==other.m_n?0:1) ) : rc ;
123 }
124 string_view substr( std::size_t pos , std::size_t count = npos ) const
125 {
126 if( empty() || pos > m_n ) throw std::out_of_range( "string_view" ) ;
127 return string_view( m_p + pos , std::min(m_n-pos,count) ) ;
128 }
129 std::size_t find( Tchar c ) const noexcept
130 {
131 if( empty() ) return std::string::npos ;
132 const Tchar * p = m_p ;
133 std::size_t n = m_n ;
134 for( std::size_t pos = 0U ; n ; p++ , n-- , pos++ )
135 {
136 if( *p == c )
137 return pos ;
138 }
139 return std::string::npos ;
140 }
141 std::size_t find( const Tchar * substr_p , std::size_t pos , std::size_t substr_n ) const
142 {
143 return find( basic_string_view<Tchar>(substr_p,substr_n) , pos ) ;
144 }
145 std::size_t find( basic_string_view<Tchar> substr , std::size_t pos = 0U ) const
146 {
147 if( empty() || pos >= m_n ) return std::string::npos ;
148 if( substr.empty() ) return pos ;
149 auto const end = m_p + m_n ;
150 auto p = std::search( m_p+pos , end , substr.m_p , substr.m_p+substr.m_n ) ;
151 return p == end ? std::string::npos : std::distance(m_p,p) ;
152 }
153 std::size_t find_first_of( const Tchar * chars , std::size_t pos , std::size_t chars_size ) const noexcept
154 {
155 return find_first_of( basic_string_view<Tchar>(chars,chars_size) , pos ) ;
156 }
157 std::size_t find_first_of( basic_string_view<Tchar> chars , std::size_t pos = 0U ) const noexcept
158 {
159 if( empty() || pos >= m_n || chars.empty() ) return std::string::npos ;
160 const Tchar * p = m_p + pos ;
161 std::size_t n = m_n - pos ;
162 for( ; n ; p++ , n-- , pos++ )
163 {
164 const std::size_t i_end = chars.size() ;
165 for( std::size_t i = 0U ; i < i_end ; i++ )
166 {
167 if( *p == chars[i] )
168 return pos ;
169 }
170 }
171 return std::string::npos ;
172 }
173 std::size_t find_first_not_of( const Tchar * chars , std::size_t pos , std::size_t chars_size ) const noexcept
174 {
175 return find_first_not_of( basic_string_view<Tchar>(chars,chars_size) , pos ) ;
176 }
177 std::size_t find_first_not_of( basic_string_view<Tchar> chars , std::size_t pos = 0U ) const noexcept
178 {
179 if( empty() || pos >= m_n || chars.empty() ) return std::string::npos ;
180 const Tchar * p = m_p + pos ;
181 std::size_t n = m_n - pos ;
182 for( ; n ; p++ , n-- , pos++ )
183 {
184 bool match = false ;
185 const std::size_t i_end = chars.size() ;
186 for( std::size_t i = 0U ; !match && i < i_end ; i++ )
187 {
188 if( *p == chars[i] )
189 match = true ;
190 }
191 if( !match )
192 return pos ;
193 }
194 return std::string::npos ;
195 }
196 std::basic_string<Tchar> sv_to_string_imp() const
197 {
198 return empty() ? std::basic_string<Tchar>() : std::basic_string<Tchar>( m_p , m_n ) ;
199 }
200
201private:
202 const Tchar * m_p{nullptr} ;
203 std::size_t m_n{0U} ;
204} ;
205
206namespace G
207{
208 template <typename Tchar> std::basic_string<Tchar> sv_to_string( basic_string_view<Tchar> sv )
209 {
210 // (greppable name -- remove when using c++17 std::string_view)
211 return std::basic_string<Tchar>( sv.sv_to_string_imp() ) ;
212 }
213 inline std::ostream & operator<<( std::ostream & stream , const string_view & sv )
214 {
215 if( !sv.empty() )
216 stream.write( sv.data() , sv.size() ) ; // NOLINT narrowing
217 return stream ;
218 }
219 inline std::wostream & operator<<( std::wostream & stream , const wstring_view & sv )
220 {
221 if( !sv.empty() )
222 stream.write( sv.data() , sv.size() ) ; // NOLINT narrowing
223 return stream ;
224 }
225 template <typename Tchar> void swap( basic_string_view<Tchar> & a , basic_string_view<Tchar> b ) noexcept
226 {
227 a.swap( b ) ;
228 }
229 inline bool operator==( const std::string & s , string_view sv )
230 {
231 return sv.empty() ? s.empty() : ( 0 == s.compare( 0 , s.size() , sv.data() , sv.size() ) ) ;
232 }
233 inline bool operator==( string_view sv , const std::string & s )
234 {
235 return sv.empty() ? s.empty() : ( 0 == s.compare( 0 , s.size() , sv.data() , sv.size() ) ) ;
236 }
237 inline bool operator!=( const std::string & s , string_view sv )
238 {
239 return !(s == sv) ;
240 }
241 inline bool operator!=( string_view sv , const std::string & s )
242 {
243 return !(sv == s) ;
244 }
245}
246
247#endif
A class template like c++17's std::basic_string_view.
Definition: gstringview.h:73
Low-level classes.
Definition: galign.h:28