Gemmi C++ API
Loading...
Searching...
No Matches
util.hpp
Go to the documentation of this file.
1// Copyright 2017 Global Phasing Ltd.
2//
3// Utilities. Mostly for working with strings and vectors.
4
5#ifndef GEMMI_UTIL_HPP_
6#define GEMMI_UTIL_HPP_
7
8#include <cassert>
9#include <cctype> // for isspace
10#include <cstring> // for strncmp
11#include <algorithm> // for equal, find, remove_if
12#include <iterator> // for begin, end, make_move_iterator
13#include <string>
14#include <vector>
15
16namespace gemmi {
17
18// ##### string helpers #####
19
20inline void append_to_str(std::string& out, int v) { out += std::to_string(v); }
21inline void append_to_str(std::string& out, size_t v) { out += std::to_string(v); }
22void append_to_str(std::string& out, double) = delete;
23template<typename T>
24void append_to_str(std::string& out, const T& v) { out += v; }
25
26inline void cat_to(std::string&) {}
27template <typename T, typename... Args>
28void cat_to(std::string& out, const T& value, Args const&... args) {
29 append_to_str(out, value);
30 cat_to(out, args...);
31}
32template <class... Args>
33std::string cat(Args const&... args) {
34 std::string out;
35 cat_to(out, args...);
36 return out;
37}
38
39inline bool starts_with(const std::string& str, const std::string& prefix) {
40 size_t sl = prefix.length();
41 return str.length() >= sl && str.compare(0, sl, prefix) == 0;
42}
43
44template<size_t N> bool starts_with(const char* a, const char (&b)[N]) {
45 return std::strncmp(a, b, N-1) == 0;
46}
47
48inline bool ends_with(const std::string& str, const std::string& suffix) {
49 size_t sl = suffix.length();
50 return str.length() >= sl && str.compare(str.length() - sl, sl, suffix) == 0;
51}
52
53// can be faster than std::tolower() b/c it takes char not int
54inline char lower(char c) {
55 if (c >= 'A' && c <= 'Z')
56 return c | 0x20;
57 return c;
58}
59
60// works as expected only for a-zA-Z
61inline char alpha_up(char c) { return c & ~0x20; }
62
63inline std::string to_lower(std::string str) {
64 for (char& c : str)
65 if (c >= 'A' && c <= 'Z')
66 c |= 0x20;
67 return str;
68}
69
70inline std::string to_upper(std::string str) {
71 for (char& c : str)
72 if (c >= 'a' && c <= 'z')
73 c &= ~0x20;
74 return str;
75}
76
77// case-insensitive character comparison
78inline bool isame(char a, char b) {
79 return a == b || ((a^b) == 0x20 && (a|0x20) >= 'a' && (a|0x20) <= 'z');
80}
81
82// Case-insensitive comparisons. The second arg must be lowercase.
83
84inline bool iequal_from(const std::string& str, size_t offset, const std::string& low) {
85 return str.length() == low.length() + offset &&
86 std::equal(std::begin(low), std::end(low), str.begin() + offset,
87 [](char c1, char c2) { return c1 == lower(c2); });
88}
89
90inline bool iequal(const std::string& str, const std::string& low) {
91 return iequal_from(str, 0, low);
92}
93
94inline bool istarts_with(const std::string& str, const std::string& prefix) {
95 return str.length() >= prefix.length() &&
96 std::equal(std::begin(prefix), std::end(prefix), str.begin(),
97 [](char c1, char c2) { return c1 == lower(c2); });
98}
99inline bool iends_with(const std::string& str, const std::string& suffix) {
100 size_t sl = suffix.length();
101 return str.length() >= sl &&
102 std::equal(std::begin(suffix), std::end(suffix), str.end() - sl,
103 [](char c1, char c2) { return c1 == lower(c2); });
104}
105
106inline bool giends_with(const std::string& str, const std::string& suffix) {
107 return iends_with(str, suffix) || iends_with(str, suffix + ".gz");
108}
109
110inline std::string trim_str(const std::string& str) {
111 const std::string ws = " \r\n\t";
112 std::string::size_type first = str.find_first_not_of(ws);
113 if (first == std::string::npos)
114 return std::string{};
115 std::string::size_type last = str.find_last_not_of(ws);
116 return str.substr(first, last - first + 1);
117}
118
119inline std::string rtrim_str(const std::string& str) {
120 std::string::size_type last = str.find_last_not_of(" \r\n\t");
121 return str.substr(0, last == std::string::npos ? 0 : last + 1);
122}
123
124// end is after the last character of the string (typically \0)
125inline const char* rtrim_cstr(const char* start, const char* end=nullptr) {
126 if (!start)
127 return nullptr;
128 if (!end) {
129 end = start;
130 while (*end != '\0')
131 ++end;
132 }
133 while (end > start && std::isspace(end[-1]))
134 --end;
135 return end;
136}
137
138namespace impl {
139inline size_t length(char) { return 1; }
140inline size_t length(const std::string& s) { return s.length(); }
141}
142
143// takes a single separator (usually char or string);
144// may return empty fields
145template<typename S>
146void split_str_into(const std::string& str, S sep,
147 std::vector<std::string>& result) {
148 std::size_t start = 0, end;
149 while ((end = str.find(sep, start)) != std::string::npos) {
150 result.emplace_back(str, start, end - start);
151 start = end + impl::length(sep);
152 }
153 result.emplace_back(str, start);
154}
155
156template<typename S>
157std::vector<std::string> split_str(const std::string& str, S sep) {
158 std::vector<std::string> result;
160 return result;
161}
162
163// _multi variants takes multiple 1-char separators as a string;
164// discards empty fields
165inline void split_str_into_multi(const std::string& str, const char* seps,
166 std::vector<std::string>& result) {
167 std::size_t start = str.find_first_not_of(seps);
168 while (start != std::string::npos) {
169 std::size_t end = str.find_first_of(seps, start);
170 result.emplace_back(str, start, end - start);
171 start = str.find_first_not_of(seps, end);
172 }
173}
174
175inline std::vector<std::string> split_str_multi(const std::string& str,
176 const char* seps=" \t") {
177 std::vector<std::string> result;
179 return result;
180}
181
182template<typename T, typename S, typename F>
183std::string join_str(T begin, T end, const S& sep, const F& getter) {
184 std::string r;
185 bool first = true;
186 for (T i = begin; i != end; ++i) {
187 if (!first)
188 r += sep;
189 r += getter(*i);
190 first = false;
191 }
192 return r;
193}
194
195template<typename T, typename S>
196std::string join_str(T begin, T end, const S& sep) {
197 return join_str(begin, end, sep, [](const std::string& t) { return t; });
198}
199
200template<typename T, typename S, typename F>
201std::string join_str(const T& iterable, const S& sep, const F& getter) {
202 return join_str(iterable.begin(), iterable.end(), sep, getter);
203}
204
205template<typename T, typename S>
206std::string join_str(const T& iterable, const S& sep) {
207 return join_str(iterable.begin(), iterable.end(), sep);
208}
209
210template<typename T, typename S>
211void string_append_sep(std::string& str, S sep, const T& item) {
212 if (!str.empty())
213 str += sep;
214 str += item;
215}
216
217inline void replace_all(std::string &s,
218 const std::string &old, const std::string &new_) {
219 std::string::size_type pos = 0;
220 while ((pos = s.find(old, pos)) != std::string::npos) {
221 s.replace(pos, old.size(), new_);
222 pos += new_.size();
223 }
224}
225
226// list is a comma separated string
227inline bool is_in_list(const std::string& name, const std::string& list,
228 char sep=',') {
229 if (name.length() >= list.length())
230 return name == list;
231 for (size_t start=0, end=0; end != std::string::npos; start=end+1) {
232 end = list.find(sep, start);
233 if (list.compare(start, end - start, name) == 0)
234 return true;
235 }
236 return false;
237}
238
239// ##### vector helpers #####
240
241template <class T>
242bool in_vector(const T& x, const std::vector<T>& v) {
243 return std::find(v.begin(), v.end(), x) != v.end();
244}
245
246template <typename F, typename T>
247bool in_vector_f(F f, const std::vector<T>& v) {
248 return std::find_if(v.begin(), v.end(), f) != v.end();
249}
250
251template <class T>
252T* vector_end_ptr(std::vector<T>& v) { return v.data() + v.size(); }
253template <class T>
254const T* vector_end_ptr(const std::vector<T>& v) { return v.data() + v.size(); }
255
256template <class T>
257void vector_move_extend(std::vector<T>& dst, std::vector<T>&& src) {
258 if (dst.empty())
259 dst = std::move(src);
260 else
261 dst.insert(dst.end(), std::make_move_iterator(src.begin()),
262 std::make_move_iterator(src.end()));
263}
264
265// wrapper around the erase-remove idiom
266template <class T, typename F>
267void vector_remove_if(std::vector<T>& v, F&& condition) {
268 v.erase(std::remove_if(v.begin(), v.end(), condition), v.end());
269}
270
273template <class T>
274void vector_insert_columns(std::vector<T>& data, size_t old_width,
275 size_t length, size_t n, size_t pos, const T& new_value) {
276 assert(data.size() == old_width * length);
277 assert(pos <= old_width);
278 data.resize(data.size() + n * length);
279 typename std::vector<T>::iterator dst = data.end();
280 for (size_t i = length; i-- != 0; ) {
281 for (size_t j = old_width; j-- != pos; )
282 *--dst = data[i * old_width + j];
283 for (size_t j = n; j-- != 0; )
284 *--dst = new_value;
285 for (size_t j = pos; j-- != 0; )
286 *--dst = data[i * old_width + j];
287 }
288 assert(dst == data.begin());
289}
292template <class T>
293void vector_remove_column(std::vector<T>& data, size_t new_width, size_t pos) {
294 assert(pos <= new_width);
295 for (size_t source = pos + 1; source < data.size(); ++source)
296 for (size_t i = 0; i < new_width && source < data.size(); ++i)
297 data[pos++] = data[source++];
298 data.resize(pos);
299}
300
301
302// ##### other helpers #####
303
304// Numeric ID used for case-insensitive comparison of 4 letters.
305// s must have 4 chars or 3 chars + NUL, ' ' and NUL are equivalent in s.
306constexpr int ialpha4_id(const char* s) {
307 return (s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]) & ~0x20202020;
308}
309// Numeric ID used for case-insensitive comparison of 3 letters.
310constexpr int ialpha3_id(const char* s) {
311 return (s[0] << 16 | s[1] << 8 | s[2]) & ~0x20202020;
312}
313
314} // namespace gemmi
315#endif
T * vector_end_ptr(std::vector< T > &v)
Definition util.hpp:252
void append_to_str(std::string &out, int v)
Definition util.hpp:20
bool iequal_from(const std::string &str, size_t offset, const std::string &low)
Definition util.hpp:84
char lower(char c)
Definition util.hpp:54
bool ends_with(const std::string &str, const std::string &suffix)
Definition util.hpp:48
void vector_remove_if(std::vector< T > &v, F &&condition)
Definition util.hpp:267
bool isame(char a, char b)
Definition util.hpp:78
const char * rtrim_cstr(const char *start, const char *end=nullptr)
Definition util.hpp:125
constexpr int ialpha3_id(const char *s)
Definition util.hpp:310
bool in_vector_f(F f, const std::vector< T > &v)
Definition util.hpp:247
bool istarts_with(const std::string &str, const std::string &prefix)
Definition util.hpp:94
std::string rtrim_str(const std::string &str)
Definition util.hpp:119
std::string join_str(T begin, T end, const S &sep, const F &getter)
Definition util.hpp:183
bool in_vector(const T &x, const std::vector< T > &v)
Definition util.hpp:242
bool iends_with(const std::string &str, const std::string &suffix)
Definition util.hpp:99
void split_str_into_multi(const std::string &str, const char *seps, std::vector< std::string > &result)
Definition util.hpp:165
std::string to_lower(std::string str)
Definition util.hpp:63
void string_append_sep(std::string &str, S sep, const T &item)
Definition util.hpp:211
std::string to_upper(std::string str)
Definition util.hpp:70
void vector_insert_columns(std::vector< T > &data, size_t old_width, size_t length, size_t n, size_t pos, const T &new_value)
Definition util.hpp:274
std::string cat(Args const &... args)
Definition util.hpp:33
bool is_in_list(const std::string &name, const std::string &list, char sep=',')
Definition util.hpp:227
bool giends_with(const std::string &str, const std::string &suffix)
Definition util.hpp:106
void cat_to(std::string &)
Definition util.hpp:26
bool starts_with(const std::string &str, const std::string &prefix)
Definition util.hpp:39
std::vector< std::string > split_str_multi(const std::string &str, const char *seps=" \t")
Definition util.hpp:175
std::vector< std::string > split_str(const std::string &str, S sep)
Definition util.hpp:157
void vector_remove_column(std::vector< T > &data, size_t new_width, size_t pos)
Definition util.hpp:293
void split_str_into(const std::string &str, S sep, std::vector< std::string > &result)
Definition util.hpp:146
bool iequal(const std::string &str, const std::string &low)
Definition util.hpp:90
std::string trim_str(const std::string &str)
Definition util.hpp:110
void replace_all(std::string &s, const std::string &old, const std::string &new_)
Definition util.hpp:217
constexpr int ialpha4_id(const char *s)
Definition util.hpp:306
void vector_move_extend(std::vector< T > &dst, std::vector< T > &&src)
Definition util.hpp:257
char alpha_up(char c)
Definition util.hpp:61