jaulib v1.3.8
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
basic_types.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020-2024 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <cmath>
26#include <cstdint>
27#include <cinttypes>
28#include <cstring>
29
30#include <ctime>
31
32#include <algorithm>
33
34#include <jau/byte_util.hpp>
35#include <jau/cpp_lang_util.hpp>
36#include <jau/debug.hpp>
37#include <jau/basic_types.hpp>
38#include <jau/float_math.hpp>
39#include <jau/functional.hpp>
40#include <jau/int_math.hpp>
41#include <jau/int_types.hpp>
42#include <jau/secmem.hpp>
44#include <jau/string_util.hpp>
45#include <utility>
46
47using namespace jau;
48
49void jau::zero_bytes_sec(void *s, size_t n) noexcept __attrdef_no_optimize__
50{
51 // asm asm-qualifiers ( AssemblerTemplate : OutputOperands [ : InputOperands [ : Clobbers ] ] )
52 asm volatile("" : "+r,m"(s), "+r,m"(n) : : "memory"); // a nop asm, usually guaranteeing synchronized order and non-optimization
53 ::explicit_bzero(s, n);
54 // ::bzero(s, n);
55 // ::memset(s, 0, n);
56}
57
58/**
59 * See <http://man7.org/linux/man-pages/man2/clock_gettime.2.html>
60 * <p>
61 * Regarding avoiding kernel via VDSO,
62 * see <http://man7.org/linux/man-pages/man7/vdso.7.html>,
63 * clock_gettime seems to be well supported at least on kernel >= 4.4.
64 * Only bfin and sh are missing, while ia64 seems to be complicated.
65 */
67 struct timespec t;
68 ::clock_gettime(CLOCK_MONOTONIC, &t);
69 return fraction_timespec( (int64_t)t.tv_sec, (int64_t)t.tv_nsec );
70}
71
73 struct timespec t { 0, 0 };
74 ::clock_gettime(CLOCK_REALTIME, &t);
75 return fraction_timespec( (int64_t)t.tv_sec, (int64_t)t.tv_nsec );
76}
77
78uint64_t jau::getCurrentMilliseconds() noexcept {
79 constexpr uint64_t ms_per_sec = 1'000UL;
80 constexpr uint64_t ns_per_ms = 1'000'000UL;
81 struct timespec t { 0, 0 };
82 ::clock_gettime(CLOCK_MONOTONIC, &t);
83 return static_cast<uint64_t>( t.tv_sec ) * ms_per_sec +
84 static_cast<uint64_t>( t.tv_nsec ) / ns_per_ms;
85}
86
87uint64_t jau::getWallClockSeconds() noexcept {
88 struct timespec t { 0, 0 };
89 ::clock_gettime(CLOCK_REALTIME, &t);
90 return static_cast<uint64_t>( t.tv_sec );
91}
92
93std::string fraction_timespec::to_string() const noexcept {
94 return std::to_string(tv_sec) + "s + " + std::to_string(tv_nsec) + "ns";
95}
96
97std::string fraction_timespec::to_iso8601_string(bool space_separator, bool muteTime) const noexcept {
98 std::time_t t0 = static_cast<std::time_t>(tv_sec);
99 struct std::tm tm_0;
100 if( nullptr == ::gmtime_r(&t0, &tm_0) ) {
101 if( muteTime ) {
102 if( space_separator ) {
103 return "1970-01-01";
104 } else {
105 return "1970-01-01Z";
106 }
107 } else {
108 if( space_separator ) {
109 return "1970-01-01 00:00:00";
110 } else {
111 return "1970-01-01T00:00:00Z";
112 }
113 }
114 } else {
115 // 2022-05-28T23:23:50Z 20+1
116 //
117 // 1655994850s + 228978909ns
118 // 2022-06-23T14:34:10.228978909Z 30+1
119 char b[30 + 1];
120 size_t p;
121 if( muteTime || ( 0 == tm_0.tm_hour && 0 == tm_0.tm_min && 0 == tm_0.tm_sec && 0 == tv_nsec ) ) {
122 p = ::strftime(b, sizeof(b), "%Y-%m-%d", &tm_0);
123 } else {
124 if( space_separator ) {
125 p = ::strftime(b, sizeof(b), "%Y-%m-%d %H:%M:%S", &tm_0);
126 } else {
127 p = ::strftime(b, sizeof(b), "%Y-%m-%dT%H:%M:%S", &tm_0);
128 }
129 }
130 if( 0 < p && p < sizeof(b) - 1 ) {
131 size_t q = 0;
132 const size_t remaining = sizeof(b) - p;
133 if( !muteTime && 0 < tv_nsec ) {
134 q = ::snprintf(b + p, remaining, ".%09" PRIi64, tv_nsec);
135 }
136 if( !space_separator ) {
137 ::snprintf(b + p + q, remaining-q, "Z");
138 }
139 }
140 return std::string(b);
141 }
142}
143
144fraction_timespec fraction_timespec::from(int year, unsigned month, unsigned day,
145 unsigned hour, unsigned minute,
146 unsigned seconds, uint64_t nano_seconds) noexcept {
148 if( !( 1<=month && month<=12 &&
149 1<=day && day<=31 &&
150 hour<=23 &&
151 minute<=59 && seconds<=60 ) ) {
152 return res; // error
153 }
154 struct std::tm tm_0;
155 ::memset(&tm_0, 0, sizeof(tm_0));
156 tm_0.tm_year = year - 1900; // years since 1900
157 tm_0.tm_mon = static_cast<int>(month) - 1; // months since Janurary [0-11]
158 tm_0.tm_mday = static_cast<int>(day); // day of the month [1-31]
159 tm_0.tm_hour = static_cast<int>(hour); // hours since midnight [0-23]
160 tm_0.tm_min = static_cast<int>(minute); // minutes after the hour [0-59]
161 tm_0.tm_sec = static_cast<int>(seconds); // seconds after the minute [0-60], including one leap second
162 std::time_t t1 = ::timegm (&tm_0);
163 res.tv_sec = static_cast<int64_t>(t1);
164 res.tv_nsec = static_cast<int64_t>(nano_seconds);
165 return res;
166}
167
168fraction_timespec fraction_timespec::from(const std::string_view datestr, Bool addUTCOffset) noexcept {
169 int64_t utcOffsetSec;
170 size_t consumedChars;
171 fraction_timespec res = from(datestr, utcOffsetSec, consumedChars);
172 if( value(addUTCOffset) ) {
173 res.tv_sec += utcOffsetSec;
174 }
175 (void)consumedChars;
176 return res;
177}
178
179fraction_timespec fraction_timespec::from(const std::string_view datestr, int64_t &utcOffsetSec, size_t &consumedChars) noexcept {
180 consumedChars = 0;
181 utcOffsetSec = 0;
182 if( nullptr == datestr.data() || 0 == datestr.length() ) {
183 return fraction_timespec(); // error
184 }
185 const char * const str = datestr.data();
186 const size_t len = datestr.length();
187 size_t idx;
188 int y=0;
189 unsigned M=0, d=0;
190 {
191 int count=0;
192 const int items = std::sscanf(str, "%4d-%2u-%2u%n", &y, &M, &d, &count);
193 // INFO_PRINT("X01: items %d, chars %d, len %zu, str: '%s'", items, count, len, str);
194 if( 3 != items || !(5 <= count && static_cast<size_t>(count) <= len) ) {
195 return fraction_timespec(); // error
196 }
197 idx = count;
198 }
199 consumedChars = idx;
201 if( idx == len) {
202 return res; // EOS
203 }
204 if( str[idx] == 'Z' ) {
205 ++consumedChars;
206 return res; // EOS
207 }
208 if( str[idx] == 'T' ) {
209 ++idx;
210 } else if( str[idx] == ' ' ) {
211 // eat up space before time
212 do {
213 ++idx;
214 } while( idx < len && str[idx] == ' ' );
215 } else {
216 return res; // remainder not matching
217 }
218 if( idx == len ) {
219 return res; // EOS post 'T' or ' '
220 }
221
222 unsigned h=0,m=0,s=0;
223 {
224 int count=0;
225 const int items = std::sscanf(str+idx, "%2u:%2u:%2u%n", &h, &m, &s, &count);
226 // INFO_PRINT("X02: items %d, chars %d, len %zu, str: '%s'", items, count, len-idx, str+idx);
227 if( 3 != items || !(5 <= count && static_cast<size_t>(count) <= len - idx) ) {
228 return res; // error in remainder
229 }
230 idx += count;
231 }
232 consumedChars = idx;
233 res = fraction_timespec::from(y, M, d, h, m, s, 0);
234
235 if( idx == len) {
236 return res; // EOS
237 }
238 if( str[idx] == 'Z' ) {
239 ++consumedChars;
240 return res; // EOS
241 }
242 if( str[idx] == '.' ) {
243 ++idx;
244 if( idx == len) {
245 return res; // EOS
246 }
247 unsigned long fs=0;
248 {
249 int count=0;
250 const int items = std::sscanf(str+idx, "%9lu%n", &fs, &count);
251 // INFO_PRINT("X03: items %d, chars %d, len %zu, str: '%s'", items, count, len-idx, str+idx);
252 if( 1 != items || !(0 <= count && static_cast<size_t>(count) <= len - idx) ) {
253 return res; // error in remainder
254 }
255 idx += count;
256 }
257 const jau::nsize_t fs_digits = jau::digits10(fs, 1, true);
258 if( 9 < fs_digits ) {
259 return res; // error in remainder
260 }
261 res.tv_nsec = static_cast<int64_t>(fs) * static_cast<int64_t>( std::pow(10, 9 - fs_digits) );
262 consumedChars = idx;
263 }
264 if( idx == len) {
265 return res; // EOS
266 }
267 if( str[idx] == 'Z' ) {
268 ++consumedChars;
269 return res; // EOS
270 }
271 // Offset parsing...
272
273 // Eat up space before offset
274 while( idx < len && str[idx] == ' ' ) {
275 ++idx;
276 }
277 if( idx == len) {
278 return res; // EOS
279 }
280 int64_t offset_sign = 1;
281 if( str[idx] == '+' ) {
282 ++idx;
283 } else if( str[idx] == '-' ) {
284 ++idx;
285 offset_sign = -1;
286 }
287 if( idx == len) {
288 return res; // EOS or done (no offset)
289 }
290
291 unsigned oh=0,om=0;
292 {
293 int count=0;
294 const int items = std::sscanf(str+idx, "%2u%n", &oh, &count);
295 // INFO_PRINT("X04: items %d, chars %d, len %zu, str: '%s'", items, count, len-idx, str+idx);
296 if( 1 != items || !(1 <= count && static_cast<size_t>(count) <= len - idx) ) {
297 return res; // error in remainder
298 }
299 idx += count;
300 }
301 if( idx < len ) {
302 // make `:` separator optional
303 if( str[idx] == ':' ) {
304 ++idx;
305 }
306 if( idx < len ) {
307 int count=0;
308 const int items = std::sscanf(str+idx, "%2u%n", &om, &count);
309 // INFO_PRINT("X05: items %d, chars %d, len %zu, str: '%s'", items, count, len-idx, str+idx);
310 if( 1 == items ) {
311 idx += count;
312 } // else tolerate missing minutes
313 }
314 }
315 consumedChars = idx;
316 // add the timezone offset if desired, rendering result non-UTC
317 utcOffsetSec = offset_sign * ( ( oh * 60_i64 * 60_i64 ) + ( om * 60_i64 ) );
318 return res;
319}
320
321bool jau::milli_sleep(uint64_t td_ms, const bool ignore_irq) noexcept {
322 constexpr uint64_t ms_per_sec = 1'000UL;
323 constexpr uint64_t ns_per_ms = 1'000'000UL;
324 constexpr uint64_t ns_per_sec = 1'000'000'000UL;;
325 const int64_t td_ns_0 = static_cast<int64_t>( (td_ms * ns_per_ms) % ns_per_sec );
326 struct timespec ts;
327 ts.tv_sec = static_cast<decltype(ts.tv_sec)>(td_ms/ms_per_sec); // signed 32- or 64-bit integer
328 ts.tv_nsec = td_ns_0;
329 int res;
330 do {
331 res = ::clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts);
332 } while( ignore_irq && EINTR == res );
333 return 0 == res;
334}
335bool jau::sleep(const fraction_timespec& relative_time, const bool ignore_irq) noexcept {
336 struct timespec ts = relative_time.to_timespec();
337 int res;
338 do {
339 res = ::clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts);
340 } while( ignore_irq && EINTR == res );
341 return 0 == res;
342}
343
344bool jau::sleep_until(const fraction_timespec& absolute_time, const bool monotonic, const bool ignore_irq) noexcept {
345 if( absolute_time <= fraction_tv::zero ) {
346 return false;
347 }
348 // typedef struct timespec __gthread_time_t;
349 struct timespec ts = absolute_time.to_timespec();
350 int res;
351 do {
352 res = ::clock_nanosleep(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME,
353 TIMER_ABSTIME, &ts, &ts);
354 } while( ignore_irq && EINTR == res );
355 return 0 == res;
356}
357
358bool jau::sleep_for(const fraction_timespec& relative_time, const bool monotonic, const bool ignore_irq) noexcept {
359 if( relative_time <= fraction_tv::zero ) {
360 return false;
361 }
362 const fraction_timespec now = monotonic ? getMonotonicTime() : getWallClockTime();
363 return sleep_until( now + relative_time, monotonic, ignore_irq );
364}
365
366bool jau::sleep_for(const fraction_i64& relative_time, const bool monotonic, const bool ignore_irq) noexcept {
367 if( relative_time <= fractions_i64::zero ) {
368 return false;
369 }
370 bool overflow = false;
371 const fraction_timespec atime = ( monotonic ? getMonotonicTime() : getWallClockTime() ) + fraction_timespec(relative_time, &overflow);
372 if( overflow ) {
373 return false;
374 } else {
375 return sleep_until( atime, monotonic, ignore_irq );
376 }
377}
378
379#if defined(__linux__) && defined(__GLIBC__)
380 // Hack for glibc/pthread library w/o pthread_cond_clockwait,
381 // i.e. on g++8, arm32, Debian 10.
382 // Here we have to use pthread_cond_timedwait(), ignoring the clock type.
383 //
384 // __attribute__((weak)) tested w/ g++8.3, g++10 and clang-11
385 //
386 typedef __clockid_t os_clockid_t;
387 extern int pthread_cond_clockwait (pthread_cond_t *__restrict __cond,
388 pthread_mutex_t *__restrict __mutex,
389 os_clockid_t __clock_id,
390 const struct timespec *__restrict __abstime)
391 __nonnull ((1, 2, 4)) __attribute__((weak));
392
393 static bool __jau__has_pthread_cond_clockwait() noexcept {
394 const bool r = nullptr != pthread_cond_clockwait;
395 ::fprintf(stderr, "INFO: jau::has_pthread_cond_clockwait: %d\n", r);
396 return r;
397 }
398 static bool jau_has_pthread_cond_clockwait() noexcept {
399 static bool r = __jau__has_pthread_cond_clockwait();
400 return r;
401 }
402#else
403 typedef int32_t os_clockid_t;
404 static int pthread_cond_clockwait (pthread_cond_t * __cond,
405 pthread_mutex_t * __mutex,
406 os_clockid_t __clock_id,
407 const struct timespec * __abstime) {
408 (void)__cond;
409 (void)__mutex;
410 (void)__clock_id;
411 (void)__abstime;
412 return -1;
413 }
414
415 static bool jau_has_pthread_cond_clockwait() noexcept {
416 return false;
417 }
418#endif
419
420std::cv_status jau::wait_until(std::condition_variable& cv, std::unique_lock<std::mutex>& lock, const fraction_timespec& absolute_time, const bool monotonic) noexcept {
421 if( absolute_time <= fraction_tv::zero ) {
422 return std::cv_status::no_timeout;
423 }
424 // typedef struct timespec __gthread_time_t;
425 struct timespec ts = absolute_time.to_timespec();
426
428 pthread_cond_clockwait(cv.native_handle(), lock.mutex()->native_handle(),
429 monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
430 } else {
431 ::pthread_cond_timedwait(cv.native_handle(), lock.mutex()->native_handle(), &ts);
432 }
433
434 const fraction_timespec now = monotonic ? getMonotonicTime() : getWallClockTime();
435 return now < absolute_time ? std::cv_status::no_timeout : std::cv_status::timeout;
436}
437
438std::cv_status jau::wait_for(std::condition_variable& cv, std::unique_lock<std::mutex>& lock, const fraction_timespec& relative_time, const bool monotonic) noexcept {
439 if( relative_time <= fraction_tv::zero ) {
440 return std::cv_status::no_timeout;
441 }
442 const fraction_timespec now = monotonic ? getMonotonicTime() : getWallClockTime();
443 return wait_until(cv, lock, now + relative_time, monotonic);
444}
445
446std::cv_status jau::wait_for(std::condition_variable& cv, std::unique_lock<std::mutex>& lock, const fraction_i64& relative_time, const bool monotonic) noexcept {
447 if( relative_time <= fractions_i64::zero ) {
448 return std::cv_status::no_timeout;
449 }
450 bool overflow = false;
451 const fraction_timespec atime = ( monotonic ? getMonotonicTime() : getWallClockTime() ) + fraction_timespec(relative_time, &overflow);
452 if( overflow ) {
453 return std::cv_status::timeout;
454 } else {
455 return wait_until(cv, lock, atime, monotonic);
456 }
457}
458
459std::string jau::threadName(const std::thread::id id) noexcept {
460 #if 1
461 return "Thread 0x"+jau::to_hexstring( std::hash<std::thread::id>{}(id) );
462 #else
463 std::stringstream ss;
464 ss.setf(std::ios_base::hex | std::ios_base::showbase);
465 ss << "Thread " << id;
466 return ss.str();
467 #endif
468}
469
470jau::ExceptionBase::ExceptionBase(std::string &&type, std::string const& m, const char* file, int line) noexcept // NOLINT(modernize-pass-by-value)
471: msg_( std::move(type) ),
472 backtrace_( jau::get_backtrace(true /* skip_anon_frames */) )
473{
474 msg_.append(" @ ").append(file).append(":").append(std::to_string(line)).append(": ").append(m);
475 what_ = msg_;
476 what_.append("\nNative backtrace:\n");
477 what_.append(backtrace_);
478}
479
480std::string jau::get_string(const uint8_t *buffer, nsize_t const buffer_len, nsize_t const max_len) noexcept {
481 const nsize_t cstr_max_len = std::min(buffer_len, max_len);
482 const size_t cstr_len = ::strnlen(reinterpret_cast<const char*>(buffer), cstr_max_len); // if cstr_len == cstr_max_len then no EOS
483 return std::string(reinterpret_cast<const char*>(buffer), cstr_len);
484}
485
486void jau::trimInPlace(std::string &s) noexcept {
487 s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
488 return !std::isspace(ch);
489 }));
490 s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
491 return !std::isspace(ch);
492 }).base(), s.end());
493}
494
495std::string jau::trim(const std::string &_s) noexcept {
496 std::string s(_s);
497 trimInPlace(s);
498 return s;
499}
500
501std::vector<std::string> jau::split_string(const std::string& str, const std::string& separator) noexcept {
502 std::vector<std::string> res;
503 size_t p0 = 0;
504 while( p0 != std::string::npos && p0 < str.size() ) {
505 size_t p1 = str.find(separator, p0);
506 res.push_back(str.substr(p0, p1)); // incl. npos
507 if( p1 != std::string::npos ) {
508 p1 += separator.length();
509 }
510 p0 = p1;
511 }
512 return res;
513}
514
515std::string& jau::toLowerInPlace(std::string& s) noexcept {
516 std::transform(s.begin(), s.end(), s.begin(),
517 [](unsigned char c){ return std::tolower(c); });
518 return s;
519}
520std::string jau::toLower(const std::string& s) noexcept {
521 std::string t(s); toLowerInPlace(t); return t;
522}
523
524// one static_assert is sufficient for whole compilation unit
525static_assert( is_defined_endian(endian_t::native) );
526static_assert( is_little_or_big_endian() );
527
528uint128dp_t jau::merge_uint128(uint16_t const uuid16, uint128dp_t const & base_uuid, nsize_t const uuid16_le_octet_index)
529{
530 if( uuid16_le_octet_index > 14 ) {
531 std::string msg("uuid16_le_octet_index ");
532 msg.append(std::to_string(uuid16_le_octet_index));
533 msg.append(", not within [0..14]");
535 }
536 uint128dp_t dest = base_uuid;
537
538 // base_uuid: 00000000-0000-1000-8000-00805F9B34FB
539 // uuid16: DCBA
540 // uuid16_le_octet_index: 12
541 // result: 0000DCBA-0000-1000-8000-00805F9B34FB
542 //
543 // LE: low-mem - FB349B5F8000-0080-0010-0000-ABCD0000 - high-mem
544 // ^ index 12
545 // LE: uuid16 -> value.data[12+13]
546 //
547 // BE: low-mem - 0000DCBA-0000-1000-8000-00805F9B34FB - high-mem
548 // ^ index 2
549 // BE: uuid16 -> value.data[2+3]
550 //
551 nsize_t offset;
552 if( is_big_endian() ) {
553 offset = 15 - 1 - uuid16_le_octet_index;
554 } else {
555 offset = uuid16_le_octet_index;
556 }
557 // uint16_t * destu16 = (uint16_t*)(dest.data + offset);
558 // *destu16 += uuid16;
559 reinterpret_cast<packed_t<uint16_t>*>( dest.data + offset )->store += uuid16;
560 return dest;
561}
562
563uint128dp_t jau::merge_uint128(uint32_t const uuid32, uint128dp_t const & base_uuid, nsize_t const uuid32_le_octet_index)
564{
565 if( uuid32_le_octet_index > 12 ) {
566 std::string msg("uuid32_le_octet_index ");
567 msg.append(std::to_string(uuid32_le_octet_index));
568 msg.append(", not within [0..12]");
570 }
571 uint128dp_t dest = base_uuid;
572
573 // base_uuid: 00000000-0000-1000-8000-00805F9B34FB
574 // uuid32: 87654321
575 // uuid32_le_octet_index: 12
576 // result: 87654321-0000-1000-8000-00805F9B34FB
577 //
578 // LE: low-mem - FB349B5F8000-0080-0010-0000-12345678 - high-mem
579 // ^ index 12
580 // LE: uuid32 -> value.data[12..15]
581 //
582 // BE: low-mem - 87654321-0000-1000-8000-00805F9B34FB - high-mem
583 // ^ index 0
584 // BE: uuid32 -> value.data[0..3]
585 //
586 nsize_t offset;;
587 if( is_big_endian() ) {
588 offset = 15 - 3 - uuid32_le_octet_index;
589 } else {
590 offset = uuid32_le_octet_index;
591 }
592 // uint32_t * destu32 = (uint32_t*)(dest.data + offset);
593 // *destu32 += uuid32;
594 reinterpret_cast<packed_t<uint32_t>*>( dest.data + offset )->store += uuid32;
595 return dest;
596}
597
598std::string jau::vformat_string(const char* format, va_list ap) {
599 size_t nchars;
600 std::string str;
601 {
602 const size_t bsz = 1024; // including EOS
603 str.reserve(bsz); // incl. EOS
604 str.resize(bsz-1); // excl. EOS
605
606 nchars = std::vsnprintf(&str[0], bsz, format, ap); // NOLINT(clang-analyzer-valist.Uninitialized): clang-tidy bug
607 if( nchars < bsz ) {
608 str.resize(nchars);
609 str.shrink_to_fit();
610 return str;
611 }
612 }
613 {
614 const size_t bsz = std::min<size_t>(nchars+1, str.max_size()+1); // limit incl. EOS
615 str.reserve(bsz); // incl. EOS
616 str.resize(bsz-1); // excl. EOS
617 nchars = std::vsnprintf(&str[0], bsz, format, ap); // NOLINT(clang-analyzer-valist.Uninitialized): clang-tidy bug
618 str.resize(nchars);
619 return str;
620 }
621}
622
623std::string jau::format_string(const char* format, ...) {
624 va_list args;
625 va_start (args, format);
626 std::string str = vformat_string(format, args);
627 va_end (args);
628 return str;
629}
630
631static snsize_t hexCharByte_(const uint8_t c)
632{
633 if('0' <= c && c <= '9') {
634 return c - '0';
635 }
636 if('A' <= c && c <= 'F') {
637 return c - 'A' + 10;
638 }
639 if('a' <= c && c <= 'f') {
640 return c - 'a' + 10;
641 }
642 return -1;
643}
644
645size_t jau::hexStringBytes(std::vector<uint8_t>& out, const std::string& hexstr, const bool lsbFirst, const bool checkLeading0x) noexcept {
646 return jau::hexStringBytes(out, cast_char_ptr_to_uint8(hexstr.data()), hexstr.size(), lsbFirst, checkLeading0x);
647}
648#include <cassert>
649size_t jau::hexStringBytes(std::vector<uint8_t>& out, const uint8_t hexstr[], const size_t hexstr_len, const bool lsbFirst, const bool checkLeading0x) noexcept {
650 size_t offset;
651 if( checkLeading0x && hexstr_len >= 2 && hexstr[0] == '0' && hexstr[1] == 'x' ) {
652 offset = 2;
653 } else {
654 offset = 0;
655 }
656 size_t lsb, msb;
657 if( lsbFirst ) {
658 lsb = 1; msb = 0;
659 } else {
660 lsb = 0; msb = 1;
661 }
662 const size_t hexlen_in = hexstr_len - offset;
663 const size_t bsize = hexlen_in / 2;
664 out.clear();
665 out.reserve(bsize + hexlen_in % 2);
666
667 // Odd nibbles:
668 // - 0xf12 = 0x0f12 = { 0x12, 0x0f } - msb, 1st single low-nibble is most significant
669 // - 12f = 0xf012 = { 0x12, 0xf0 } - lsb, last single high-nibble is most significant
670 //
671 const bool has_single_nibble = 0 < hexlen_in % 2;
672 uint8_t high_msb_nibble = 0;
673 if( !lsbFirst && has_single_nibble ) {
674 // consume single MSB nibble
675 const size_t idx = 0;
676 assert( hexstr_len - 1 >= offset + idx );
677 const snsize_t l = hexCharByte_( hexstr[ offset + idx ] );
678 if( 0 <= l ) {
679 high_msb_nibble = static_cast<uint8_t>( l );
680 } else {
681 // invalid char
682 return out.size();
683 }
684 ++offset;
685 }
686 size_t i = 0;
687 for (; i < bsize; ++i) {
688 const size_t idx = ( lsb*i + msb*(bsize-1-i) ) * 2;
689 assert( hexstr_len - 1 >= offset + idx + 1 );
690 const snsize_t h = hexCharByte_( hexstr[ offset + idx ] );
691 const snsize_t l = hexCharByte_( hexstr[ offset + idx + 1 ] );
692 if( 0 <= h && 0 <= l ) {
693 out.push_back( static_cast<uint8_t>( (h << 4) + l ) );
694 } else {
695 // invalid char
696 return out.size();
697 }
698 }
699 if( has_single_nibble ) {
700 if( lsbFirst ) {
701 assert( hexstr_len - 1 == offset + i*2 );
702 const snsize_t h = hexCharByte_( hexstr[ offset + i*2 ] );
703 if( 0 <= h ) {
704 out.push_back( static_cast<uint8_t>( (h << 4) + 0 ) );
705 } else {
706 // invalid char
707 return out.size();
708 }
709 } else {
710 out.push_back( high_msb_nibble );
711 }
712 }
713 assert( hexlen_in/2 + hexlen_in%2 == out.size() );
714 return out.size();
715}
716
717uint64_t jau::from_hexstring(std::string const & s, const bool lsbFirst, const bool checkLeading0x) noexcept
718{
719 std::vector<uint8_t> out;
720 hexStringBytes(out, s, lsbFirst, checkLeading0x);
721 if constexpr ( jau::is_little_endian() ) {
722 while( out.size() < sizeof(uint64_t) ) {
723 out.push_back(0);
724 }
725 } else {
726 while( out.size() < sizeof(uint64_t) ) {
727 out.insert(out.cbegin(), 0);
728 }
729 }
730 return *pointer_cast<const uint64_t*>( out.data() );
731}
732
733static const char* HEX_ARRAY_LOW = "0123456789abcdef";
734static const char* HEX_ARRAY_BIG = "0123456789ABCDEF";
735
736std::string jau::bytesHexString(const void* data, const nsize_t length,
737 const bool lsbFirst, const bool lowerCase, const bool skipLeading0x) noexcept
738{
739 const char* hex_array = lowerCase ? HEX_ARRAY_LOW : HEX_ARRAY_BIG;
740 std::string str;
741
742 if( nullptr == data ) {
743 return "null";
744 }
745 if( 0 == length ) {
746 return "nil";
747 }
748 const uint8_t * const bytes = static_cast<const uint8_t*>(data);
749 if( lsbFirst ) {
750 // LSB left -> MSB right, no leading `0x`
751 // TODO: skip tail all-zeros?
752 str.reserve(length * 2 +1);
753 for (nsize_t j = 0; j < length; j++) {
754 const int v = bytes[j] & 0xFF;
755 str.push_back(hex_array[v >> 4]);
756 str.push_back(hex_array[v & 0x0F]);
757 }
758 } else {
759 // MSB left -> LSB right, with leading `0x`
760 if( skipLeading0x ) {
761 str.reserve(length * 2 +1);
762 } else {
763 str.reserve(length * 2 +1 +2);
764 str.push_back('0');
765 str.push_back('x');
766 }
767 bool skip_leading_zeros = true;
768 nsize_t j = length;
769 do {
770 j--;
771 const int v = bytes[j] & 0xFF;
772 if( 0 != v || !skip_leading_zeros || j == 0 ) {
773 str.push_back(hex_array[v >> 4]);
774 str.push_back(hex_array[v & 0x0F]);
775 skip_leading_zeros = false;
776 }
777 } while( j != 0);
778 }
779 return str;
780}
781
782std::string& jau::byteHexString(std::string& dest, const uint8_t value, const bool lowerCase) noexcept
783{
784 const char* hex_array = lowerCase ? HEX_ARRAY_LOW : HEX_ARRAY_BIG;
785
786 if( 2 > dest.capacity() - dest.size() ) { // Until C++20, then reserve is ignored if capacity > reserve
787 dest.reserve(dest.size()+2);
788 }
789 const int v = value & 0xFF;
790 dest.push_back(hex_array[v >> 4]);
791 dest.push_back(hex_array[v & 0x0F]);
792 return dest;
793}
794
795std::string jau::to_string(const endian_t v) noexcept {
796 switch(v) {
797 case endian_t::little: return "little";
798 case endian_t::big: return "big";
799 case endian_t::pdp: return "pdb";
800 case endian_t::honeywell: return "honeywell";
801 case endian_t::undefined: return "undefined";
802 }
803 return "undef";
804}
805
806std::string jau::to_string(const lb_endian_t v) noexcept {
807 switch(v) {
808 case lb_endian_t::little: return "little";
809 case lb_endian_t::big: return "big";
810 }
811 return "undef";
812}
813
814std::string jau::to_string(const jau::func::target_type v) noexcept {
815 switch(v) {
816 case jau::func::target_type::null: return "null";
817 case jau::func::target_type::member: return "member";
818 case jau::func::target_type::free: return "free";
819 case jau::func::target_type::lambda: return "lambda";
820 case jau::func::target_type::ylambda: return "ylambda";
821 case jau::func::target_type::capval: return "capval";
822 case jau::func::target_type::capref: return "capref";
823 case jau::func::target_type::std: return "std";
824 }
825 return "undef";
826}
827
828bool jau::to_integer(long long & result, const char * str, size_t str_len, const char limiter, const char *limiter_pos) {
829 static constexpr const bool _debug = false;
830 char *endptr = nullptr;
831 if( nullptr == limiter_pos ) {
832 limiter_pos = str + str_len;
833 }
834 errno = 0;
835 const long long num = std::strtoll(str, &endptr, 10);
836 if( 0 != errno ) {
837 // value under- or overflow occured
838 if constexpr ( _debug ) {
839 INFO_PRINT("Value under- or overflow occurred, value %lld in: '%s', errno %d %s", num, str, errno, strerror(errno));
840 }
841 return false;
842 }
843 if( nullptr == endptr || endptr == str ) {
844 // no digits consumed
845 if constexpr ( _debug ) {
846 INFO_PRINT("Value no digits consumed @ idx %d, %p == start, in: '%s'", endptr-str, endptr, str);
847 }
848 return false;
849 }
850 if( endptr < limiter_pos ) {
851 while( endptr < limiter_pos && ::isspace(*endptr) ) { // only accept whitespace
852 ++endptr;
853 }
854 }
855 if( *endptr != limiter || endptr != limiter_pos ) {
856 // numerator value not completely valid
857 if constexpr ( _debug ) {
858 INFO_PRINT("Value end not '%c' @ idx %d, %p != %p, in: %p '%s' len %zd", limiter, endptr-str, endptr, limiter_pos, str, str, str_len);
859 }
860 return false;
861 }
862 result = num;
863 return true;
864}
865
866bool jau::to_integer(long long & result, const std::string& str, const char limiter, const char *limiter_pos) {
867 return to_integer(result, str.c_str(), str.size(), limiter, limiter_pos);
868}
869
870bool jau::to_fraction_i64(fraction_i64& result, const std::string & value, const fraction_i64& min_allowed, const fraction_i64& max_allowed) noexcept {
871 static constexpr const bool _debug = false;
872 const char * str = const_cast<const char*>(value.c_str());
873 const size_t str_len = value.length();
874 const char *divptr = nullptr;
875
876 divptr = std::strstr(str, "/");
877 if( nullptr == divptr ) {
878 if constexpr ( _debug ) {
879 INFO_PRINT("Missing '/' in: '%s'", str);
880 }
881 return false;
882 }
883
884 long long num;
885 if( !to_integer(num, str, str_len, '/', divptr) ) {
886 return false;
887 }
888
889 long long denom; // 0x7ffc7090d904 != 0x7ffc7090d907 " 10 / 1000000 "
890 if( !to_integer(denom, divptr+1, str_len-(divptr-str)-1, '\0', str + str_len) ) {
891 return false;
892 }
893
894 fraction_i64 temp((int64_t)num, (uint64_t)denom);
895 if( ! ( min_allowed <= temp && temp <= max_allowed ) ) {
896 // invalid user value range
897 if constexpr ( _debug ) {
898 INFO_PRINT("Numerator out of range, not %s <= %s <= %s, in: '%s'", min_allowed.to_string().c_str(), temp.to_string().c_str(), max_allowed.to_string().c_str(), str);
899 }
900 return false;
901 }
902 result = temp;
903 return true;
904}
905
906std::string jau::math::to_string(const jau::math::math_error_t v) noexcept {
907 switch(v) {
908 case jau::math::math_error_t::none: return "none";
909 case jau::math::math_error_t::invalid: return "invalid";
910 case jau::math::math_error_t::div_by_zero: return "div_by_zero";
911 case jau::math::math_error_t::overflow: return "overflow";
912 case jau::math::math_error_t::underflow: return "underflow";
913 case jau::math::math_error_t::inexact: return "inexact";
914 case jau::math::math_error_t::undefined: return "undefined";
915 }
916 return "undef";
917}
918
919std::string jau::type_info::toString() const noexcept {
920 using namespace jau::enums;
921
922 std::string r("TypeInfo[addr ");
923 r.append(jau::to_hexstring(this))
924 .append(", hash ").append(jau::to_hexstring(hash_code()))
925 .append(", `").append(name())
926 .append("`, ident").append(to_string(m_idflags));
927 r.append("]]");
928 return r;
929}
930
static const char * HEX_ARRAY_BIG
static snsize_t hexCharByte_(const uint8_t c)
int32_t os_clockid_t
static int pthread_cond_clockwait(pthread_cond_t *__cond, pthread_mutex_t *__mutex, os_clockid_t __clock_id, const struct timespec *__abstime)
static bool jau_has_pthread_cond_clockwait() noexcept
static const char * HEX_ARRAY_LOW
#define E_FILE_LINE
ExceptionBase(std::string &&type, std::string const &m, const char *file, int line) noexcept
std::string to_string(const bool show_double=false) const noexcept
Returns a string representation of this fraction.
std::string toString() const noexcept
constexpr size_t hash_code() const noexcept
Returns an unspecified hash code of this instance.
constexpr bool is_little_endian() noexcept
Evaluates true if platform is running in little endian mode, i.e.
constexpr bool is_big_endian() noexcept
Evaluates true if platform is running in big endian mode, i.e.
constexpr bool is_defined_endian(const endian_t &v) noexcept
Evaluates true if the given endian is defined, i.e.
constexpr bool is_little_or_big_endian() noexcept
Evaluates true if platform is running in little or big endian mode, i.e.
endian_t
Endian identifier, indicating endianess of all scalar types.
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
const uint8_t * cast_char_ptr_to_uint8(const char *s) noexcept
@ pdp
Identifier for DEC PDP-11, aka ENDIAN_LITTLE_WORD.
@ undefined
Undetermined endian.
@ native
Identifier for native platform type, one of the above.
@ little
Identifier for little endian.
@ honeywell
Identifier for Honeywell 316, aka ENDIAN_BIG_WORD.
@ big
Identifier for big endian.
@ little
Identifier for little endian, equivalent to endian::little.
@ big
Identifier for big endian, equivalent to endian::big.
constexpr bool value(const Bool rhs) noexcept
constexpr std::enable_if_t< sizeof(Dest)==sizeof(Source) &&std::is_pointer_v< Source > &&std::is_pointer_v< Dest >, Dest > pointer_cast(const Source &src) noexcept
A constexpr pointer cast implementation for C++17, inspired by C++20 bit_cast<>(arg).
#define __attrdef_no_optimize__
constexpr std::string_view name(const Bool v) noexcept
Bool
Boolean type without implicit conversion, safe for function parameter.
bool to_fraction_i64(fraction_i64 &result, const std::string &value, const fraction_i64 &min_allowed, const fraction_i64 &max_allowed) noexcept
Stores the fraction_i64 value of the given string value in format <num>/<denom>, which may contain wh...
fraction_timespec getWallClockTime() noexcept
Returns current wall-clock real-time since Unix Epoch 00:00:00 UTC on 1970-01-01.
fraction_timespec getMonotonicTime() noexcept
Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.
fraction< int64_t > fraction_i64
fraction using int64_t as integral type
target_type
func::target_type identifier for the target function delegate_t<R, A...> object, exposed by jau::func...
@ null
Denotes a func::null_target_t.
@ lambda
Denotes a func::lambda_target_t.
@ capval
Denotes a func::capval_target_t.
@ capref
Denotes a func::capref_target_t.
@ member
Denotes a func::member_target_t.
@ free
Denotes a func::free_target_t.
@ std
Denotes a func::std_target_t.
@ ylambda
Denotes a func::ylambda_target_t.
constexpr nsize_t digits10(const T x, const snsize_t x_sign, const bool sign_is_digit=true) noexcept
Returns the number of decimal digits of the given integral value number using std::log10<T>().
Definition int_math.hpp:403
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition int_types.hpp:55
uint128dp_t merge_uint128(uint16_t const uuid16, uint128dp_t const &base_uuid, nsize_t const uuid16_le_octet_index)
Merge the given 'uuid16' into a 'base_uuid' copy at the given little endian 'uuid16_le_octet_index' p...
int_fast32_t snsize_t
Natural 'ssize_t' alternative using int_fast32_t as its natural sized type.
Definition int_types.hpp:67
math_error_t
Error types as specified by C++ Math Error Handling
std::string to_string(const math_error_t v) noexcept
Returns std::string representation of math_error_t.
@ underflow
See FE_UNDERFLOW, i.e.
@ overflow
See FE_OVERFLOW, i.e.
@ undefined
undefined math error
@ div_by_zero
See FE_DIVBYZERO, i.e.
@ inexact
See FE_INEXACT, i.e.
@ invalid
See FE_INVALID, i.e.
void zero_bytes_sec(void *s, size_t n) noexcept __attrdecl_no_optimize__
Wrapper to ::explicit_bzero(), ::bzero() or ::memset(), whichever is available in that order.
std::string & toLowerInPlace(std::string &s) noexcept
std::string trim(const std::string &s) noexcept
trim copy
std::string vformat_string(const char *format, va_list ap)
Returns a string according to vprintf() formatting rules using va_list instead of a variable number o...
void trimInPlace(std::string &s) noexcept
trim in place
std::string to_hexstring(value_type const &v, const bool skipLeading0x=false) noexcept
Produce a lower-case hexadecimal string representation with leading 0x in MSB of the given pointer.
std::string get_string(const uint8_t *buffer, nsize_t const buffer_len, nsize_t const max_len) noexcept
Returns a C++ String taken from buffer with maximum length of min(max_len, max_len).
uint64_t from_hexstring(std::string const &s, const bool lsbFirst=!jau::is_little_endian(), const bool checkLeading0x=true) noexcept
Converts a given hexadecimal string representation into a uint64_t value according to hexStringBytes(...
std::string & byteHexString(std::string &dest, const uint8_t value, const bool lowerCase) noexcept
Produce a hexadecimal string representation of the given byte value.
bool to_integer(long long &result, const std::string &str, const char limiter='\0', const char *limiter_pos=nullptr)
std::string bytesHexString(const void *data, const nsize_t length, const bool lsbFirst, const bool lowerCase=true, const bool skipLeading0x=false) noexcept
Produce a hexadecimal string representation of the given byte values.
std::vector< std::string > split_string(const std::string &str, const std::string &separator) noexcept
Split given string str at separator into the resulting std::vector excluding the separator sequence .
std::string format_string(const char *format,...)
Returns a string according to printf() formatting rules and variable number of arguments following th...
std::string toLower(const std::string &s) noexcept
size_t hexStringBytes(std::vector< uint8_t > &out, const std::string &hexstr, const bool lsbFirst, const bool checkLeading0x) noexcept
Converts a given hexadecimal string representation into a byte vector.
Author: Sven Gothel sgothel@jausoft.com Copyright Gothel Software e.K.
Definition enum_util.hpp:65
constexpr const jau::fraction_timespec zero(0, 0)
jau::fraction_timespec zero is { 0, 0 }
constexpr const jau::fraction_i64 zero(0l, 1lu)
zero is 0/1
Author: Sven Gothel sgothel@jausoft.com Copyright (c) 2022 Gothel Software e.K.
Definition file_util.hpp:41
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
std::string get_backtrace(const bool skip_anon_frames, const jau::snsize_t max_frames=-1, const jau::snsize_t skip_frames=1) noexcept
Returns a de-mangled backtrace string separated by newline excluding this function.
Definition debug.cpp:94
std::cv_status wait_for(std::condition_variable &cv, std::unique_lock< std::mutex > &lock, const fraction_timespec &relative_time, const bool monotonic=true) noexcept
wait_for causes the current thread to block until the condition variable is notified,...
uint64_t getWallClockSeconds() noexcept
Returns current wall-clock system time of day in seconds since Unix Epoch 00:00:00 UTC on 1 January 1...
std::string threadName(const std::thread::id id) noexcept
void INFO_PRINT(const char *format,...) noexcept
Use for unconditional informal messages, prefix '[elapsed_time] Info: '.
Definition debug.cpp:248
std::cv_status wait_until(std::condition_variable &cv, std::unique_lock< std::mutex > &lock, const fraction_timespec &absolute_time, const bool monotonic=true) noexcept
wait_until causes the current thread to block until the condition variable is notified,...
bool sleep_until(const fraction_timespec &absolute_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_until causes the current thread to block until the specific time is reached.
bool sleep(const fraction_timespec &relative_time, const bool ignore_irq=true) noexcept
sleep using high precision monotonic timer, useful for one-shot delays (only).
bool milli_sleep(uint64_t td_ms, const bool ignore_irq=true) noexcept
millisecond sleep using high precision monotonic timer, useful for one-shot delays (only).
uint64_t getCurrentMilliseconds() noexcept
Returns current monotonic time in milliseconds.
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...
int64_t tv_nsec
Nanoseconds component with its absolute value in range [0..1'000'000'000[ or [0..1'000'000'000).
int64_t tv_sec
Seconds component, with its absolute value in range [0..inf[ or [0..inf).
std::string to_string() const noexcept
Return simple string representation in seconds and nanoseconds.
constexpr fraction_timespec() noexcept
Constructs a zero fraction_timespec instance.
std::string to_iso8601_string(bool space_separator=false, bool muteTime=false) const noexcept
Convenience string conversion interpreted since Unix Epoch in UTC to ISO 8601 YYYY-mm-ddTHH:MM:SS....
static fraction_timespec from(const std::string_view datestr, int64_t &utcOffsetSec, size_t &consumedChars) noexcept
Conversion constructor from an ISO8601 time string, as produced via to_iso8601_string().
Support aligned memory transfer from and to potentially unaligned memory.
A 128-bit packed uint8_t data array.
uint8_t data[16]