rocprofiler-sdk/cxx/details/tokenize.hpp Source File

rocprofiler-sdk/cxx/details/tokenize.hpp Source File#

ROCprofiler-SDK developer API: rocprofiler-sdk/cxx/details/tokenize.hpp Source File
ROCprofiler-SDK developer API 1.0.0
ROCm Profiling API and tools
tokenize.hpp
1// MIT License
2//
3// Copyright (c) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#pragma once
24
25#include <rocprofiler-sdk/cxx/details/mpl.hpp>
26
27#include <functional>
28#include <sstream>
29#include <stdexcept>
30#include <string>
31#include <string_view>
32#include <vector>
33
34namespace rocprofiler
35{
36namespace sdk
37{
38namespace parse
39{
40template <typename Tp>
41inline Tp
42from_string(const std::string& str)
43{
44 auto ss = std::stringstream{str};
45 auto val = Tp{};
46 ss >> val;
47 return val;
48}
49
50template <typename Tp>
51inline Tp
52from_string(const char* cstr)
53{
54 auto ss = std::stringstream{cstr};
55 auto val = Tp{};
56 ss >> val;
57 return val;
58}
59
60/// \brief tokenize a string into a set
61///
62template <typename ContainerT = std::vector<std::string>,
63 typename ValueT = typename ContainerT::value_type,
64 typename PredicateT = std::function<ValueT(ValueT&&)>>
65inline ContainerT
66tokenize(
67 std::string_view line,
68 std::string_view delimiters = "\"',;: ",
69 PredicateT&& predicate = [](ValueT&& s) -> ValueT { return s; })
70{
71 using value_type = ValueT;
72
73 size_t _beginp = 0; // position that is the beginning of the new string
74 size_t _delimp = 0; // position of the delimiter in the string
75 ContainerT _result = {};
76 if(mpl::reserve(_result, 0))
77 {
78 size_t _nmax = 0;
79 for(char itr : line)
80 {
81 if(delimiters.find(itr) != std::string::npos) ++_nmax;
82 }
83 mpl::reserve(_result, _nmax);
84 }
85 while(_beginp < line.length() && _delimp < line.length())
86 {
87 // find the first character (starting at _delimp) that is not a delimiter
88 _beginp = line.find_first_not_of(delimiters, _delimp);
89 // if no a character after or at _end that is not a delimiter is not found
90 // then we are done
91 if(_beginp == std::string::npos) break;
92 // starting at the position of the new string, find the next delimiter
93 _delimp = line.find_first_of(delimiters, _beginp);
94
95 auto _tmp = value_type{};
96 // starting at the position of the new string, get the characters
97 // between this position and the next delimiter
98 if(_beginp < line.length()) _tmp = line.substr(_beginp, _delimp - _beginp);
99
100 // don't add empty strings
101 if(!_tmp.empty())
102 {
103 mpl::emplace(_result, std::forward<PredicateT>(predicate)(std::move(_tmp)));
104 }
105 }
106 return _result;
107}
108
109/// \brief tokenize a string into a set
110///
111template <typename ContainerT = std::vector<std::string>,
112 typename DelimT = std::string_view,
113 typename ValueT = typename ContainerT::value_type,
114 typename PredicateT = ValueT (*)(DelimT&&)>
115inline ContainerT
116tokenize(
117 std::string_view line,
118 const std::vector<DelimT>& delimiters,
119 PredicateT&& predicate = [](DelimT&& s) -> ValueT { return ValueT{s}; })
120{
121 ContainerT _result = {};
122 size_t _start = 0;
123 size_t _end = std::string::npos;
124
125 while(_start != std::string::npos)
126 {
127 _end = std::string::npos;
128
129 // Find the earliest occurrence of any delimiter
130 for(const auto& itr : delimiters)
131 {
132 size_t pos = line.find(itr, _start);
133 if(pos != std::string::npos && (_end == std::string::npos || pos < _end))
134 {
135 _end = pos;
136 }
137 }
138
139 // Extract token and update start position
140 if(_end != std::string::npos)
141 {
142 mpl::emplace(_result,
143 std::forward<PredicateT>(predicate)(line.substr(_start, _end - _start)));
144 _start = _end;
145
146 // Move start past the delimiter
147 for(const auto& delimiter : delimiters)
148 {
149 if(line.compare(_start, delimiter.size(), delimiter) == 0)
150 {
151 _start += delimiter.size();
152 break;
153 }
154 }
155 }
156 else
157 {
158 // Last token after the final delimiter
159 mpl::emplace(_result, std::forward<PredicateT>(predicate)(line.substr(_start)));
160 break;
161 }
162 }
163
164 return _result;
165}
166
167/// \brief apply a string transformation to substring in between a common delimiter.
168///
169template <typename PredicateT = std::function<std::string(const std::string&)>>
170inline std::string
171str_transform(std::string_view input,
172 std::string_view _begin,
173 std::string_view _end,
174 PredicateT&& predicate)
175{
176 size_t _beg_pos = 0; // position that is the beginning of the new string
177 size_t _end_pos = 0; // position of the delimiter in the string
178 std::string _result = std::string{input};
179 while(_beg_pos < _result.length() && _end_pos < _result.length())
180 {
181 // find the first sequence of characters after the end-position
182 _beg_pos = _result.find(_begin, _end_pos);
183
184 // if sequence wasn't found, we are done
185 if(_beg_pos == std::string::npos) break;
186
187 // starting after the position of the first delimiter, find the end sequence
188 if(!_end.empty())
189 _end_pos = _result.find(_end, _beg_pos + 1);
190 else
191 _end_pos = _beg_pos + _begin.length();
192
193 // break if not found
194 if(_end_pos == std::string::npos) break;
195
196 // length of the substr being operated on
197 auto _len = _end_pos - _beg_pos;
198
199 // get the substring between the two delimiters (including first delimiter)
200 auto _sub = _result.substr(_beg_pos, _len);
201
202 // apply the transform
203 auto _transformed = predicate(_sub);
204
205 // only replace if necessary
206 if(_sub != _transformed)
207 {
208 _result = _result.replace(_beg_pos, _len, _transformed);
209 // move end to the end of transformed string
210 _end_pos = _beg_pos + _transformed.length();
211 }
212 }
213 return _result;
214}
215
216inline std::string
217strip(std::string&& str, std::string_view characters)
218{
219 constexpr auto npos = std::string_view::npos;
220
221 auto bpos = str.find_first_not_of(characters);
222 auto epos = str.find_last_not_of(characters);
223
224 if(bpos != npos && epos != npos)
225 return str.substr(bpos, (epos - bpos + 1));
226 else if(bpos != npos)
227 return str.substr(bpos);
228 else if(epos != npos)
229 return str.substr(0, epos + 1);
230
231 return str;
232}
233} // namespace parse
234} // namespace sdk
235} // namespace rocprofiler