E-MailRelay
gstringview.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 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.cpp
19///
20
21#include "gdef.h"
22#include "gstringview.h"
23#include <algorithm>
24#include <iterator> // std::distance
25
26namespace G
27{
28 namespace StringViewImp
29 {
30 template <typename Tsv>
31 bool sv_imatch( Tsv a , Tsv b ) noexcept
32 {
33 if( a.empty() || b.empty() ) return a.empty() && b.empty() ;
34 if( a.size() != b.size() ) return false ;
35 const char * const end = a.data() + a.size() ;
36 const char * q = b.data() ;
37 for( const char * p = a.data() ; p != end ; ++p , ++q )
38 {
39 char c1 = *p ;
40 char c2 = *q ;
41 if( c1 >= 'A' && c1 <= 'Z' ) c1 += '\x20' ;
42 if( c2 >= 'A' && c2 <= 'Z' ) c2 += '\x20' ;
43 if( c1 != c2 ) return false ;
44 }
45 return true ;
46 }
47 template <typename Tsv>
48 Tsv sv_substr( Tsv sv , std::size_t pos , std::size_t count ) noexcept
49 {
50 if( pos >= sv.size() )
51 return { sv.data() , std::size_t(0U) } ;
52 else
53 return { sv.data() + pos , std::min(sv.size()-pos,count) } ;
54 }
55 }
56}
57
58#if GCONFIG_HAVE_CXX_STRING_VIEW
59
60bool G::sv_imatch( std::string_view a , std::string_view b ) noexcept
61{
62 return StringViewImp::sv_imatch<std::string_view>( a , b ) ;
63}
64
65std::string_view G::sv_substr_noexcept( std::string_view a , std::size_t pos , std::size_t count ) noexcept
66{
67 return StringViewImp::sv_substr<std::string_view>( a , pos , count ) ;
68}
69
70#else
71
72bool G::sv_imatch( G::string_view a , G::string_view b ) noexcept
73{
74 return StringViewImp::sv_imatch<G::string_view>( a , b ) ;
75}
76
77G::string_view G::sv_substr_noexcept( G::string_view a , std::size_t pos , std::size_t count ) noexcept
78{
79 return StringViewImp::sv_substr<G::string_view>( a , pos , count ) ;
80}
81
82G::string_view G::string_view::substr( std::size_t pos , std::size_t count ) const
83{
84 if( (empty() && pos!=0U) || pos > m_n )
85 throw std::out_of_range( "string_view::substr" ) ;
86 else if( pos == m_n )
87 return { m_p , std::size_t(0U) } ; // (more than the standard requires)
88 else
89 return { m_p + pos , std::min(m_n-pos,count) } ;
90}
91
92std::size_t G::string_view::find( char c , std::size_t pos ) const noexcept
93{
94 if( empty() || pos >= m_n ) return std::string::npos ;
95 const char * p = m_p + pos ;
96 std::size_t n = m_n - pos ;
97 for( ; n ; p++ , n-- , pos++ )
98 {
99 if( *p == c )
100 return pos ;
101 }
102 return std::string::npos ;
103}
104
105std::size_t G::string_view::find( const char * substr_p , std::size_t pos , std::size_t substr_n ) const
106{
107 return find( string_view(substr_p,substr_n) , pos ) ;
108}
109
110std::size_t G::string_view::find( string_view substr , std::size_t pos ) const
111{
112 if( empty() || pos >= m_n ) return std::string::npos ;
113 if( substr.empty() ) return pos ;
114 auto const end = m_p + m_n ;
115 auto p = std::search( m_p+pos , end , substr.m_p , substr.m_p+substr.m_n ) ;
116 return p == end ? std::string::npos : std::distance(m_p,p) ;
117}
118
119std::size_t G::string_view::find_first_of( const char * chars , std::size_t pos , std::size_t chars_size ) const noexcept
120{
121 return find_first_of( string_view(chars,chars_size) , pos ) ;
122}
123
124std::size_t G::string_view::find_first_of( string_view chars , std::size_t pos ) const noexcept
125{
126 if( empty() || pos >= m_n || chars.empty() ) return std::string::npos ;
127 const char * p = m_p + pos ;
128 std::size_t n = m_n - pos ;
129 for( ; n ; p++ , n-- , pos++ )
130 {
131 const std::size_t i_end = chars.size() ;
132 for( std::size_t i = 0U ; i < i_end ; i++ )
133 {
134 if( *p == chars[i] )
135 return pos ;
136 }
137 }
138 return std::string::npos ;
139}
140
141std::size_t G::string_view::find_first_not_of( char c , std::size_t pos ) const noexcept
142{
143 if( empty() || pos >= m_n ) return std::string::npos ;
144 const char * p = m_p + pos ;
145 std::size_t n = m_n - pos ;
146 for( ; n ; p++ , n-- , pos++ )
147 {
148 if( *p != c )
149 return pos ;
150 }
151 return std::string::npos ;
152}
153
154std::size_t G::string_view::find_first_not_of( const char * chars , std::size_t pos , std::size_t chars_size ) const noexcept
155{
156 return find_first_not_of( string_view(chars,chars_size) , pos ) ;
157}
158
159std::size_t G::string_view::find_first_not_of( string_view chars , std::size_t pos ) const noexcept
160{
161 if( empty() || pos >= m_n ) return std::string::npos ;
162 const char * p = m_p + pos ;
163 std::size_t n = m_n - pos ;
164 for( ; n ; p++ , n-- , pos++ )
165 {
166 bool match = false ;
167 const std::size_t i_end = chars.size() ;
168 for( std::size_t i = 0U ; !match && i < i_end ; i++ )
169 {
170 if( *p == chars[i] )
171 match = true ;
172 }
173 if( !match )
174 return pos ;
175 }
176 return std::string::npos ;
177}
178
179std::size_t G::string_view::find_last_of( const char * chars , std::size_t pos , std::size_t chars_size ) const noexcept
180{
181 return find_last_of( string_view(chars,chars_size) , pos ) ;
182}
183
184std::size_t G::string_view::find_last_of( string_view chars , std::size_t pos ) const noexcept
185{
186 if( empty() ) return std::string::npos ;
187 if( pos >= m_n ) pos = m_n - 1U ;
188 const char * p = data() + pos ;
189 std::size_t count = pos ;
190 for( std::size_t n = 0U ; n <= count ; n++ , p-- , pos-- )
191 {
192 bool match = false ;
193 const std::size_t i_end = chars.size() ;
194 for( std::size_t i = 0U ; !match && i < i_end ; i++ )
195 {
196 if( *p == chars[i] )
197 match = true ;
198 }
199 if( match )
200 return pos ;
201 }
202 return std::string::npos ;
203}
204
205std::size_t G::string_view::find_last_not_of( const char * chars , std::size_t pos , std::size_t chars_size ) const noexcept
206{
207 return find_last_not_of( string_view(chars,chars_size) , pos ) ;
208}
209
210std::size_t G::string_view::find_last_not_of( string_view chars , std::size_t pos ) const noexcept
211{
212 if( empty() ) return std::string::npos ;
213 if( pos >= m_n ) pos = m_n - 1U ;
214 const char * p = data() + pos ;
215 std::size_t count = pos ;
216 for( std::size_t n = 0U ; n <= count ; n++ , p-- , pos-- )
217 {
218 bool match = false ;
219 const std::size_t i_end = chars.size() ;
220 for( std::size_t i = 0U ; !match && i < i_end ; i++ )
221 {
222 if( *p == chars[i] )
223 match = true ;
224 }
225 if( !match )
226 return pos ;
227 }
228 return std::string::npos ;
229}
230
231std::size_t G::string_view::rfind( char c , std::size_t pos ) const noexcept
232{
233 if( empty() || pos == 0U ) return std::string::npos ;
234 if( pos == std::string::npos || pos > m_n ) pos = m_n ;
235 const char * p = m_p + pos - 1U ;
236 std::size_t n = pos - 1U ;
237 for( ; n ; n-- , p-- )
238 {
239 if( *p == c )
240 return n ;
241 }
242 return std::string::npos ;
243}
244
245#endif
A class like c++17's std::string_view.
Definition: gstringview.h:70
Low-level classes.
Definition: garg.h:36