E-MailRelay
gstringfield.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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 gstringfield.h
19///
20
21#ifndef G_STRING_FIELD_H
22#define G_STRING_FIELD_H
23
24#include "gdef.h"
25#include "gstringview.h"
26#include "gassert.h"
27#include <string>
28#include <algorithm>
29#include <iterator>
30#include <cstddef> // std::nullptr_t
31
32namespace G
33{
34 template <typename T> class StringFieldT ;
35 template <typename T> class StringFieldIteratorT ;
36 using StringField = StringFieldT<std::string> ;
37 using StringFieldView = StringFieldT<string_view> ;
38}
39
40//| \class G::StringFieldT
41/// A zero-copy string field iterator where the field separators
42/// are short fixed strings.
43///
44/// \code
45/// for( StringField f(s,"\r\n",2U) ; f ; ++f )
46/// std::cout << std::string_view(f.data(),f.size()) << "\n" ;
47/// \endcode
48///
49/// \see G::Str::splitIntoFields(), G::SubString
50///
51template <typename T>
53{
54public:
55 using char_type = typename T::value_type ;
56
57 StringFieldT( const T & s , const char_type * sep , std::size_t sepn ) noexcept ;
58 ///< Constructor. The parameters must stay valid
59 ///< for the object lifefime.
60 ///<
61 ///< The rvalue overload is deleted to avoid passing a
62 ///< temporary T that has been implicitly constructed from
63 ///< something else. Temporary string_views constructed
64 ///< from a string would be safe, but might be unsafe for
65 ///< other types.
66
67 StringFieldT( const T & s , char_type sep ) noexcept ;
68 ///< Constructor. The parameters must stay valid
69 ///< for the object lifefime.
70
71 explicit operator bool() const noexcept ;
72 ///< Returns true if a valid field.
73
74 bool valid() const noexcept ;
75 ///< Returns true if a valid field.
76
77 static constexpr bool deref_operator_noexcept = std::is_same<T,string_view>::value ;
78
79 T operator()() const noexcept(deref_operator_noexcept) ;
80 ///< Returns the current field substring. Prefer data()
81 ///< and size() to avoid copying.
82
83 StringFieldT<T> & operator++() noexcept ;
84 ///< Moves to the next field.
85
86 const char_type * data() const noexcept ;
87 ///< Returns the current field pointer.
88
89 std::size_t size() const noexcept ;
90 ///< Returns the current field size.
91
92 bool first() const noexcept ;
93 ///< Returns true if the current field is the first.
94
95 bool last() const noexcept ;
96 ///< Returns true if the current field is the last.
97
98 std::size_t count() const noexcept ;
99 ///< Returns the number of fields.
100
101public:
102 ~StringFieldT() = default ;
103 StringFieldT( T && s , const char * , std::size_t ) = delete ;
104 StringFieldT( T && s , char ) = delete ;
105 StringFieldT( const StringFieldT<T> & ) = delete ;
106 StringFieldT( StringFieldT<T> && ) = delete ;
107 StringFieldT<T> & operator=( const StringFieldT<T> & ) = delete ;
108 StringFieldT<T> & operator=( StringFieldT<T> && ) = delete ;
109
110private:
111 const T & m_s ;
112 char m_c ;
113 const char_type * m_sep ;
114 std::size_t m_sepn ;
115 std::size_t m_fpos ;
116 std::size_t m_fendpos ;
117} ;
118
119//| \class G::StringFieldIteratorT
120/// A standard forward iterator for G::StringFieldT:
121/// \code
122/// StringFieldView f( "foo,bar"_sv , "," , 1U ) ;
123/// std::copy( begin(f) , end(f) , std::back_inserter(list) ) ; // or...
124/// for( string_view sv : f ) list.push_back( sv ) ;
125/// \endcode
126///
127template <typename T>
129{
130public:
131 using iterator_category = std::forward_iterator_tag ;
132 using value_type = T ;
133 using difference_type = int ;
134 using pointer = T* ;
135 using reference = T& ;
136 explicit StringFieldIteratorT( StringFieldT<T> & ) noexcept ;
137 explicit StringFieldIteratorT( std::nullptr_t ) noexcept ;
138 StringFieldIteratorT & operator++() noexcept ;
139 T operator*() const noexcept(StringFieldT<T>::deref_operator_noexcept) ;
140 bool operator==( StringFieldIteratorT other ) const noexcept ;
141 bool operator!=( StringFieldIteratorT other ) const noexcept ;
142private:
143 StringFieldT<T> * f ;
144} ;
145
146namespace G
147{
148 namespace StringFieldImp /// An implementation namespace for G::StringField.
149 {
150 template <typename T> inline T substr( const T & s ,
151 std::size_t pos , std::size_t len ) noexcept(std::is_same<T,string_view>::value)
152 {
153 return s.substr( pos , len ) ;
154 }
155 template <> string_view inline substr<string_view>( const string_view & s ,
156 std::size_t pos , std::size_t len ) noexcept
157 {
158 return sv_substr( s , pos , len ) ;
159 }
160 static_assert( !noexcept(std::string().substr(0,0)) , "" ) ;
161 static_assert( noexcept(sv_substr(string_view(),0,0)) , "" ) ;
162 }
163}
164
165template <typename T>
166G::StringFieldT<T>::StringFieldT( const T & s , const char_type * sep_p , std::size_t sep_n ) noexcept :
167 m_s(s) ,
168 m_c('\0') ,
169 m_sep(sep_p) ,
170 m_sepn(sep_n) ,
171 m_fpos(s.empty()?std::string::npos:0U) ,
172 m_fendpos(s.find(m_sep,0U,m_sepn))
173{
174}
175
176template <typename T>
177G::StringFieldT<T>::StringFieldT( const T & s , char_type sep ) noexcept :
178 m_s(s) ,
179 m_c(sep) ,
180 m_sep(&m_c) ,
181 m_sepn(1U) ,
182 m_fpos(s.empty()?std::string::npos:0U) ,
183 m_fendpos(s.find(m_sep,0U,m_sepn))
184{
185}
186
187template <typename T>
188const typename T::value_type * G::StringFieldT<T>::data() const noexcept
189{
190 G_ASSERT( m_fpos != std::string::npos ) ;
191 return m_s.data() + m_fpos ;
192}
193
194template <typename T>
195std::size_t G::StringFieldT<T>::size() const noexcept
196{
197 G_ASSERT( m_fpos != std::string::npos ) ;
198 return (m_fendpos==std::string::npos?m_s.size():m_fendpos) - m_fpos ;
199}
200
201template <typename T>
202G::StringFieldT<T>::operator bool() const noexcept
203{
204 return m_fpos != std::string::npos ;
205}
206
207template <typename T>
208bool G::StringFieldT<T>::valid() const noexcept
209{
210 return m_fpos != std::string::npos ;
211}
212
213template <typename T>
214T G::StringFieldT<T>::operator()() const noexcept(deref_operator_noexcept)
215{
216 if( m_fpos == std::string::npos ) return {} ;
217 return StringFieldImp::substr<T>( m_s , m_fpos , size() ) ;
218}
219
220template <typename T>
222{
223 m_fpos = m_fendpos ;
224 if( m_fpos != std::string::npos )
225 {
226 m_fpos = std::min( m_s.size() , m_fpos + m_sepn ) ;
227 m_fendpos = m_s.find( m_sep , m_fpos , m_sepn ) ; // documented as non-throwing
228 }
229 return *this ;
230}
231
232template <typename T>
233bool G::StringFieldT<T>::first() const noexcept
234{
235 return m_fpos == 0U ;
236}
237
238template <typename T>
239bool G::StringFieldT<T>::last() const noexcept
240{
241 return m_fendpos == std::string::npos ;
242}
243
244template <typename T>
245std::size_t G::StringFieldT<T>::count() const noexcept
246{
247 std::size_t n = 0U ;
248 for( StringFieldT<T> f( m_s , m_sep , m_sepn ) ; f ; ++f )
249 n++ ;
250 return n ;
251}
252
253// --
254
255template <typename T>
257 f(&f_in)
258{
259}
260
261template <typename T>
262G::StringFieldIteratorT<T>::StringFieldIteratorT( std::nullptr_t ) noexcept :
263 f(nullptr)
264{
265}
266
267template <typename T>
269{
270 if( f ) ++(*f) ;
271 return *this ;
272}
273
274template <typename T>
275T G::StringFieldIteratorT<T>::operator*() const noexcept(StringFieldT<T>::deref_operator_noexcept)
276{
277 return (*f)() ;
278}
279
280template <typename T>
281bool G::StringFieldIteratorT<T>::operator==( StringFieldIteratorT other ) const noexcept
282{
283 return (f&&f->valid()?f->data():nullptr) == (other.f&&other.f->valid()?other.f->data():nullptr) ;
284}
285
286template <typename T>
287bool G::StringFieldIteratorT<T>::operator!=( StringFieldIteratorT other ) const noexcept
288{
289 return !(*this == other) ;
290}
291
292namespace G
293{
294 template <typename T> StringFieldIteratorT<T> begin( StringFieldT<T> & f ) noexcept
295 {
296 return StringFieldIteratorT<T>( f ) ;
297 }
298}
299
300namespace G
301{
302 template <typename T> StringFieldIteratorT<T> end( StringFieldT<T> & ) noexcept
303 {
304 return StringFieldIteratorT<T>( nullptr ) ;
305 }
306}
307
308#endif
A standard forward iterator for G::StringFieldT:
Definition: gstringfield.h:129
A zero-copy string field iterator where the field separators are short fixed strings.
Definition: gstringfield.h:53
bool first() const noexcept
Returns true if the current field is the first.
Definition: gstringfield.h:233
bool valid() const noexcept
Returns true if a valid field.
Definition: gstringfield.h:208
bool last() const noexcept
Returns true if the current field is the last.
Definition: gstringfield.h:239
StringFieldT< T > & operator++() noexcept
Moves to the next field.
Definition: gstringfield.h:221
StringFieldT(const T &s, const char_type *sep, std::size_t sepn) noexcept
Constructor.
Definition: gstringfield.h:166
T operator()() const noexcept(deref_operator_noexcept)
Returns the current field substring.
Definition: gstringfield.h:214
const char_type * data() const noexcept
Returns the current field pointer.
Definition: gstringfield.h:188
std::size_t size() const noexcept
Returns the current field size.
Definition: gstringfield.h:195
std::size_t count() const noexcept
Returns the number of fields.
Definition: gstringfield.h:245
Low-level classes.
Definition: garg.h:30