join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
utils.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_UTILS_HPP
26#define JOIN_CORE_UTILS_HPP
27
28// libjoin.
29#include <join/error.hpp>
30
31// C++.
32#include <type_traits>
33#include <stdexcept>
34#include <iostream>
35#include <iomanip>
36#include <sstream>
37#include <utility>
38#include <chrono>
39#include <random>
40#include <limits>
41#include <bit>
42
43// C.
44#include <cstdint>
45#include <cstddef>
46#include <cstring>
47
48#define JOIN_ALWAYS_INLINE inline __attribute__ ((always_inline))
49
50#define JOIN_LIKELY(x) __builtin_expect (!!(x), 1)
51#define JOIN_UNLIKELY(x) __builtin_expect (!!(x), 0)
52
53#define OUT_ENUM(a) \
54 case a: \
55 return #a
56
57namespace join
58{
59 namespace details
60 {
62 {
63 bool operator() (const std::string& a, const std::string& b) const noexcept
64 {
65 return ::strcasecmp (a.c_str (), b.c_str ()) < 0;
66 }
67 };
68 }
69
74 template <typename Exception, typename... Args>
75 [[noreturn]] __attribute__ ((cold, noinline)) void throwException (Args&&... args)
76 {
77 throw Exception (std::forward<Args> (args)...);
78 }
79
85 template <class Type>
86 inline Type& swap (Type& val)
87 requires (std::is_arithmetic_v<Type> && sizeof (Type) <= sizeof (uint64_t))
88 {
89 if constexpr (std::endian::native == std::endian::little)
90 {
91 if constexpr (sizeof (Type) == sizeof (uint16_t))
92 {
93 val = std::bit_cast<Type> (__builtin_bswap16 (std::bit_cast<uint16_t> (val)));
94 }
95 else if constexpr (sizeof (Type) == sizeof (uint32_t))
96 {
97 val = std::bit_cast<Type> (__builtin_bswap32 (std::bit_cast<uint32_t> (val)));
98 }
99 else if constexpr (sizeof (Type) == sizeof (uint64_t))
100 {
101 val = std::bit_cast<Type> (__builtin_bswap64 (std::bit_cast<uint64_t> (val)));
102 }
103 }
104 return val;
105 }
106
113 inline bool compareNoCase (const std::string& a, const std::string& b)
114 {
115 return ((a.size () == b.size ()) && std::equal (a.begin (), a.end (), b.begin (), [] (char c1, char c2) {
116 return std::toupper (c1) == std::toupper (c2);
117 }));
118 }
119
125 inline std::string& trimLeft (std::string& s)
126 {
127 return s.erase (0, s.find_first_not_of ("\f\t\v\r\n "));
128 }
129
135 inline std::string& trimRight (std::string& s)
136 {
137 return s.erase (s.find_last_not_of (" \f\t\v\r\n") + 1);
138 }
139
145 inline std::string& trim (std::string& s)
146 {
147 return trimLeft (trimRight (s));
148 }
149
157 inline std::string& replaceAll (std::string& str, const std::string& toReplace, const std::string& by)
158 {
159 size_t pos = 0;
160
161 while ((pos = str.find (toReplace, pos)) != std::string::npos)
162 {
163 str.replace (pos, toReplace.length (), by);
164 pos += by.length ();
165 }
166
167 return str;
168 }
169
176 inline std::vector<std::string> split (const std::string& in, const std::string& delim)
177 {
178 std::vector<std::string> tokens;
179 if (in.size ())
180 {
181 size_t beg = 0, end = in.find (delim);
182 size_t sz = delim.size ();
183 while (end != std::string::npos)
184 {
185 tokens.push_back (in.substr (beg, end - beg));
186 beg = end + sz;
187 end = in.find (delim, beg);
188 }
189 tokens.push_back (in.substr (beg));
190 }
191 return tokens;
192 }
193
200 inline std::vector<std::string> rsplit (const std::string& in, const std::string& delim)
201 {
202 std::vector<std::string> tokens;
203 if (in.size ())
204 {
205 size_t beg = in.rfind (delim), end = std::string::npos;
206 size_t sz = delim.size ();
207 while (beg != std::string::npos)
208 {
209 tokens.push_back (in.substr (beg + sz, end - beg - sz));
210 end = beg;
211 beg = in.rfind (delim, end - sz);
212 }
213 tokens.push_back (in.substr (0, end));
214 }
215 return tokens;
216 }
217
225 inline bool getline (std::istream& in, std::string& line, std::streamsize max = 1024)
226 {
227 line.clear ();
228
229 while (max--)
230 {
231 char ch = in.get ();
232 if (in.fail ())
233 {
234 return false;
235 }
236
237 if (ch == '\r')
238 {
239 continue;
240 }
241
242 if (ch == '\n')
243 {
244 return true;
245 }
246
247 line.push_back (ch);
248 }
249
251
252 return false;
253 }
254
262 inline bool getline (std::streambuf& in, std::string& line, std::streamsize max = 1024)
263 {
264 std::istream istream (&in);
265 return getline (istream, line, max);
266 }
267
276 inline bool readBytes (const char*& cur, const char* end, void* out, size_t size) noexcept
277 {
278 if (size > static_cast<size_t> (end - cur))
279 {
281 return false;
282 }
283
284 ::memcpy (out, cur, size);
285 cur += size;
286
287 return true;
288 }
289
298 inline bool writeBytes (char*& cur, const char* end, const void* in, size_t size) noexcept
299 {
300 if (size > static_cast<size_t> (end - cur))
301 {
303 return false;
304 }
305
306 ::memcpy (cur, in, size);
307 cur += size;
308
309 return true;
310 }
311
319 inline uint16_t checksum (const uint16_t* data, size_t len, uint16_t current = 0) noexcept
320 {
321 uint32_t sum = current;
322
323 while (len > 1)
324 {
325 sum += *data++;
326 len -= 2;
327 }
328
329 if (len == 1)
330 {
331 if constexpr (std::endian::native == std::endian::little)
332 {
333 sum += *reinterpret_cast<const uint8_t*> (data);
334 }
335 else
336 {
337 sum += *reinterpret_cast<const uint8_t*> (data) << 8;
338 }
339 }
340
341 sum = (sum >> 16) + (sum & 0xffff);
342 sum += (sum >> 16);
343
344 return static_cast<uint16_t> (~sum);
345 }
346
352 inline void dump (const void* data, unsigned long size, std::ostream& out = std::cout)
353 {
354 const uint8_t* buf = reinterpret_cast<const uint8_t*> (data);
355 std::ostringstream oss;
356
357 for (int i = 0; i < int (size); i += 16)
358 {
359 oss << std::hex << std::uppercase << std::setw (8);
360 oss << std::setfill ('0') << i << std::dec << ":";
361
362 for (int j = 0; j < 16; ++j)
363 {
364 if (j % 4 == 0)
365 oss << std::dec << " ";
366
367 if (i + j < int (size))
368 {
369 oss << std::hex << std::uppercase << std::setw (2);
370 oss << std::setfill ('0') << static_cast<int> (buf[i + j]);
371 }
372 else
373 oss << std::dec << " ";
374 }
375
376 oss << std::dec << " ";
377
378 for (int j = 0; j < 16; ++j)
379 {
380 if (i + j < int (size))
381 {
382 if (isprint (buf[i + j]))
383 oss << buf[i + j];
384 else
385 oss << ".";
386 }
387 }
388
389 oss << "\n";
390 }
391
392 oss << "\n";
393
394 out << oss.str () << std::flush;
395 }
396
401 template <typename Type>
402 Type randomize ()
403 {
404 static_assert (std::is_integral_v<Type>, "randomize requires an integral type");
405 thread_local std::random_device rnd;
406 std::uniform_int_distribution<Type> dist{};
407 return dist (rnd);
408 }
409
416 template <class Func, class... Args>
417 std::chrono::milliseconds benchmark (Func&& func, Args&&... args)
418 {
419 auto beg = std::chrono::steady_clock::now ();
420 func (std::forward<Args> (args)...);
421 auto end = std::chrono::steady_clock::now ();
422 return std::chrono::duration_cast<std::chrono::milliseconds> (end - beg);
423 }
424
430 template <typename Clock, typename Duration>
431 struct timespec toTimespec (std::chrono::time_point<Clock, Duration> timePoint)
432 {
433 auto secs = std::chrono::time_point_cast<std::chrono::seconds> (timePoint);
434 auto ns = std::chrono::time_point_cast<std::chrono::nanoseconds> (timePoint) -
435 std::chrono::time_point_cast<std::chrono::nanoseconds> (secs);
436
437 auto scount = secs.time_since_epoch ().count ();
438 auto ncount = ns.count ();
439
440 return {.tv_sec = scount, .tv_nsec = ncount};
441 }
442
448 template <typename Rep, typename Period>
449 struct timespec toTimespec (std::chrono::duration<Rep, Period> duration)
450 {
451 auto secs = std::chrono::duration_cast<std::chrono::seconds> (duration);
452 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds> (duration - secs);
453
454 auto scount = secs.count ();
455 auto ncount = ns.count ();
456
457 return {.tv_sec = scount, .tv_nsec = ncount};
458 }
459
465 constexpr bool isPow2 (uint64_t value) noexcept
466 {
467 return (value != 0) && ((value & (value - 1)) == 0);
468 }
469
475 constexpr uint64_t nextPow2 (uint64_t value) noexcept
476 {
477 if (value == 0)
478 {
479 return 1;
480 }
481
482 value--;
483 value |= value >> 1;
484 value |= value >> 2;
485 value |= value >> 4;
486 value |= value >> 8;
487 value |= value >> 16;
488 value |= value >> 32;
489
490 return value + 1;
491 }
492}
493
494#endif
Definition acceptor.hpp:32
void dump(const void *data, unsigned long size, std::ostream &out=std::cout)
dump data to standard output stream.
Definition utils.hpp:352
constexpr bool isPow2(uint64_t value) noexcept
check if a value is a power of two.
Definition utils.hpp:465
__attribute__((cold, noinline)) void throwException(Args &&... args)
throw an exception out of the hot path.
Definition utils.hpp:75
std::chrono::milliseconds benchmark(Func &&func, Args &&... args)
benchmark function call.
Definition utils.hpp:417
std::string & trim(std::string &s)
trim.
Definition utils.hpp:145
Type & swap(Type &val)
swaps byte orders.
Definition utils.hpp:86
struct timespec toTimespec(std::chrono::time_point< Clock, Duration > timePoint)
converts time_point to timespec.
Definition utils.hpp:431
constexpr uint64_t nextPow2(uint64_t value) noexcept
round up to the next power of two.
Definition utils.hpp:475
bool readBytes(const char *&cur, const char *end, void *out, size_t size) noexcept
read bytes from a buffer.
Definition utils.hpp:276
uint16_t checksum(const uint16_t *data, size_t len, uint16_t current=0) noexcept
get standard 1s complement checksum.
Definition utils.hpp:319
bool compareNoCase(const std::string &a, const std::string &b)
case insensitive string comparison.
Definition utils.hpp:113
Type randomize()
create a random number.
Definition utils.hpp:402
std::vector< std::string > split(const std::string &in, const std::string &delim)
split a string using a delimiter.
Definition utils.hpp:176
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
thread_local std::error_code lastError
last error.
Definition error.cpp:32
std::string & trimLeft(std::string &s)
trim left.
Definition utils.hpp:125
bool getline(std::istream &in, std::string &line, std::streamsize max=1024)
read line (delimiter "\r\n").
Definition utils.hpp:225
std::vector< std::string > rsplit(const std::string &in, const std::string &delim)
split a string in reverse order using a delimiter.
Definition utils.hpp:200
bool writeBytes(char *&cur, const char *end, const void *in, size_t size) noexcept
write bytes to a buffer.
Definition utils.hpp:298
std::string & replaceAll(std::string &str, const std::string &toReplace, const std::string &by)
replace all occurrences of a substring.
Definition utils.hpp:157
std::string & trimRight(std::string &s)
trim right.
Definition utils.hpp:135
Definition error.hpp:144
Definition utils.hpp:62
bool operator()(const std::string &a, const std::string &b) const noexcept
Definition utils.hpp:63