E-MailRelay
gstringtoken.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 gstringtoken.h
19///
20
21#ifndef G_STRING_TOKEN_H
22#define G_STRING_TOKEN_H
23
24#include "gdef.h"
25#include "gassert.h"
26#include "gstringview.h"
27#include <string>
28#include <type_traits>
29#include <algorithm>
30
31namespace G
32{
33 template <typename T> class StringTokenT ;
34 using StringToken = StringTokenT<std::string> ;
35 using StringTokenView = StringTokenT<string_view> ;
36}
37
38//| \class G::StringTokenT
39/// A zero-copy string token iterator where the token separators
40/// are runs of whitespace characters, with no support for escape
41/// characters. Leading and trailing whitespace are not significant.
42/// Empty whitespace yields a single token. Stepping beyond the
43/// last token is allowed.
44///
45/// \code
46/// for( StringToken t(s," \t",2U) ; t ; ++t )
47/// std::cout << t() << "\n" ;
48/// \endcode
49///
50/// \see G::Str::splitIntoTokens()
51///
52template <typename T>
54{
55public:
56 using char_type = typename T::value_type ;
57
58 StringTokenT( const T & s , const char_type * ws , std::size_t wsn ) noexcept ;
59 ///< Constructor. The parameters must stay valid for
60 ///< the object lifefime.
61 ///<
62 ///< The rvalue overload is deleted to avoid passing a
63 ///< temporary T that has been implicitly constructed from
64 ///< something else. Temporary string_views constructed
65 ///< from a string would be safe, but might be unsafe for
66 ///< other types.
67
68 StringTokenT( const T & s , string_view ws ) noexcept ;
69 ///< Constructor. The parameters must stay valid
70 ///< for the object lifefime.
71
72 bool valid() const noexcept ;
73 ///< Returns true if a valid token position.
74
75 explicit operator bool() const noexcept ;
76 ///< Returns true if a valid token.
77
78 const char_type * data() const noexcept ;
79 ///< Returns the current token pointer.
80
81 std::size_t size() const noexcept ;
82 ///< Returns the current token size.
83
84 std::size_t pos() const noexcept ;
85 ///< Returns the offset of data().
86
87 T operator()() const noexcept(std::is_same<T,string_view>::value) ;
88 ///< Returns the current token substring or T() if
89 ///< not valid().
90
91 StringTokenT<T> & operator++() noexcept ;
92 ///< Moves to the next token.
93
94 StringTokenT<T> & next() noexcept ;
95 ///< Moves to the next token.
96
97public:
98 ~StringTokenT() = default ;
99 StringTokenT( T && s , const char_type * , std::size_t ) = delete ;
100 StringTokenT( T && s , string_view ) = delete ;
101 StringTokenT( const StringTokenT<T> & ) = delete ;
102 StringTokenT( StringTokenT<T> && ) = delete ;
103 StringTokenT<T> & operator=( const StringTokenT<T> & ) = delete ;
104 StringTokenT<T> & operator=( StringTokenT<T> && ) = delete ;
105
106private:
107 static constexpr std::size_t npos = T::npos ;
108 const T & m_s ;
109 const char_type * m_ws ;
110 std::size_t m_wsn ;
111 std::size_t m_pos ;
112 std::size_t m_endpos ;
113} ;
114
115namespace G
116{
117 namespace StringTokenImp /// An implementation namespace for G::StringToken.
118 {
119 template <typename T> inline T substr( const T & s ,
120 std::size_t pos , std::size_t len ) noexcept(std::is_same<T,string_view>::value)
121 {
122 return s.substr( pos , len ) ;
123 }
124 template <> inline string_view substr<string_view>( const string_view & s ,
125 std::size_t pos , std::size_t len ) noexcept
126 {
127 return sv_substr( s , pos , len ) ;
128 }
129 static_assert( !noexcept(std::string().substr(0,0)) , "" ) ;
130 static_assert( noexcept(sv_substr(string_view(),0,0)) , "" ) ;
131 }
132}
133
134template <typename T>
135G::StringTokenT<T>::StringTokenT( const T & s , const char_type * ws , std::size_t wsn ) noexcept :
136 m_s(s) ,
137 m_ws(ws) ,
138 m_wsn(wsn) ,
139 m_pos(s.empty()?npos:s.find_first_not_of(m_ws,0U,m_wsn)) ,
140 m_endpos(s.find_first_of(m_ws,m_pos,m_wsn))
141{
142 G_ASSERT( !(s.empty()) || ( m_pos == npos && m_endpos == npos ) ) ;
143 G_ASSERT( !(!s.empty() && wsn==0U) || ( m_pos == 0U && m_endpos == npos ) ) ;
144 G_ASSERT( !(m_pos == npos) || m_endpos == npos ) ;
145}
146
147template <typename T>
148G::StringTokenT<T>::StringTokenT( const T & s , string_view ws ) noexcept :
149 m_s(s) ,
150 m_ws(ws.data()) ,
151 m_wsn(ws.size()) ,
152 m_pos(s.empty()?npos:s.find_first_not_of(m_ws,0U,m_wsn)) ,
153 m_endpos(s.find_first_of(m_ws,m_pos,m_wsn))
154{
155}
156
157template <typename T>
158const typename T::value_type * G::StringTokenT<T>::data() const noexcept
159{
160 //static_assert( __cplusplus >= 201100 , "" ) ; // broken on msvc
161 return m_s.data() + (m_pos==npos?0U:m_pos) ;
162}
163
164template <typename T>
165std::size_t G::StringTokenT<T>::size() const noexcept
166{
167 return (m_endpos==npos?m_s.size():m_endpos) - m_pos ;
168}
169
170template <typename T>
171std::size_t G::StringTokenT<T>::pos() const noexcept
172{
173 return m_pos == npos ? 0U : m_pos ;
174}
175
176template <typename T>
177G::StringTokenT<T>::operator bool() const noexcept
178{
179 return m_pos != npos ;
180}
181
182template <typename T>
183bool G::StringTokenT<T>::valid() const noexcept
184{
185 return m_pos != npos ;
186}
187
188template <typename T>
189T G::StringTokenT<T>::operator()() const noexcept(std::is_same<T,string_view>::value)
190{
191 using string_type = T ;
192 return m_pos == npos ? string_type{} : StringTokenImp::substr( m_s , m_pos , size() ) ;
193}
194
195template <typename T>
197{
198 m_pos = m_s.find_first_not_of( m_ws , m_endpos , m_wsn ) ;
199 m_endpos = m_s.find_first_of( m_ws , m_pos , m_wsn ) ;
200 G_ASSERT( !(m_s.empty()) || ( m_pos == npos && m_endpos == npos ) ) ;
201 G_ASSERT( !(!m_s.empty() && m_wsn==0U) || ( m_pos == npos && m_endpos == npos ) ) ;
202 G_ASSERT( !(m_pos == npos) || m_endpos == npos ) ;
203 return *this ;
204}
205
206template <typename T>
208{
209 return ++(*this) ;
210}
211
212#endif
A zero-copy string token iterator where the token separators are runs of whitespace characters,...
Definition: gstringtoken.h:54
StringTokenT< T > & next() noexcept
Moves to the next token.
Definition: gstringtoken.h:207
const char_type * data() const noexcept
Returns the current token pointer.
Definition: gstringtoken.h:158
bool valid() const noexcept
Returns true if a valid token position.
Definition: gstringtoken.h:183
std::size_t size() const noexcept
Returns the current token size.
Definition: gstringtoken.h:165
std::size_t pos() const noexcept
Returns the offset of data().
Definition: gstringtoken.h:171
StringTokenT< T > & operator++() noexcept
Moves to the next token.
Definition: gstringtoken.h:196
StringTokenT(const T &s, const char_type *ws, std::size_t wsn) noexcept
Constructor.
Definition: gstringtoken.h:135
T operator()() const noexcept(std::is_same< T, string_view >::value)
Returns the current token substring or T() if not valid().
Definition: gstringtoken.h:189
A class like c++17's std::string_view.
Definition: gstringview.h:51
Low-level classes.
Definition: garg.h:30
STL namespace.