gempyre 1.8.6
Loading...
Searching...
No Matches
gempyre_utils.h
Go to the documentation of this file.
1#ifndef UTILS_H
2#define UTILS_H
3
4#include <ctime>
5#include <chrono>
6#include <vector>
7#include <map>
8#include <sstream>
9#include <fstream>
10#include <optional>
11#include <variant>
12#include <functional>
13#include <algorithm>
14#include <future>
15#include <limits>
16#include <iomanip>
17#include <any>
18#include <string_view>
19
33#define GEMPYREUTILSDEBUG(x) GempyreUtils::log(Utils::LogLevel::Debug, x, __FILE__, __LINE__)
36#define gempyre_utils_assert(b) (b || GempyreUtils::do_fatal("Panic!", nullptr, __FILE__, __LINE__))
38#define gempyre_utils_assert_x(b, x) (b || GempyreUtils::do_fatal(x, nullptr, __FILE__, __LINE__))
40#define gempyre_utils_assert_x_f(b, x, f) (b || GempyreUtils::do_fatal(x, f, __FILE__, __LINE__))
42#define gempyre_utils_fatal(x) GempyreUtils::do_fatal(x, nullptr, __FILE__, __LINE__)
44#define gempyre_utils_fatal_f(x, f) GempyreUtils::do_fatal(x, f, __FILE__, __LINE__)
46#define gempyre_utils_auto_clean(p, f) std::unique_ptr<std::remove_pointer<decltype(p)>::type, decltype(&f)> _ ## p (p, &f)
48#define gempyre_utils_auto_close(p, f) GempyreUtils::_Close<std::decay_t<decltype(p)>, decltype(&f)> _ ## p (p, &f)
49
51
52#ifdef WINDOWS_EXPORT
53 #define UTILS_EX __declspec(dllexport)
54#else
55 #define UTILS_EX
56#endif
57
58#ifdef _MSC_VER
59using SSIZE_T = long long;
60#else
61using SSIZE_T = ssize_t;
62#endif
63
64
66
67namespace GempyreUtils {
71enum class LogLevel : int {
72 None,
73 Fatal,
74 Error,
75 Warning,
76 Info,
77 Debug,
79 };
80
82class LogWriter {
83public:
87 virtual ~LogWriter();
88 LogWriter(const GempyreUtils::LogWriter&) = delete;
89 LogWriter& operator=(const GempyreUtils::LogWriter&) = delete;
93 virtual std::string header(LogLevel logLevel);
94
99 virtual bool do_write(const char* buffer, size_t count) = 0;
101 virtual bool has_ansi() const;
102private:
103 LogWriter* m_previousLogWriter{nullptr};
104};
105
107class UTILS_EX FileLogWriter : public LogWriter {
108public:
109 FileLogWriter(std::string_view path);
110protected:
111 bool do_write(const char* buffer, size_t count) override;
112protected:
113 std::ofstream m_file;
114};
115
116class UTILS_EX StreamLogWriter : public LogWriter {
117public:
118 StreamLogWriter(std::ostream& os);
119protected:
120 bool do_write(const char* buffer, size_t count) override;
121protected:
122 std::ostream& m_os;
123};
125
128UTILS_EX void set_log_level(LogLevel level);
129
132UTILS_EX LogLevel log_level();
133
137UTILS_EX std::string to_str(LogLevel log_level);
138
140UTILS_EX std::ostream log_stream(LogLevel logLevel);
141
142template <typename T, typename ...Args>
143inline void log_line(LogLevel level, std::ostream& os, const T& e, Args... args) {
144 os << e << " ";
145 log_line(level, os, args...);
146}
147
148
149UTILS_EX void process_exit(int);
150
151template<typename T>
152inline void log_line(LogLevel level, std::ostream& os, const T& e) {
153 os << e << std::endl;
154 if(level == LogLevel::Fatal) {
155 process_exit(99);
156 }
157}
159
164template <typename T, typename ...Args>
165inline void log(LogLevel level, const T& e, Args... args) {
166 if(level <= log_level()) {
167 auto os = log_stream(level);
168 log_line(level, os, e, args...);
169 }
170}
171
173template <LogLevel level, typename T, typename ...Args>
174inline void write_log(const T& e, Args... args) {
175 log(level, e, args...);
176}
178
180template <typename T, typename ...Args>
181inline void log_debug(const T& e, Args... args) {
182 write_log<LogLevel::Debug, T, Args...>(e, args...);
183}
184
185
187inline bool do_fatal(std::string_view txt, std::function<void()> f, const char* file, int line) {
188 if(f) f();
189 log(LogLevel::Fatal, txt, "at", file, "line:", line);
190 return false;
191}
193
194
195#ifdef _MSC_VER
196#define __PRETTY_FUNCTION__ __FUNCSIG__
197#endif
198
200#define GEM_DEBUG(...) GempyreUtils::log(GempyreUtils::LogLevel::Debug, __PRETTY_FUNCTION__, __VA_ARGS__)
202}
203
204
205
206
210namespace GempyreUtils {
211
213//Helper for C memory management
214template <typename T, typename A>
215class _Close {
216public:
217 _Close(T ref, A&& f) : t(ref), d(f) {}
218 ~_Close() {(void) this->d(this->t);}
219 _Close(_Close&& other) = default;
220 _Close& operator=(_Close&& other) = default;
221 _Close(const _Close& other) = delete;
222 _Close& operator=(const _Close& other) = delete;
223private:
224 T t;
225 A d;
226};
228
229
231UTILS_EX void init();
232UTILS_EX std::string current_time_string();
233UTILS_EX std::string last_error();
235
237template<typename E>
238struct ErrorValue {
239 ErrorValue(E&& e) : err{e} {}
240 ErrorValue(const E& e) : err{e} {}
241 E err;
242 };
244
248// internal for Result
249template <typename E> struct Error {
251 using value_type = E;
253 E error;
254};
256template <typename R, typename E = std::string>
257struct Result : private std::variant<R, Error<E>> {
259 using Err = Error<E>;
262 using value_type = R;
264 using error_type = E;
267 constexpr Result(R&& r) : std::variant<R, Err>{r} {}
270 constexpr Result(Err&& e) : std::variant<R, Err>{e} {} // use makeError
273 constexpr Result(const R& r) : std::variant<R, Err>{r} {}
276 constexpr Result(const Err& e) : std::variant<R,Err>{e} {}
280 constexpr Result& operator=(R&& r) {*this = std::move(r); return *this;}
284 constexpr Result& operator=(Err&& e) {*this = std::move(e); return *this;}
288 constexpr Result& operator=(const R& r) {*this = r; return *this;}
292 constexpr Result& operator=(const Err &e) {*this = e; return *this;}
294 constexpr operator bool() const {return std::get_if<R>(this);}
296 constexpr operator std::optional<R>() const {return has_value() ? std::make_optional<R>(value()) : std::nullopt;}
298 constexpr bool has_value() const {return operator bool();}
300 constexpr const R& value() const {return std::get<R>(*this);}
302 constexpr const E& error() const {return std::get<Err>(*this).error;}
304 constexpr R& value() {return std::get<R>(*this);}
306 constexpr R& operator *() {return std::get<R>(*this);}
308 constexpr const R& operator *() const {return std::get<R>(*this);}
310 constexpr R* operator ->() {return &std::get<R>(*this);}
312 constexpr const R* operator ->() const {return &std::get<R>(*this);}
316 constexpr static auto make_error(const E& e) {return Result<R, E>{Error<E>{e}};}
320 constexpr static auto make_error(E&& e) {return Result<R, E>{Error<E>{e}};}
323 constexpr static auto make_error() {return Result<R, E>{Error<E>{}};}
326 constexpr static auto ok() {return Result<R, E>{R{}};}
327};
328
330template <typename R, typename E>
331constexpr inline bool operator==(const Result<R, E>& a, const Result<R, E>& b) {return Result<R, E>::ParentType::operator==(a, b);}
333template <typename R, typename E>
334constexpr inline bool operator!=(const Result<R, E>& a, const Result<R, E>& b) {return !operator==(a, b);}
335
337using ResultTrue = Result<std::true_type, std::string>;
338
344template<typename T, typename... A>
345Result<T, std::string> make_error(A&&... a) {
346 std::stringstream str;
347 (str << ... << a); //str << ... << a;
348 return Result<T, std::string>::make_error(str.str());
349}
350
358UTILS_EX std::string qq(std::string_view s);
359
363UTILS_EX std::string chop(std::string_view s);
364
369UTILS_EX std::string chop(std::string_view s, std::string_view chopped);
370
376UTILS_EX std::string substitute(std::string_view str, std::string_view substring, std::string_view substitution);
377
381UTILS_EX std::string remove_spaces(std::string_view str);
382
384template <typename T>
385T convert(std::string_view source) {
386 std::istringstream ss(std::string{source});
387 typename std::remove_const<T>::type v{};
388 ss.operator>>(v); //overloads have similar conversions MSVC19
389 return v;
390}
391
396inline
397std::string_view right(std::string_view str, size_t p) {
398 return str.substr(str.length() - p);
399}
400
405inline
406std::string_view chomp(std::string_view str, size_t p) {
407 return str.substr(0, str.length() - p);
408}
409
410
411template <>
412inline std::string convert<std::string>(std::string_view source)
413{
414 return std::string{source};
415}
417
423template <typename T>
424std::optional<T> parse(std::string_view source, const std::optional<int>& forced_base = std::nullopt) {
425 if (source.empty())
426 return std::nullopt;
427 std::stringstream ss;
428 if (forced_base) {
429 ss << std::setbase(*forced_base) << source;
430 } else {
431 auto base = std::dec;
432 if (source.size() > 1 && source[0] == '0') {
433 if (source.size() > 2 && (source[1] == 'x' || source[1] == 'X')) {
434 base = std::hex;
435 } else {
436 base = std::oct;
437 }
438 }
439 ss << base << source;
440 }
441 T v;
442 /*static_cast<std::istream&>(ss)*/
443 ss >> v; //MSVC said it would be otherwise ambiguous
444 return !ss.fail() && (!forced_base || ss.eof()) ? std::make_optional(v) : std::nullopt;
445}
446
453template <typename T>
454T parse_or(std::string_view source, const T& default_value, const std::optional<int>& forced_base = std::nullopt) {
455 const auto value = parse<T>(source, forced_base);
456 return value ? value.value() : default_value;
457}
458
462template <class T>
463std::string to_low(const T& str) {
464 std::string n;
465 std::transform(std::begin(str), std::end(str), std::back_inserter(n),
466 [](auto c){return std::tolower(c);});
467 return n;
468}
469
470
474template <class T>
475std::string to_upper(const T& str) {
476 std::string n;
477 std::transform(std::begin(str), std::end(str), std::back_inserter(n),
478 [](auto c){return std::toupper(c);});
479 return n;
480}
481
482
486inline std::string_view ltrim(std::string_view str) {
487 const auto begin = std::find_if(str.begin(), str.end(), [](auto ch) {
488 return (ch > ' ');
489 });
490 return str.substr(static_cast<std::string_view::size_type>(
491 std::distance(str.begin(), begin)));
492}
493
497inline std::string_view rtrim(std::string_view str) {
498 const auto end = std::find_if(str.rbegin(), str.rend(), [](auto ch) {
499 return (ch > ' ');
500 });
501 return str.substr(0, static_cast<std::string_view::size_type>(
502 std::distance(end, str.rend())));
503}
504
508inline std::string_view trim(std::string_view str) {
509 return ltrim(rtrim(str));
510}
511
512
513
517 template< typename T >
518 std::string to_hex(T ival) {
519 std::stringstream stream;
520 stream << std::setfill('0') << std::setw(sizeof(T) * 2)
521 << std::hex << ival;
522 return stream.str();
523 }
524
525
530UTILS_EX int levenshtein_distance(std::string_view s1, std::string_view s2);
531
535UTILS_EX bool is_valid_utf8(std::string_view str);
536
541inline bool iequals(std::string_view a, std::string_view b) {
542 return
543 std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b), [](auto aa, auto bb) {
544 return std::tolower(aa) == std::tolower(bb);
545 });
546}
547
553template<typename C, typename T>
554std::optional<T> at(const C& container, std::string_view s, unsigned index = 0) {
555 const auto range = container.equal_range(s);
556 const auto it = std::next(range.first, index);
557 return (std::distance(range.first, it) < std::distance(range.first, range.second)) ?
558 std::make_optional(it->second) : std::nullopt;
559}
560
561template<typename C, typename T>
562T at_or(const C& container, std::string_view s, const T& defaultValue, unsigned index = 0) {
563 const auto v = at<C, T>(container, s, index);
564 return v.has_value() ? *v : defaultValue;
565}
567
573template <class Container = std::vector<std::string>>
574Container split(std::string_view str, const char splitChar = ' ') {
575 Container con;
576 std::istringstream iss(std::string{str});
577 for(std::string token; iss.good() && std::getline(iss, token, splitChar);) {
578 con.insert(con.end(), convert<typename Container::value_type>(token));
579 }
580 return con;
581}
582
584template <typename IT>
585inline constexpr std::string_view make_string_view(IT begin, IT end)
586{
587 return (begin == end) ? std::string_view{} : std::string_view{&*begin, std::distance(begin, end)};
588}
590
596template <class T, typename K = typename T::key_type>
597std::vector<K> keys(const T& map) {
598 std::vector<K> ks; ks.resize(map.size());
599 std::transform(map.begin(), map.end(), ks.begin(), [](const auto& p) {return p.first;});
600 return ks;
601}
602
604 template<typename V>
605 struct DefaultJoiner {
606 auto operator()(const V& v) const {return v;}
607 };
609
611template <class IT, typename In, typename Out>
612[[deprecated("See join with Callable")]] std::string join(const IT& begin,
613 const IT& end,
614 std::string_view joinChar = "",
615 const std::function<Out (const In&)>& f = [](const In& k)->Out{return k;}) {
616 std::string s;
617 std::ostringstream iss(s);
618 if(begin != end) {
619 for(auto it = begin;;) {
620 iss << f(*it);
621 if(!(++it != end)) break;
622 if(!joinChar.empty())
623 iss << joinChar;
624 }
625 }
626 return iss.str();
627}
628
629template <class T, typename In, typename Out>
630[[deprecated("See join with Callable")]] std::string join(const T& t,
631 std::string_view joinChar = "",
632 const std::function<Out (const In&)>& f = [](const In& v)->Out{return v;}) {
633 return join(t.begin(), t.end(), joinChar, f);
634}
635
636template <class IT, typename In, typename Out, typename = std::enable_if_t<std::is_pointer<IT>::value>>
637[[deprecated("See join with Callable")]] std::string join(const IT begin,
638 const IT end,
639 std::string_view joinChar = "",
640 const std::function<Out (const In&)>& f = [](const In& k)->Out{return k;}) {
641 std::string s;
642 std::ostringstream iss(s);
643 if(begin != end) {
644 for(auto it = begin;;) {
645 iss << f(*it);
646 if(!(++it != end)) break;
647 if(!joinChar.empty())
648 iss << joinChar;
649 }
650 }
651 return iss.str();
652}
653
655
664template <typename IT, typename Callable = DefaultJoiner<typename IT::value_type>,
665 typename = std::enable_if_t<!std::is_pointer<IT>::value>>
666std::string join(const IT& begin,
667 const IT& end,
668 std::string_view joinChar = "",
669 const Callable& f = Callable{}) {
670 std::string s;
671 std::ostringstream iss(s);
672 if(begin != end) {
673 for(auto it = begin;;) {
674 iss << f(*it);
675 if(!(++it != end)) break;
676 if(!joinChar.empty())
677 iss << joinChar;
678 }
679 }
680 return iss.str();
681}
682
691template <typename IT, typename Callable = DefaultJoiner<typename std::remove_pointer<IT>::type>,
692 typename = std::enable_if_t<std::is_pointer<IT>::value>>
693std::string join(const IT begin,
694 const IT end,
695 std::string_view joinChar = "",
696 const Callable& f = Callable{}) {
697 std::string s;
698 std::ostringstream iss(s);
699 if(begin != end) {
700 for(auto it = begin;;) {
701 iss << f(*it);
702 if(!(++it != end)) break;
703 if(!joinChar.empty())
704 iss << joinChar;
705 }
706 }
707 return iss.str();
708}
709
717template <typename T, typename Callable = DefaultJoiner<typename T::value_type>>
718std::string join(const T& t,
719 std::string_view joinChar = "",
720 const Callable& f = Callable{}) {
721 return join(std::begin(t), std::end(t), joinChar, f);
722}
723
725template <typename T>
726T merge(const T& b1, const T& b2) {
727 T bytes(b1.size() + b2.size());
728 auto begin = bytes.begin();
729 std::copy(b1.begin(), b1.end(), begin);
730 std::advance(begin, std::distance(b1.begin(), b1.end()));
731 std::copy(b2.begin(), b2.end(), begin);
732 return bytes;
733 }
734
735// I just wonder why copy instead of move hence not public
736template <typename T, typename ...Arg>
737T merge(const T& b1, const T& b2, Arg ...args) {
738 T bytes(b1.size() + b2.size());
739 auto begin = bytes.begin();
740 std::copy(b1.begin(), b1.end(), begin);
741 std::advance(begin, std::distance(b1.begin(), b1.end()));
742 std::copy(b2.begin(), b2.end(), begin);
743 return merge(bytes, args...);
744}
746
748template <typename IT> IT advanced(IT it, int distance) {
749 std::advance(it, distance);
750 return it;
751}
752
753template <typename K, typename V >
755std::optional<V> get_value(const std::multimap<K, V>& map, const K& key, int index = 0)
756{
757 const auto range = map.equal_range(key);
758 return std::distance(range.first, range.second) > index ?
759 std::make_optional((advanced(range.first, index))->second) : std::nullopt;
760}
761
762
763 /*
764 * Misc Utils
765 */
766
768
769class expiror;
770[[nodiscard]]
771UTILS_EX std::shared_ptr<expiror> wait_expire(std::chrono::seconds s, const std::function<void ()>& onExpire);
772class expiror {
773public:
774 ~expiror() {m_f.wait();}
775private:
776 expiror() = default;
777 expiror(std::future<void>&& f) : m_f(std::move(f)) {}
778 std::future<void> m_f{};
779 friend std::shared_ptr<GempyreUtils::expiror> GempyreUtils::wait_expire(std::chrono::seconds s, const std::function<void ()>& onExpire);
780};
781
783
788UTILS_EX std::string hexify(std::string_view src, std::string_view pat);
789
793UTILS_EX std::string unhexify(std::string_view src);
794
796enum class OS {OtherOs, MacOs, WinOs, LinuxOs, AndroidOs, RaspberryOs};
797
799UTILS_EX OS current_os();
800
802UTILS_EX std::string html_file_launch_cmd();
804
805
807enum AddressType : unsigned {Ipv4 = 0x1, Ipv6 = 0x2};
811UTILS_EX std::vector<std::string> ip_addresses(unsigned addressType);
812
813
818enum class PathStyle {Native, Unix, Win};
819
821UTILS_EX std::string get_link(std::string_view fname);
823UTILS_EX bool is_dir(std::string_view fname);
825UTILS_EX std::string working_dir();
827UTILS_EX std::string home_dir();
829UTILS_EX std::string root_dir();
831UTILS_EX std::string abs_path(std::string_view rpath);
837UTILS_EX std::string path_pop(std::string_view filename, int steps = 1, PathStyle path_style = PathStyle::Native);
839UTILS_EX std::vector<std::string> entries(std::string_view dirname);
840
842[[deprecated("use entries")]]
843inline std::vector<std::string> directory(std::string_view dirname) {return entries(dirname);}
845
850UTILS_EX std::optional<std::string> read_process(std::string_view processName, const std::vector<std::string>& params);
852UTILS_EX std::string base_name(std::string_view filename, PathStyle path_style = PathStyle::Native);
854UTILS_EX std::tuple<std::string, std::string> split_name(std::string_view filename, PathStyle path_style = PathStyle::Native);
856UTILS_EX std::string temp_name();
858UTILS_EX std::string host_name();
860UTILS_EX std::optional<std::string> system_env(std::string_view env);
862UTILS_EX bool is_hidden_entry(std::string_view filename);
864UTILS_EX bool is_executable(std::string_view filename);
866UTILS_EX SSIZE_T file_size(std::string_view filename);
868UTILS_EX bool rename(std::string_view of, std::string_view nf);
870UTILS_EX void remove_file(std::string_view filename);
872UTILS_EX bool file_exists(std::string_view filename);
874UTILS_EX std::optional<std::string> which(std::string_view filename);
876UTILS_EX std::string push_path(std::string_view path, std::string_view name);
878template<class ...NAME>
879std::string push_path(std::string_view path, std::string_view name, NAME...names) {
880 return push_path(push_path(path, name), names...);
881}
882
884UTILS_EX int execute(std::string_view prog, const std::vector<std::string_view>& parameters);
885
887template<class ...PARAM>
888UTILS_EX int execute(std::string_view prog, PARAM...parameters) {
889 std::vector<std::string_view> parameter_list{parameters...};
890 return execute(prog, parameter_list);
891}
892
893
894
895
900template <class T>
901std::string write_to_temp(const T& data) {
902 const auto name = GempyreUtils::temp_name();
903 std::ofstream out(name, std::ios::out | std::ios::binary);
904 std::ostreambuf_iterator<typename T::value_type> iter(out);
905 std::copy(data.begin(), data.end(), iter);
906 return name;
907}
908
914template <class T>
915std::vector<T> slurp(std::string_view file, const size_t max = std::numeric_limits<size_t>::max()) {
916 std::vector<T> vec;
918 std::ifstream stream(std::string{file}, std::ios::in | std::ios::binary | std::ios::ate);
919 if(!stream.is_open()) {
920 log(LogLevel::Error, "Cannot open file", qq(file));
921 return vec;
922 }
923 const auto size = std::min(max, static_cast<size_t>(stream.tellg()));
924 if(size <= 0) {
925 return vec;
926 }
927 vec.resize(size / sizeof (T), 0);
928 stream.seekg(std::ios_base::beg);
929 auto ptr = reinterpret_cast<char*>(vec.data());
930 stream.read(ptr, static_cast<std::streamsize>(size));
931 return vec;
932 }
933
936UTILS_EX std::string slurp(std::string_view file, const size_t max = std::numeric_limits<size_t>::max());
937
939enum class JsonMode {Compact, Pretty};
942// or container type std::vector, std::unordered_map or std::map containing other values.
946UTILS_EX Result<std::string> to_json_string(const std::any& any, JsonMode mode = JsonMode::Compact);
947
949enum class MapType {Map, UnorderedMap};
954UTILS_EX Result<std::any> json_to_any(std::string_view str, MapType map_type = MapType::UnorderedMap);
955
957using JsonType = std::variant<
958int,
959double,
960bool,
961std::string,
962std::nullptr_t,
963std::vector<std::any>,
964std::map<std::string, std::any>,
965std::unordered_map<std::string, std::any>
966>;
974UTILS_EX ResultTrue set_json_value(std::any& any, std::string_view path, JsonType&& value);
975
980UTILS_EX ResultTrue remove_json_value(std::any& any, std::string_view path);
981
986UTILS_EX Result<JsonType> get_json_value(const std::any& any, std::string_view path);
987
993UTILS_EX ResultTrue make_json_path(std::any& any, std::string_view path,
994 const std::function<JsonType (std::string_view, std::string_view)>& f = [](auto, auto name) {
995 return (GempyreUtils::parse<int>(name)) ?
996 GempyreUtils::JsonType{std::vector<std::any>{}} :
997 GempyreUtils::JsonType{std::unordered_map<std::string, std::any>{}};});
998
1000UTILS_EX bool is_available(int port);
1001
1003UTILS_EX std::string base64_encode(const unsigned char* bytes, size_t sz);
1005UTILS_EX std::string base64_encode(const std::vector<uint8_t> & vec);
1007UTILS_EX std::string base64_encode(std::string_view str);
1009UTILS_EX std::vector<uint8_t> base64_decode(std::string_view data);
1010
1011
1013enum class ArgType{
1014 NO_ARG,
1015 REQ_ARG,
1016 OPT_ARG
1017 };
1018
1020using ParamList = std::vector<std::string>;
1021
1023using Options = std::multimap<std::string, std::string>;
1024
1026using Params = std::tuple<ParamList, Options>;
1027
1033UTILS_EX Params parse_args(int argc, char* argv[], const std::initializer_list<std::tuple<std::string, char, ArgType>>& args);
1034
1041template <typename T>
1042T option_or(const Options& opts, std::string_view key, const T& default_value) {
1043 const auto it = opts.find(std::string{key});
1044 if(it == opts.end())
1045 return default_value;
1046 const auto parsed = parse<T>(it->second);
1047 return parsed ? parsed.value() : default_value;
1048}
1049
1050
1051}
1052
1053
1054
1055#endif // UTILS_H
Parent class for LogWriters.
Definition gempyre_utils.h:82
virtual bool do_write(const char *buffer, size_t count)=0
Implement write to the medium.
virtual std::string header(LogLevel logLevel)
header of class, called before every line, default just returns a timestamp and loglevel string.
LogWriter()
Constructor.
virtual ~LogWriter()
Destructor.
virtual bool has_ansi() const
override to return true if this write supports ANSI colors, default just return false
UTILS_EX std::string to_str(LogLevel log_level)
Log Level to string.
UTILS_EX LogLevel log_level()
Get current log level.
void log_debug(const T &e, Args... args)
Write a debug log.
Definition gempyre_utils.h:181
void log(LogLevel level, const T &e, Args... args)
Write a log line.
Definition gempyre_utils.h:165
UTILS_EX void set_log_level(LogLevel level)
Set current log level.
LogLevel
The LogLevel enum.
Definition gempyre_utils.h:71
@ Warning
Something is wrong, Default.
@ Info
At least developer should be worried.
@ Debug_Trace
What is going on.
@ Fatal
All logs disabled.
@ Error
Execution ends here.
@ Debug
Something developer should know.