From 9c6722f99a69f038880bac0a3af4051aaaa15f55 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 11 Sep 2023 15:29:44 -0400 Subject: [PATCH 001/170] README v0 --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..829204dd --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# nestlog From 8a1f29a44b133c30c72a11f2a796d5ad10cad7f1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 11 Sep 2023 16:09:26 -0400 Subject: [PATCH 002/170] initial implementation + example + cmake "build" --- CMakeLists.txt | 7 + example/CMakeLists.txt | 21 +++ example/ex1/CMakeLists.txt | 3 + example/ex1/ex1.cpp | 14 ++ include/nestlog/array.hpp | 25 ++++ include/nestlog/fixed.hpp | 45 ++++++ include/nestlog/log_state.hpp | 227 ++++++++++++++++++++++++++++ include/nestlog/log_streambuf.hpp | 122 +++++++++++++++ include/nestlog/pad.hpp | 41 ++++++ include/nestlog/printer.hpp | 28 ++++ include/nestlog/quoted.hpp | 147 +++++++++++++++++++ include/nestlog/scope.hpp | 236 ++++++++++++++++++++++++++++++ include/nestlog/tag.hpp | 87 +++++++++++ include/nestlog/tostr.hpp | 99 +++++++++++++ include/nestlog/vector.hpp | 28 ++++ 15 files changed, 1130 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 example/CMakeLists.txt create mode 100644 example/ex1/CMakeLists.txt create mode 100644 example/ex1/ex1.cpp create mode 100644 include/nestlog/array.hpp create mode 100644 include/nestlog/fixed.hpp create mode 100644 include/nestlog/log_state.hpp create mode 100644 include/nestlog/log_streambuf.hpp create mode 100644 include/nestlog/pad.hpp create mode 100644 include/nestlog/printer.hpp create mode 100644 include/nestlog/quoted.hpp create mode 100644 include/nestlog/scope.hpp create mode 100644 include/nestlog/tag.hpp create mode 100644 include/nestlog/tostr.hpp create mode 100644 include/nestlog/vector.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..b2a41b6f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.10) + +project(nestlog VERSION 0.1) +enable_language(CXX) +enable_testing() + +add_subdirectory(example) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 00000000..ac2655ae --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,21 @@ +set(PROJECT_CXX_FLAGS "--std=c++20") + +add_definitions(${PROJECT_CXX_FLAGS}) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") + +#include(cmake/FindSphinx.cmake) + +add_subdirectory(ex1) + +# ---------------------------------------------------------------- +# make standard directories for std:: includes explicit +# so that +# (1) they appear in compile_commands.json. +# (2) clangd (run from emacs lsp-mode) can find them +# +if(CMAKE_EXPORT_COMPILE_COMMANDS) + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES + ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) +endif() diff --git a/example/ex1/CMakeLists.txt b/example/ex1/CMakeLists.txt new file mode 100644 index 00000000..ce8d9a5e --- /dev/null +++ b/example/ex1/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(ex1 ex1.cpp) + +target_include_directories(ex1 PUBLIC ${PROJECT_SOURCE_DIR}/include) diff --git a/example/ex1/ex1.cpp b/example/ex1/ex1.cpp new file mode 100644 index 00000000..60922607 --- /dev/null +++ b/example/ex1/ex1.cpp @@ -0,0 +1,14 @@ +#include "nestlog/scope.hpp" + +using namespace xo; + +void A(int x) { + XO_SCOPE(log); + + log("x:", x); +} + +int +main(int argc, char ** argv) { + A(66); +} diff --git a/include/nestlog/array.hpp b/include/nestlog/array.hpp new file mode 100644 index 00000000..03b265e9 --- /dev/null +++ b/include/nestlog/array.hpp @@ -0,0 +1,25 @@ +/* @file array.hpp */ + +#pragma once + +#include +#include + +namespace std { + template + inline std::ostream & + operator<<(std::ostream & os, + std::array const & v) + { + os << "["; + for(size_t i = 0; i < N; ++i) { + if(i > 0) + os << " "; + os << v[i]; + } + os << "]"; + return os; + } /*operator<<*/ +} /*namespace std*/ + +/* end array.hpp */ diff --git a/include/nestlog/fixed.hpp b/include/nestlog/fixed.hpp new file mode 100644 index 00000000..bf1a5526 --- /dev/null +++ b/include/nestlog/fixed.hpp @@ -0,0 +1,45 @@ +/* @file fixed.hpp */ + +#pragma once + +#include + +namespace xo { + /* use: + * ostream os = ...; + * + * os << fixed(3.1415926, 3) + * + * writes + * 3.142 + * + * on os, restoring stream's formatting+precision state + */ + class fixed { + public: + fixed(double x, uint16_t prec) : x_{x}, prec_{prec} {} + + /* print this value */ + double x_; + /* precision */ + uint16_t prec_ = 0; + }; /*fixed*/ + + inline std::ostream & + operator<<(std::ostream & s, fixed const & fx) + { + std::ios::fmtflags orig_flags = s.flags(); + std::streamsize orig_p = s.precision(); + + s.flags(std::ios::fixed); + s.precision(fx.prec_); + s << fx.x_; + + s.flags(orig_flags); + s.precision(orig_p); + + return s; + } /*operator<<*/ +} /*namespace xo*/ + +/* end fixed.hpp */ diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp new file mode 100644 index 00000000..41556b8a --- /dev/null +++ b/include/nestlog/log_state.hpp @@ -0,0 +1,227 @@ +/* @file log_state.hpp */ + +#pragma once + +#include "log_streambuf.hpp" +#include +#include // for std::unique_ptr + +namespace xo { + // track per-thread state associated with nesting logger + // + template + class state_impl { + public: + using log_streambuf_type = log_streambuf>; + + public: + state_impl(); + + std::uint32_t nesting_level() const { return nesting_level_; } + + void incr_nesting() { ++nesting_level_; } + void decr_nesting() { --nesting_level_; } + + std::ostream & ss() { return ss_; } + + /* call on entry to new scope */ + void preamble(std::string_view name1, std::string_view name2); + /* call before each new log entry */ + void indent(char pad_char); + /* call on exit from scope */ + void postamble(std::string_view name1, std::string_view name2); + + /* write collected output to *p_sbuf */ + void flush2sbuf(std::streambuf * p_sbuf); + + /* discard output, reset write pointer to beginning of buffer */ + void reset_stream() { + p_sbuf_phase1_->reset_stream(); + p_sbuf_phase2_->reset_stream(); + } + + private: + /* common implementation for .preamble(), .postamble() */ + void entryexit_aux(std::string_view name1, + std::string_view name2, + char label_char); + + private: + /* current nesting level for this thread */ + uint32_t nesting_level_ = 0; + + /* buffer space for logging + * (before pretty-printing for scope::log() calls that span multiple lines) + * reused across tos() and scope::log() calls + */ + std::unique_ptr p_sbuf_phase1_; + + /* buffer space for handling scope::log() calls that span multiple lines; + * inserts extra characters in effort to indent gracefully + */ + std::unique_ptr p_sbuf_phase2_; + + /* output stream -- always attached to .p_sbuf_phase1 + * stream inserters for application datatypes will target this stream + */ + std::ostream ss_; + }; /*state_impl*/ + + constexpr uint32_t c_default_buf_size = 1024; + + template + state_impl::state_impl() + : p_sbuf_phase1_(new log_streambuf_type(c_default_buf_size)), + p_sbuf_phase2_(new log_streambuf_type(c_default_buf_size)), + ss_(p_sbuf_phase1_.get()) + { + assert(p_sbuf_phase1_.get() == ss_.rdbuf()); + } /*ctor*/ + + template + void + state_impl::indent(char pad_char) + { + //log_streambuf * sbuf = this->p_sbuf_phase1_.get(); + +#ifdef NOT_IN_USE + { + char buf[80]; + ::snprintf(buf, sizeof(buf), "[%02d] ", this->nesting_level_); + + this->ss_ << buf; + //this->p_sbuf_->sputn(buf, strlen(buf)); + } +#endif + + /* indent to nesting level */ + for(uint32_t i = 0, n = this->nesting_level_; iss_ << pad_char; + } + } /*indent*/ + + template + void + state_impl::entryexit_aux(std::string_view name1, + std::string_view name2, + char label_char) + { + log_streambuf_type * sbuf = this->p_sbuf_phase1_.get(); + + sbuf->reset_stream(); + this->indent(' '); + + /* mnemonic for scope entry/exit */ + this->ss_ << label_char; + + /* scope name */ + this->ss_ << name1 << name2 << "\n"; + } /*entryexit_aux*/ + + template + void + state_impl::preamble(std::string_view name1, + std::string_view name2) + { + this->entryexit_aux(name1, name2, '+' /*label_char*/); + } /*preamble*/ + + template + void + state_impl::postamble(std::string_view name1, + std::string_view name2) + { + this->entryexit_aux(name1, name2, '-' /*label_char*/); + } /*postamble*/ + + template + void + state_impl::flush2sbuf(std::streambuf * p_sbuf) + { + log_streambuf_type * sbuf1 = this->p_sbuf_phase1_.get(); + log_streambuf_type * sbuf2 = this->p_sbuf_phase2_.get(); + + /* expecting sbuf to contain one line of output. + * if it contains multiple newlines, need to indent + * after each one. + * + * will scan output in *sbuf1, post-process to *sbuf2, + * then write *sbuf2 to clog + */ + char const * s = sbuf1->lo(); + char const * e = s + sbuf1->pos(); + + char const * p = s; + + /* point to first space following a non-space character. + * will indent to just after this space + */ + char const * space_after_nonspace = nullptr; + + while(true) { + bool have_nonspace = false; + + /* invariant: s<=p<=e */ + + /* for indenting, looking for first 'space following non-space, on first line', if any */ + + while(p < e) { + if(space_after_nonspace) { + ; + } else { + if(*p != ' ') + have_nonspace = true; + + if(have_nonspace && (*p == ' ')) { + space_after_nonspace = p; + } + } + + if(*p == '\n') { + ++p; + break; + } else { + ++p; + } + } + + /* p=e or *p=\n */ + + /* charseq [s,p) does not contain any newlines, print it */ + sbuf2->sputn(s, p - s); + + if(p == e) { + break; + } + + // { + // char buf[80]; + // snprintf(buf, sizeof(buf), "*** indent=[%d] next=[%c]", this->nesting_level_, *(p+1)); + // + // std::clog.rdbuf()->sputn(buf, strlen(buf)); + //} + + /* at least 1 char following newline, need to indent for it + * - minimum indent = nesting level; + * - however if space_after_nonspace defined, indent to that + */ + uint32_t n_indent = this->nesting_level_; + + if(space_after_nonspace) + n_indent += (space_after_nonspace - s); + + for(uint32_t i = 0; i < n_indent; ++i) + sbuf2->sputc(' '); + + s = p; + } + + /* now write entire contents of *sbuf2 to clog */ + p_sbuf->sputn(sbuf2->lo(), sbuf2->pos()); + + /* reset streams for next message */ + this->reset_stream(); + } /*flush2sbuf*/ +} /*namespace xo*/ + +/* end log_state.hpp */ diff --git a/include/nestlog/log_streambuf.hpp b/include/nestlog/log_streambuf.hpp new file mode 100644 index 00000000..5d06dab7 --- /dev/null +++ b/include/nestlog/log_streambuf.hpp @@ -0,0 +1,122 @@ +/* @file log_streambuf.hpp */ + +#pragma once + +#include +#include +#include // e.g. for std::memcpy() +#include // e.g. for std::memcpy() + +namespace xo { + /* recycling buffer for logging. + * write to self-extending storage array; + */ + template + class log_streambuf : public std::streambuf { + public: + log_streambuf(std::uint32_t buf_z) { + this->buf_v_.resize(buf_z); + this->reset_stream(); + } /*ctor*/ + + std::streamsize capacity() const { return this->buf_v_.size(); } + char const * lo() const { return this->pbase(); } + char const * hi() const { return this->lo() + this->capacity(); } + std::uint32_t pos() const { return this->pptr() - this->pbase(); } + + void reset_stream() { + char * p_lo = &(this->buf_v_[0]); + char * p_hi = p_lo + this->capacity(); + + /* tells parent our buffer extent */ + this->setp(p_lo, p_hi); + } /*reset_stream*/ + + protected: + virtual std::streamsize + xsputn(char const * s, std::streamsize n) override { + /* s must be an address in [this->lo() .. this->lo() + capacity()] */ + + assert(this->hi() >= this->pptr()); + +#ifdef NOT_USING_DEBUG + std::cout << "xsputn: pbase=" << (void *)(this->pbase()) + << ", pptr=" << (void*)(this->pptr()) + << "(+" << (this->pptr() - this->lo()) << ")" + << ", n=" << n << " -> (+" << (this->pptr() + n - this->lo()) << ")" + << ", buf_v.size=" << this->buf_v_.size() + << std::endl; +#endif + //std::cout << "xsputn: s=" << quoted(string_view(s, n)) << ", n=" << n << std::endl; + + if (this->pptr() + n > this->hi()) { + n = this->hi() - this->pptr(); + std::memcpy(this->pptr(), s, n); + } else { + std::memcpy(this->pptr(), s, n); + } + this->pbump(n); + + return n; + } /*xsputn*/ + + virtual int_type + overflow(int_type new_ch) override + { + char * old_pptr = this->pptr(); + std::streamsize old_n = old_pptr - this->pbase(); + + assert(old_n <= static_cast(this->buf_v_.size())); + + std::size_t new_z = 2 * this->buf_v_.size(); + + this->buf_v_.resize(new_z); + this->buf_v_[old_n] = new_ch; + + /* 'buffered range' will now be .buf_v[old_n .. new_z] */ + char * p_base = &(this->buf_v_[0]); + //char * p_lo = &(this->buf_v_[old_n+1]); + char * p_hi = p_base + this->buf_v_.capacity(); + + this->setp(p_base, p_hi); + this->pbump(old_n + 1); + + return new_ch; + } /*overflow*/ + + /* off. offset, relative to starting point dir. + * dir. + * which. in|out|both + */ + virtual pos_type seekoff(off_type off, + std::ios_base::seekdir dir, + std::ios_base::openmode which) override { + //std::cout << "seekoff: off=" << off << ", dir=" << dir << ", which=" << which << std::endl; + + // Only output stream is supported + if (which != std::ios_base::out) + throw std::runtime_error("log_streambuf: only output mode supported"); + + if (dir == std::ios_base::cur) { + this->pbump(off); + } else if (dir == std::ios_base::end) { + /* .setp(): using for side effect: sets .pptr to .pbase */ + this->setp(this->pbase(), this->epptr()); + this->pbump(off); + } else if (dir == std::ios_base::beg) { + /* .setp(): using for side effect: sets .pptr to .pbase */ + this->setp(this->pbase(), this->epptr()); + this->pbump(this->capacity() + off); + } + + return this->pptr() - this->pbase(); + } /*seekoff*/ + + private: + /* buffered output stored here */ + std::vector buf_v_; + }; /*log_streambuf*/ + +} /*namespace xo*/ + +/* end log_streambuf.hpp */ diff --git a/include/nestlog/pad.hpp b/include/nestlog/pad.hpp new file mode 100644 index 00000000..123c8d5c --- /dev/null +++ b/include/nestlog/pad.hpp @@ -0,0 +1,41 @@ +/* @file pad.hpp */ + +#pragma once + +#include + +namespace xo { + /* use: + * ostream os = ...; + * os << ":" << pad(8) << ":" + * + * writes + * : : + * + * on os + */ + class pad_impl { + public: + pad_impl(int32_t n) : n_pad_(n) {} + + uint32_t n_pad() const { return n_pad_; } + + private: + uint32_t n_pad_ = 0; + }; /*pad_impl*/ + + inline pad_impl + pad(uint32_t n) { return pad_impl(n); } + + inline std::ostream & + operator<<(std::ostream &s, + pad_impl const &pad) + { + for(uint32_t i=0; i + +namespace xo { + namespace print { + /* print an event to a logfile + * intended to be usable as EventSink argument + * to RealizationSimSource + */ + template + class printer { + public: + printer(Stream && os) : os_{std::move(os)} {} + + void operator()(T const & x) { + this->os_ << x; + } + + private: + Stream os_; + }; /*printer*/ + } /*namespace print*/ +} /*namespace xo*/ + +/* end printer.hpp */ diff --git a/include/nestlog/quoted.hpp b/include/nestlog/quoted.hpp new file mode 100644 index 00000000..5e4cc8b4 --- /dev/null +++ b/include/nestlog/quoted.hpp @@ -0,0 +1,147 @@ +/* file quoted.hpp + * + * author: Roland Conybeare, Sep 2022 + */ + +#pragma once + +#include "nestlog/tostr.hpp" +#include +#include +#include +#include + +namespace xo { + namespace print { + /* use this to avoid template conversion hassles + * since literal strings get treated as arrays + */ + template + char const * ccs(T x) { return x; } + + /* Printing cases: + * 1. T&&: + * move into quoted_impl. T must be moveable! + * 2. T&: + * copy reference into quoted_impl. + * similarly for T const &, copy reference into quoted_impl + */ + + template + class quoted_impl { + public: + quoted_impl(bool unq_flag, T const & x) : unq_flag_{unq_flag}, value_{x} {} + quoted_impl(bool unq_flag, T && x) : unq_flag_{unq_flag}, value_{std::move(x)} {} + + bool unq_flag() const { return unq_flag_; } + T const & value() const { return value_; } + + void print(std::ostream & os) const { + std::string xs = xo::tostr(value_); + + if (xs.empty()) { + /* print empty string as "" */ + os << "\"\""; + } else if ((xs.at(0) == '<') && (xs.at(xs.size() - 1) == '>')) { + /* assume string represents output of a well-formed object printer, + * and already self-escapes + */ + os << xs; + } else if (xs.find_first_of(" \"\n\r\\") == std::string::npos) { + /* no escapes needed, just print xs */ + if (unq_flag_) + os << xs; + else + os << "\"" << xs << "\""; + } else { + /* printed value contains a space + * and/or a must-be-escaped character. + * in any case, need quotes + */ + + os << "\""; + + /* print contents of ss, with escapes: + * \ => \\ + * " => \" + * newline => \n + * cr => \r + */ + for (char ch : xs) { + switch (ch) { + case '"': + /* " => \" */ + os << "\\\""; + break; + case '\n': + /* newline -> \n */ + os << "\\\n"; + break; + case '\r': + /* cr -> \r */ + os << "\\\r"; + break; + case '\\': + /* \ => \\ (mind c++ requires we escape \) */ + os << "\\\\"; + break; + default: + os << ch; + break; + } + } + + os << "\""; + } + } /*print*/ + + private: + /* .unq_flag: if true, omit surrounding " chars + * if printed value satisfies both: + * - no escaped chars + * - no spaces + */ + bool unq_flag_ = false; + /* .value: value to be printed */ + T value_; + }; /*quoted_impl*/ + + template + std::ostream & + operator<<(std::ostream & os, quoted_impl const & x) { + x.print(os); + return os; + } /*operator*/ + + /* writing out std::forward behavior for completeness' sake: + * + * 1. call quoted(x) with rvalue std::string x, then: + * - T will be deduced to [std::string] + * (in particular: _not_ std::string &, std::string const &, std::string &&) + * - rvalue std::string passed to quoted_impl ctor + * + * 2a. call quoted(x) with std::string & x, then: + * - T deduced to [std::string &] + * - std::string & passed to quoted_impl ctor + * + * 2b. call quoted(x) with std::string const & x, then: + * - T deduced to [std::string const &] + * - std::string const & passed to quoted_impl ctor + */ + template + auto quoted(T && x) { + return quoted_impl(false /*unq_flag*/, std::forward(x)); + } + + inline auto qcstr(char const * x) { + return quoted(x); + } /*qcstr*/ + + template + auto unq(T && x) { + return quoted_impl(true /*unq_flag*/, std::forward(x)); + } + } /*namespace print*/ +} /*namespace xo*/ + +/* end quoted.hpp */ diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp new file mode 100644 index 00000000..29f5791c --- /dev/null +++ b/include/nestlog/scope.hpp @@ -0,0 +1,236 @@ +/* @file scopẹhpp */ + +#pragma once + +#include "log_state.hpp" +#include "tostr.hpp" +#include "tag.hpp" + +#include +#include +#include // for std::unique_ptr + +namespace xo { + + template + class state_impl; + + /* throw exception if condition not met*/ +# define XO_EXPECT(f,msg) if(!(f)) { throw std::runtime_error(msg); } + /* establish scope using current function name */ +# define XO_SCOPE(name) xo::scope name(__FUNCTION__) + /* like XO_SCOPE(name), but also set enabled flag */ +# define XO_SCOPE2(name, debug_flag) xo::scope name(__FUNCTION__, debug_flag) +# define XO_SCOPE_DISABLED(name) xo::scope name(__FUNCTION__, false) +# define XO_STUB() { XO_SCOPE(logr); logr.log("STUB"); } + + /* nesting logger + * + * Use: + * using xo::scope; + * + * void myfunc() { + * XO_SCOPE(log); //or scope x("myfunc") + * log(a,b,c); + * anotherfunc(); + * log(d,e,f); + * } + * + * void anotherfunc() { + * XO_SCOPE(x); // or scope x("anotherfunc") + * x.log(y); + * } + * + * or: + * void myfunc() { + * bool log_flag = true; + * XO_SCOPE2(log, log_flag); // create local variable 'log' + * log && log(a,b,c); // log iff enabled + * log.end_scope(); // optional protection against compiler destroying 'log' early + * } + * + * output like: + * +myfunc: + * a,b,c + * +anotherfunc: + * y + * -anotherfunc: + * d,e,f + * -myfunc: + */ + template > + class basic_scope { + public: + using state_impl_type = state_impl; + + public: + basic_scope(std::string_view name1); + basic_scope(std::string_view name1, bool enabled_flag); + basic_scope(std::string_view name1, std::string_view name2, bool enabled_flag); + ~basic_scope(); + + bool enabled() const { return !finalized_; } + + operator bool() const { return this->enabled(); } + + /* report current nesting level */ + std::uint32_t nesting_level() const; + + template + bool log(Tn&&... rest) { + if(this->finalized_) { + throw std::runtime_error("basic_scope: attempt to use finalized scope"); + } else { + state_impl_type * logstate = require_indent_thread_local_state(); + + /* log to per-thread stream to prevent data races */ + tosn(logstate2stream(logstate), rest...); + + this->flush2clog(logstate); + } + + return true; + } /*log*/ + + template + bool operator()(Tn&&... rest) { return this->log(rest...); } + + /* call once to end scope before dtor */ + void end_scope(); + + private: + /* establish stream for logging; use thread-local storage for threadsafetỵ + * stream, if recycled (ịẹ after 1st call to scopẹlog() from a particular thread), + * will be in 'reset-to-beginning of buffer' statẹ + */ + static state_impl_type * require_indent_thread_local_state(); + + /* establish logging state; use thread-local storage for threadsafety */ + static state_impl_type * require_thread_local_state(); + + /* retrieve permanently-associated ostream for logging-state */ + static std::ostream & logstate2stream(state_impl_type * logstate); + + /* write collected output to std::clog, or chosen streambuf */ + void flush2clog(state_impl_type * logstate, std::streambuf * p_sbuf = std::clog.rdbuf()); + + private: + /* keep logging state separately for each thread */ + static thread_local std::unique_ptr s_threadlocal_state; + + /* name of this scope (part 1) */ + std::string_view name1_ = ""; + /* name of this scope (part 2) */ + std::string_view name2_ = "::"; + /* set once per scope .finalized=true <-> logging disabled */ + bool finalized_ = false; + }; /*basic_scope*/ + + template + basic_scope::basic_scope(std::string_view fn1, + std::string_view fn2, + bool enabled_flag) + : name1_(fn1), + name2_(fn2), + finalized_(!enabled_flag) + { + if(enabled_flag) { + state_impl_type * logstate = basic_scope::require_thread_local_state(); + + logstate->preamble(this->name1_, this->name2_); + logstate->flush2sbuf(std::clog.rdbuf()); + + ///* next call to scope::log() can reset to beginning of buffer space */ + //logstate->ss().seekp(0); + + logstate->incr_nesting(); + } + } /*ctor*/ + + template + basic_scope::basic_scope(std::string_view fn1, bool enabled_flag) + : basic_scope(fn1, "", enabled_flag) + {} + + template + basic_scope::basic_scope(std::string_view fn) + : basic_scope(fn, true /*enabled_flag*/) + {} + + template + basic_scope::~basic_scope() { + if(!this->finalized_) + this->end_scope(); + } /*dtor*/ + + template + thread_local std::unique_ptr> + basic_scope::s_threadlocal_state; + + template + std::uint32_t + basic_scope::nesting_level() const { + return require_thread_local_state()->nesting_level(); + } /*nesting_level*/ + + template + basic_scope::state_impl_type * + basic_scope::require_indent_thread_local_state() + { + state_impl_type * local_state = require_thread_local_state(); + + local_state->reset_stream(); + local_state->indent(' ' /*pad_char*/); + + return local_state; + } /*require_thread_local_stream*/ + + template + basic_scope::state_impl_type * + basic_scope::require_thread_local_state() + { + if(!s_threadlocal_state) { + s_threadlocal_state.reset(new state_impl_type()); + } + + return s_threadlocal_state.get(); + } /*require_thread_local_state*/ + + template + std::ostream & + basic_scope::logstate2stream(state_impl_type * logstate) + { + return logstate->ss(); + } /*logstate2stream*/ + + template + void + basic_scope::flush2clog(state_impl_type * logstate, + std::streambuf * p_sbuf) + { + logstate->flush2sbuf(p_sbuf); + } /*flush2clog*/ + + template + void + basic_scope::end_scope() + { + if(!this->finalized_) { + this->finalized_ = true; + + state_impl_type * logstate + = basic_scope::require_thread_local_state(); + + logstate->decr_nesting(); + + logstate->postamble(this->name1_, this->name2_); + logstate->flush2sbuf(std::clog.rdbuf()); + } + } /*end_scope*/ + + + using scope = basic_scope; + +} /*namespace xo*/ + +/* end scope.hpp */ diff --git a/include/nestlog/tag.hpp b/include/nestlog/tag.hpp new file mode 100644 index 00000000..16a3e21a --- /dev/null +++ b/include/nestlog/tag.hpp @@ -0,0 +1,87 @@ +/* @file tag.hpp */ + +#pragma once + +#include "nestlog/quoted.hpp" +#include + +// STRINGIFY(xyz) -> "xyz" +#define STRINGIFY(x) #x + +// TAG(xyz) -> tag("xyz", xyz) +#define TAG(x) xo::make_tag(STRINGIFY(x), x) +#define TAG2(x, y) xo::make_tag(x, y) + +namespace xo { + // associate a name with a value + // + // will print like + // :name value + // + // NOTE: will search for operator<< overloads in the logutil + // namespace + //*/ + template + struct tag_impl { + tag_impl(Name const & n, Value const & v) + : name_{n}, value_{v} {} + + Name const & name() const { return name_; } + Value const & value() const { return value_; } + + private: + Name name_; + Value value_; + }; /*tag_impl*/ + + /* deduce tag template-type from arguments */ + template + tag_impl + make_tag(Name && n, Value && v) + { + return tag_impl(n, v); + } /*make_tag*/ + + template + tag_impl + make_tag(char const * n, Value && v) { + return tag_impl(n, v); + } /*make_tag*/ + + template + tag_impl + xtag(Name && n, Value && v) + { + return tag_impl(n, v); + } /*xtag*/ + + template + tag_impl + xtag(char const * n, Value && v) { + return tag_impl(n, v); + } /*xtag*/ + + inline + tag_impl + xtag_pre(char const * n) { + return tag_impl(n, ""); + } /*xtag_pre*/ + + template + inline std::ostream & + operator<<(std::ostream &s, + tag_impl const & tag) + { + using xo::print::unq; + + if(PrefixSpace) + s << " "; + + s << ":" << tag.name() + << " " << unq(tag.value()); + + return s; + } /*operator<<*/ +} /*namespace xo*/ + +/* end tag.hpp */ diff --git a/include/nestlog/tostr.hpp b/include/nestlog/tostr.hpp new file mode 100644 index 00000000..b2bc927b --- /dev/null +++ b/include/nestlog/tostr.hpp @@ -0,0 +1,99 @@ +/* file tostr.hpp + * + * author: Roland Conybeare, Sep 2022 + */ + +#pragma once + +#include +#include +#include + +namespace xo { + /* + * write x to stream s + * note: here x is a universal reference, since + * (a) it's a template type + * (b) requires deduction to establish x's type + * this means: + * x will be an r-value reference or an l-value reference + * depending on calling context + * + * see: + * https://eli.thegreenplace.net/2014/variadic-templates-in-c/ + * http://bajamircea.github.io/coding/cpp/2016/04/07/move-forward.html + * https://en.cppreference.com/w/cpp/language/value_category + * + * has identity == has address + * + * /- has identity -----------------\ + * | | + * | lvalue | + * | glvalue /------------------------------\ + * | | | | + * | | xvalue | | + * | | rvalue | | + * | | glvalue | | + * | | | | + * \--------------------------------/ | + * | rvalue | + * | prvalue | + * | | + * \- can be moved ---------------/ + * + * 1. has identity, but cannot be moved -> it's an lvalue; otherwise it's an rvalue + * e.g: local variable name + * + * 2. can be moved, but no identity -> it's a prvalue (pure right-value); + * otherwise it's a glvalue (generalized left-value) + * e.g: non-reference function return value, or literal constant + * + * 3. has identity and can be moved -> it's an xvalue (strange value) + * e.g: std::move(a) + * + * reminder: + * - std::move() does not move: it converts lvalue to rvalue, so compiler can select + * desired overload + * - std::forward() does not forward: it recovers original value category + * (when starting with a universal reference), so compiler can select + * desired ctor + */ + + // Use: + // tos(s,a,b,c) + // is the same as + // s << a << b << c; + // + template + Stream & tos(Stream & s, T && x) { + s << x; + return s; + } /*tos*/ + + template + Stream &tos(Stream &s, T &&x, Tn &&...rest) { + s << x; + return tos(s, rest...); + } /*tos*/ + + // like tos(..), but append newline + // + template + Stream &tosn(Stream &s, Tn &&...args) { + tos(s, args...); + s << std::endl; + return s; + } /*tosn*/ + + // tostr(args..) writes arguments to temporary stingstream, + // returns its contents + // + template std::string tostr(Tn &&...args) { + std::stringstream ss; + tos(ss, args...); + //ss << std::ends; + return ss.str(); + } /*tostr*/ +} /*namespace xo*/ + +/* end tostr.hpp */ diff --git a/include/nestlog/vector.hpp b/include/nestlog/vector.hpp new file mode 100644 index 00000000..be5f4497 --- /dev/null +++ b/include/nestlog/vector.hpp @@ -0,0 +1,28 @@ +/* file vector.hpp + * + * author: Roland Conybeare, Sep 2022 + */ + +#pragma once + +#include +#include + +namespace std { + template + inline std::ostream & + operator<<(std::ostream & os, + std::vector const & v) + { + os << "["; + for(size_t i=0, z=v.size(); i 0) + os << " "; + os << v[i]; + } + os << "]"; + return os; + } /*operator<<*/ +} /*namespace std*/ + +/* end vector.hpp */ From 45988211c7ccf7daa5063170302ffdbf32d3f900 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 11 Sep 2023 16:10:50 -0400 Subject: [PATCH 003/170] doc: README.md example --- README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 829204dd..261399f8 100644 --- a/README.md +++ b/README.md @@ -1 +1,31 @@ -# nestlog +# nestlog -- logging with automatic indenting according to call graph + +Nestlog is a lightweight header-only library for console logging. + +## Examples + + ``` + /* examples/ex1/ex1.cpp */ + + #include "nestlog/scope.hpp" + + using namespace xo; + + void A(int x) { + XO_SCOPE(log) // i.e. xo::scope log("A"); + + log(":x ", x); + } + + int + main(int argc, char ** argv) { + A(66); + } + ``` + + output: + ``` + +A + :x 66 + -A + ``` From 7bfde708dd978e753475add85ae3a9a782e05c6c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 11 Sep 2023 16:12:18 -0400 Subject: [PATCH 004/170] doc: format tidy --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 261399f8..33e1b52d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ Nestlog is a lightweight header-only library for console logging. ## Examples - ``` /* examples/ex1/ex1.cpp */ #include "nestlog/scope.hpp" @@ -21,11 +20,9 @@ Nestlog is a lightweight header-only library for console logging. main(int argc, char ** argv) { A(66); } - ``` - output: - ``` +output: + +A - :x 66 + :x 66 -A - ``` From c32699ae14d55bbb5d4aa9130d74cfe660c93e6a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 11 Sep 2023 16:24:46 -0400 Subject: [PATCH 005/170] nestlog: + ex2 + expand README.md --- README.md | 70 +++++++++++++++++++++++++++++++++++--- example/CMakeLists.txt | 1 + example/ex2/CMakeLists.txt | 3 ++ example/ex2/ex2.cpp | 27 +++++++++++++++ 4 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 example/ex2/CMakeLists.txt create mode 100644 example/ex2/ex2.cpp diff --git a/README.md b/README.md index 33e1b52d..2db7c081 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ Nestlog is a lightweight header-only library for console logging. ## Examples +### 1 + /* examples/ex1/ex1.cpp */ #include "nestlog/scope.hpp" - using namespace xo; - void A(int x) { - XO_SCOPE(log) // i.e. xo::scope log("A"); + XO_SCOPE(log); // i.e. xo::scope log("A"); - log(":x ", x); + log("enter ", ":x ", x); } int @@ -24,5 +24,65 @@ Nestlog is a lightweight header-only library for console logging. output: +A - :x 66 + enter :x 66 -A + +### 2 + + /* examples ex2/ex2.cpp */ + + #include "nestlog/scope.hpp" + + int fib(int n) { + XO_SCOPE(log); + + int retval = 1; + + if (n >= 2) + retval = fib(n - 1) + fib(n - 2); + + log("result ", ":retval ", retval); + } + + int + main(int argc, char ** argv) { + XO_SCOPE(log); + + int n = 4; + int fn = fib(n); + + log(":n ", n, " :fib(n) ", fn); + } + +output: + + +main + +fib + +fib + +fib + +fib + result :retval 1 + -fib + +fib + result :retval 1 + -fib + result :retval 2 + -fib + +fib + result :retval 1 + -fib + result :retval 3 + -fib + +fib + +fib + result :retval 1 + -fib + +fib + result :retval 1 + -fib + result :retval 2 + -fib + result :retval 5 + -fib + :n 4 :fib(n) 5 + -main diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index ac2655ae..8a901a22 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -8,6 +8,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") #include(cmake/FindSphinx.cmake) add_subdirectory(ex1) +add_subdirectory(ex2) # ---------------------------------------------------------------- # make standard directories for std:: includes explicit diff --git a/example/ex2/CMakeLists.txt b/example/ex2/CMakeLists.txt new file mode 100644 index 00000000..76ae6f64 --- /dev/null +++ b/example/ex2/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(ex2 ex2.cpp) + +target_include_directories(ex2 PUBLIC ${PROJECT_SOURCE_DIR}/include) diff --git a/example/ex2/ex2.cpp b/example/ex2/ex2.cpp new file mode 100644 index 00000000..6267c045 --- /dev/null +++ b/example/ex2/ex2.cpp @@ -0,0 +1,27 @@ +/* examples ex2/ex2.cpp */ + +#include "nestlog/scope.hpp" + +int +fib(int n) { + XO_SCOPE(log); + + int retval = 1; + + if (n >= 2) + retval = fib(n - 1) + fib(n - 2); + + log("result ", ":retval ", retval); + + return retval; +} + +int +main(int argc, char ** argv) { + XO_SCOPE(log); + + int n = 4; + int fn = fib(n); + + log(":n ", n, " :fib(n) ", fn); +} From 01bd1ffc6f79e5ea5183844372ec115c7c07016c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 11 Sep 2023 16:37:50 -0400 Subject: [PATCH 006/170] tweak example 2 output --- README.md | 39 ++++++++++++++++++++++++--------------- example/ex2/ex2.cpp | 6 ++++-- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 2db7c081..4e934ad7 100644 --- a/README.md +++ b/README.md @@ -33,15 +33,20 @@ output: #include "nestlog/scope.hpp" - int fib(int n) { - XO_SCOPE(log); + int + fib(int n) { + XO_SCOPE(log); - int retval = 1; + int retval = 1; - if (n >= 2) - retval = fib(n - 1) + fib(n - 2); + if (n >= 2) { + log(":n ", n); + retval = fib(n - 1) + fib(n - 2); + } - log("result ", ":retval ", retval); + log(":n ", n, " -> :retval ", retval); + + return retval; } int @@ -58,31 +63,35 @@ output: +main +fib + :n 4 +fib + :n 3 +fib + :n 2 +fib - result :retval 1 + :n 1 -> :retval 1 -fib +fib - result :retval 1 + :n 0 -> :retval 1 -fib - result :retval 2 + :n 2 -> :retval 2 -fib +fib - result :retval 1 + :n 1 -> :retval 1 -fib - result :retval 3 + :n 3 -> :retval 3 -fib +fib + :n 2 +fib - result :retval 1 + :n 1 -> :retval 1 -fib +fib - result :retval 1 + :n 0 -> :retval 1 -fib - result :retval 2 + :n 2 -> :retval 2 -fib - result :retval 5 + :n 4 -> :retval 5 -fib :n 4 :fib(n) 5 -main diff --git a/example/ex2/ex2.cpp b/example/ex2/ex2.cpp index 6267c045..dfc2a7bd 100644 --- a/example/ex2/ex2.cpp +++ b/example/ex2/ex2.cpp @@ -8,10 +8,12 @@ fib(int n) { int retval = 1; - if (n >= 2) + if (n >= 2) { + log(":n ", n); retval = fib(n - 1) + fib(n - 2); + } - log("result ", ":retval ", retval); + log(":n ", n, " -> :retval ", retval); return retval; } From 89b493e939926d05a1ab564ce272175fb0c62db9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 12:23:32 -0400 Subject: [PATCH 007/170] build: bugfix: missed commit nestlog.cmake --- cmake/nestlog.cmake | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 cmake/nestlog.cmake diff --git a/cmake/nestlog.cmake b/cmake/nestlog.cmake new file mode 100644 index 00000000..30736007 --- /dev/null +++ b/cmake/nestlog.cmake @@ -0,0 +1,31 @@ +# ---------------------------------------------------------------- +# use this in subdirs that compile c++ code +# +macro(xo_include_options target) + # ---------------------------------------------------------------- + # PROJECT_SOURCE_DIR: + # so we can for example write + # #include "nestlog/scope.hpp" + # from anywhere in the project + # PROJECT_BINARY_DIR: + # since generated version file will be in build directory, + # need that build directory to also appear in + # compiler's include path + # + target_include_directories( + ${target} PUBLIC + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR} + ) + + # ---------------------------------------------------------------- + # make standard directories for std:: includes explicit + # so that + # (1) they appear in compile_commands.json. + # (2) clangd (run from emacs lsp-mode) can find them + # + if(CMAKE_EXPORT_COMPILE_COMMANDS) + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES + ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) + endif() +endmacro() From 49f8acfabb87f94291b497ae71fdbb4177d2b362 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 12:24:05 -0400 Subject: [PATCH 008/170] build: include paths (for lsp integration) --- CMakeLists.txt | 2 ++ example/ex1/CMakeLists.txt | 3 +-- example/ex2/CMakeLists.txt | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2a41b6f..38939895 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,4 +4,6 @@ project(nestlog VERSION 0.1) enable_language(CXX) enable_testing() +include(cmake/nestlog.cmake) + add_subdirectory(example) diff --git a/example/ex1/CMakeLists.txt b/example/ex1/CMakeLists.txt index ce8d9a5e..6af29d79 100644 --- a/example/ex1/CMakeLists.txt +++ b/example/ex1/CMakeLists.txt @@ -1,3 +1,2 @@ add_executable(ex1 ex1.cpp) - -target_include_directories(ex1 PUBLIC ${PROJECT_SOURCE_DIR}/include) +xo_include_options(ex1) diff --git a/example/ex2/CMakeLists.txt b/example/ex2/CMakeLists.txt index 76ae6f64..1ac5735a 100644 --- a/example/ex2/CMakeLists.txt +++ b/example/ex2/CMakeLists.txt @@ -1,3 +1,2 @@ add_executable(ex2 ex2.cpp) - -target_include_directories(ex2 PUBLIC ${PROJECT_SOURCE_DIR}/include) +xo_include_options(ex2) From 5ad143d5b69912658edbb4aa8201938055851a3b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 12:24:33 -0400 Subject: [PATCH 009/170] nestlog: control indent level + args with scope entry --- example/ex2/ex2.cpp | 17 ++++--- include/nestlog/log_state.hpp | 22 +++++++--- include/nestlog/log_streambuf.hpp | 3 +- include/nestlog/pad.hpp | 27 ++++++++---- include/nestlog/scope.hpp | 73 +++++++++++++++++++------------ include/nestlog/tostr.hpp | 6 +++ 6 files changed, 98 insertions(+), 50 deletions(-) diff --git a/example/ex2/ex2.cpp b/example/ex2/ex2.cpp index dfc2a7bd..85066b73 100644 --- a/example/ex2/ex2.cpp +++ b/example/ex2/ex2.cpp @@ -2,28 +2,33 @@ #include "nestlog/scope.hpp" +using namespace xo; + int fib(int n) { - XO_SCOPE(log); + scope log(XO_SSETUP0(), ":n ", n); int retval = 1; if (n >= 2) { - log(":n ", n); retval = fib(n - 1) + fib(n - 2); + log(":n ", n); } - - log(":n ", n, " -> :retval ", retval); + log("<- :retval ", retval); return retval; } int main(int argc, char ** argv) { - XO_SCOPE(log); + log_config::indent_width = 4; int n = 4; + + scope log(XO_SSETUP0(), ":n", 4); + int fn = fib(n); - log(":n ", n, " :fib(n) ", fn); + log(":n ", n); + log("<- :fib(n) ", fn); } diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index 41556b8a..8d096950 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -2,7 +2,9 @@ #pragma once +#include "log_config.hpp" #include "log_streambuf.hpp" +#include "pad.hpp" #include #include // for std::unique_ptr @@ -44,11 +46,12 @@ namespace xo { /* common implementation for .preamble(), .postamble() */ void entryexit_aux(std::string_view name1, std::string_view name2, - char label_char); + char label_char, + bool newline_flag); private: /* current nesting level for this thread */ - uint32_t nesting_level_ = 0; + std::uint32_t nesting_level_ = 0; /* buffer space for logging * (before pretty-printing for scope::log() calls that span multiple lines) @@ -95,16 +98,20 @@ namespace xo { #endif /* indent to nesting level */ + this->ss_ << pad(this->nesting_level_ * log_config::indent_width, pad_char); +#ifdef OBSOLETE for(uint32_t i = 0, n = this->nesting_level_; iss_ << pad_char; } +#endif } /*indent*/ template void state_impl::entryexit_aux(std::string_view name1, std::string_view name2, - char label_char) + char label_char, + bool newline_flag) { log_streambuf_type * sbuf = this->p_sbuf_phase1_.get(); @@ -115,7 +122,10 @@ namespace xo { this->ss_ << label_char; /* scope name */ - this->ss_ << name1 << name2 << "\n"; + this->ss_ << name1 << name2; + + if (newline_flag) + this->ss_ << "\n"; } /*entryexit_aux*/ template @@ -123,7 +133,7 @@ namespace xo { state_impl::preamble(std::string_view name1, std::string_view name2) { - this->entryexit_aux(name1, name2, '+' /*label_char*/); + this->entryexit_aux(name1, name2, '+' /*label_char*/, false /*!newline_flag*/); } /*preamble*/ template @@ -131,7 +141,7 @@ namespace xo { state_impl::postamble(std::string_view name1, std::string_view name2) { - this->entryexit_aux(name1, name2, '-' /*label_char*/); + this->entryexit_aux(name1, name2, '-' /*label_char*/, true /*newline_flag*/); } /*postamble*/ template diff --git a/include/nestlog/log_streambuf.hpp b/include/nestlog/log_streambuf.hpp index 5d06dab7..02b4b183 100644 --- a/include/nestlog/log_streambuf.hpp +++ b/include/nestlog/log_streambuf.hpp @@ -5,7 +5,8 @@ #include #include #include // e.g. for std::memcpy() -#include // e.g. for std::memcpy() +#include +#include namespace xo { /* recycling buffer for logging. diff --git a/include/nestlog/pad.hpp b/include/nestlog/pad.hpp index 123c8d5c..e85d9c25 100644 --- a/include/nestlog/pad.hpp +++ b/include/nestlog/pad.hpp @@ -3,36 +3,47 @@ #pragma once #include +#include namespace xo { /* use: * ostream os = ...; + * + * 1. * os << ":" << pad(8) << ":" * * writes * : : * + * 2. + * os << pad(16, '-') + * + * writes + * ---------------- + * * on os */ class pad_impl { public: - pad_impl(int32_t n) : n_pad_(n) {} + pad_impl(std::uint32_t n, char pad_char) : n_pad_{n}, pad_char_{pad_char} {} - uint32_t n_pad() const { return n_pad_; } + std::uint32_t n_pad() const { return n_pad_; } + char pad_char() const { return pad_char_; } private: - uint32_t n_pad_ = 0; + std::uint32_t n_pad_ = 0; + char pad_char_ = '\0'; }; /*pad_impl*/ inline pad_impl - pad(uint32_t n) { return pad_impl(n); } + pad(std::uint32_t n, char pad_char = ' ') { return pad_impl(n, pad_char); } inline std::ostream & - operator<<(std::ostream &s, - pad_impl const &pad) + operator<<(std::ostream & s, + pad_impl const & pad) { - for(uint32_t i=0; i class state_impl; +//# define XO_SSETUP0() xo::scope_setup(__FUNCTION__) +# define XO_SSETUP0() xo::scope_setup(__PRETTY_FUNCTION__) + /* throw exception if condition not met*/ # define XO_EXPECT(f,msg) if(!(f)) { throw std::runtime_error(msg); } /* establish scope using current function name */ -# define XO_SCOPE(name) xo::scope name(__FUNCTION__) +# define XO_SCOPE(name) xo::scope name(xo::scope_setup(__FUNCTION__)) /* like XO_SCOPE(name), but also set enabled flag */ -# define XO_SCOPE2(name, debug_flag) xo::scope name(__FUNCTION__, debug_flag) -# define XO_SCOPE_DISABLED(name) xo::scope name(__FUNCTION__, false) +# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(__FUNCTION__, debug_flag)) +# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(__FUNCTION__, false)) # define XO_STUB() { XO_SCOPE(logr); logr.log("STUB"); } + /* convenience class for basic_scope<..> construction (see below). + * use to disambiguate setup from other arguments + */ + struct scope_setup { + scope_setup(std::string_view name1, std::string_view name2, bool enabled_flag) + : name1_{name1}, name2_{name2}, enabled_flag_{enabled_flag} {} + scope_setup(std::string_view name1, bool enabled_flag) + : scope_setup(name1, "", enabled_flag) {} + scope_setup(std::string_view name1) + : scope_setup(name1, true /*enabled_flag*/) {} + + std::string_view name1_ = "<.name1>"; + std::string_view name2_ = "<.name2>"; + bool enabled_flag_ = false; + }; /*scope_setup*/ + /* nesting logger * * Use: @@ -64,9 +83,9 @@ namespace xo { using state_impl_type = state_impl; public: - basic_scope(std::string_view name1); - basic_scope(std::string_view name1, bool enabled_flag); - basic_scope(std::string_view name1, std::string_view name2, bool enabled_flag); + //basic_scope(std::string_view name1, bool enabled_flag); + template + basic_scope(scope_setup setup, Tn&&... rest); ~basic_scope(); bool enabled() const { return !finalized_; } @@ -76,6 +95,8 @@ namespace xo { /* report current nesting level */ std::uint32_t nesting_level() const; + void set_dest_sbuf(std::streambuf * x) { this->dest_sbuf_ = x; } + template bool log(Tn&&... rest) { if(this->finalized_) { @@ -86,7 +107,7 @@ namespace xo { /* log to per-thread stream to prevent data races */ tosn(logstate2stream(logstate), rest...); - this->flush2clog(logstate); + this->flush2sbuf(logstate); } return true; @@ -112,12 +133,14 @@ namespace xo { static std::ostream & logstate2stream(state_impl_type * logstate); /* write collected output to std::clog, or chosen streambuf */ - void flush2clog(state_impl_type * logstate, std::streambuf * p_sbuf = std::clog.rdbuf()); + void flush2sbuf(state_impl_type * logstate); private: /* keep logging state separately for each thread */ static thread_local std::unique_ptr s_threadlocal_state; + /* send indented output to this streambuf (e.g. std::clog.rdbuf()) */ + std::streambuf * dest_sbuf_ = std::clog.rdbuf(); /* name of this scope (part 1) */ std::string_view name1_ = ""; /* name of this scope (part 2) */ @@ -127,17 +150,20 @@ namespace xo { }; /*basic_scope*/ template - basic_scope::basic_scope(std::string_view fn1, - std::string_view fn2, - bool enabled_flag) - : name1_(fn1), - name2_(fn2), - finalized_(!enabled_flag) + template + basic_scope::basic_scope(scope_setup setup, Tn&&... args) + + : name1_{std::move(setup.name1_)}, + name2_{std::move(setup.name2_)}, + finalized_{!setup.enabled_flag_} { - if(enabled_flag) { + if(setup.enabled_flag_) { state_impl_type * logstate = basic_scope::require_thread_local_state(); logstate->preamble(this->name1_, this->name2_); + + tosn(logstate2stream(logstate), " ", args...); + logstate->flush2sbuf(std::clog.rdbuf()); ///* next call to scope::log() can reset to beginning of buffer space */ @@ -147,16 +173,6 @@ namespace xo { } } /*ctor*/ - template - basic_scope::basic_scope(std::string_view fn1, bool enabled_flag) - : basic_scope(fn1, "", enabled_flag) - {} - - template - basic_scope::basic_scope(std::string_view fn) - : basic_scope(fn, true /*enabled_flag*/) - {} - template basic_scope::~basic_scope() { if(!this->finalized_) @@ -205,11 +221,10 @@ namespace xo { template void - basic_scope::flush2clog(state_impl_type * logstate, - std::streambuf * p_sbuf) + basic_scope::flush2sbuf(state_impl_type * logstate) { - logstate->flush2sbuf(p_sbuf); - } /*flush2clog*/ + logstate->flush2sbuf(this->dest_sbuf_); + } /*flush2sbuf*/ template void diff --git a/include/nestlog/tostr.hpp b/include/nestlog/tostr.hpp index b2bc927b..e395cfe3 100644 --- a/include/nestlog/tostr.hpp +++ b/include/nestlog/tostr.hpp @@ -59,6 +59,12 @@ namespace xo { * desired ctor */ + /* no-op terminal case */ + template + Stream & tos(Stream & s) { + return s; + } + // Use: // tos(s,a,b,c) // is the same as From 605f4df41f26909df3f8f2100fc92ff20026538c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 12:34:16 -0400 Subject: [PATCH 010/170] nestlog: missed commit log_config.hpp --- include/nestlog/log_config.hpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 include/nestlog/log_config.hpp diff --git a/include/nestlog/log_config.hpp b/include/nestlog/log_config.hpp new file mode 100644 index 00000000..9b1eff12 --- /dev/null +++ b/include/nestlog/log_config.hpp @@ -0,0 +1,22 @@ +/* @file log_config.hpp */ + +#pragma once + +#include + +namespace xo { + /* Tag here b/c we want header-only library */ + template + struct log_config_impl { + /* spaces per indent level */ + static std::uint32_t indent_width; + }; /*log_config_impl*/ + + template + std::uint32_t + log_config_impl::indent_width = 1; + + using log_config = log_config_impl; +} /*namespace xo*/ + +/* end log_config.hpp */ From 7c964ab93cb7e29535dae83caacb2453b6acac8e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 12:34:44 -0400 Subject: [PATCH 011/170] nestlog: + trailing args with .end_scope() --- example/ex2/ex2.cpp | 3 ++- include/nestlog/log_state.hpp | 13 ++++--------- include/nestlog/scope.hpp | 15 ++++++++++----- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/example/ex2/ex2.cpp b/example/ex2/ex2.cpp index 85066b73..2084b551 100644 --- a/example/ex2/ex2.cpp +++ b/example/ex2/ex2.cpp @@ -14,7 +14,8 @@ fib(int n) { retval = fib(n - 1) + fib(n - 2); log(":n ", n); } - log("<- :retval ", retval); + + log.end_scope("<- :retval ", retval); return retval; } diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index 8d096950..ac25e043 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -46,8 +46,7 @@ namespace xo { /* common implementation for .preamble(), .postamble() */ void entryexit_aux(std::string_view name1, std::string_view name2, - char label_char, - bool newline_flag); + char label_char); private: /* current nesting level for this thread */ @@ -110,8 +109,7 @@ namespace xo { void state_impl::entryexit_aux(std::string_view name1, std::string_view name2, - char label_char, - bool newline_flag) + char label_char) { log_streambuf_type * sbuf = this->p_sbuf_phase1_.get(); @@ -123,9 +121,6 @@ namespace xo { /* scope name */ this->ss_ << name1 << name2; - - if (newline_flag) - this->ss_ << "\n"; } /*entryexit_aux*/ template @@ -133,7 +128,7 @@ namespace xo { state_impl::preamble(std::string_view name1, std::string_view name2) { - this->entryexit_aux(name1, name2, '+' /*label_char*/, false /*!newline_flag*/); + this->entryexit_aux(name1, name2, '+' /*label_char*/); } /*preamble*/ template @@ -141,7 +136,7 @@ namespace xo { state_impl::postamble(std::string_view name1, std::string_view name2) { - this->entryexit_aux(name1, name2, '-' /*label_char*/, true /*newline_flag*/); + this->entryexit_aux(name1, name2, '-' /*label_char*/); } /*postamble*/ template diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp index 249eb23f..0f1af013 100644 --- a/include/nestlog/scope.hpp +++ b/include/nestlog/scope.hpp @@ -105,7 +105,7 @@ namespace xo { state_impl_type * logstate = require_indent_thread_local_state(); /* log to per-thread stream to prevent data races */ - tosn(logstate2stream(logstate), rest...); + tosn(logstate2stream(logstate), std::forward(rest)...); this->flush2sbuf(logstate); } @@ -114,10 +114,11 @@ namespace xo { } /*log*/ template - bool operator()(Tn&&... rest) { return this->log(rest...); } + bool operator()(Tn&&... args) { return this->log(std::forward(args)...); } /* call once to end scope before dtor */ - void end_scope(); + template + void end_scope(Tn&&... args); private: /* establish stream for logging; use thread-local storage for threadsafetỵ @@ -162,7 +163,7 @@ namespace xo { logstate->preamble(this->name1_, this->name2_); - tosn(logstate2stream(logstate), " ", args...); + tosn(logstate2stream(logstate), " ", std::forward(args)...); logstate->flush2sbuf(std::clog.rdbuf()); @@ -227,8 +228,9 @@ namespace xo { } /*flush2sbuf*/ template + template void - basic_scope::end_scope() + basic_scope::end_scope(Tn&&... args) { if(!this->finalized_) { this->finalized_ = true; @@ -239,6 +241,9 @@ namespace xo { logstate->decr_nesting(); logstate->postamble(this->name1_, this->name2_); + + tosn(logstate2stream(logstate), " ", std::forward(args)...); + logstate->flush2sbuf(std::clog.rdbuf()); } } /*end_scope*/ From 2871874dd8faed258639ea322b8f9ba6b45c9cfe Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 15:21:48 -0400 Subject: [PATCH 012/170] nestlog: choose function-printing style --- example/CMakeLists.txt | 1 + example/ex2/ex2.cpp | 2 +- example/ex3/CMakeLists.txt | 2 ++ example/ex3/ex3.cpp | 36 ++++++++++++++++++++++++++++++++++ include/nestlog/log_config.hpp | 7 +++++++ include/nestlog/log_state.hpp | 25 ++++++++++++++--------- include/nestlog/scope.hpp | 30 ++++++++++++++++------------ 7 files changed, 80 insertions(+), 23 deletions(-) create mode 100644 example/ex3/CMakeLists.txt create mode 100644 example/ex3/ex3.cpp diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 8a901a22..06512248 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") add_subdirectory(ex1) add_subdirectory(ex2) +add_subdirectory(ex3) # ---------------------------------------------------------------- # make standard directories for std:: includes explicit diff --git a/example/ex2/ex2.cpp b/example/ex2/ex2.cpp index 2084b551..3d246f0e 100644 --- a/example/ex2/ex2.cpp +++ b/example/ex2/ex2.cpp @@ -26,7 +26,7 @@ main(int argc, char ** argv) { int n = 4; - scope log(XO_SSETUP0(), ":n", 4); + scope log(XO_SSETUP0(), ":n ", 4); int fn = fib(n); diff --git a/example/ex3/CMakeLists.txt b/example/ex3/CMakeLists.txt new file mode 100644 index 00000000..d81e0e99 --- /dev/null +++ b/example/ex3/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(ex3 ex3.cpp) +xo_include_options(ex3) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp new file mode 100644 index 00000000..58d81dc7 --- /dev/null +++ b/example/ex3/ex3.cpp @@ -0,0 +1,36 @@ +/* examples ex3/ex3.cpp */ + +#include "nestlog/scope.hpp" + +using namespace xo; + +int +fib(int n) { + scope log(XO_SSETUP0(), ":n ", n); + + int retval = 1; + + if (n >= 2) { + retval = fib(n - 1) + fib(n - 2); + log(":n ", n); + } + + log.end_scope("<- :retval ", retval); + + return retval; +} + +int +main(int argc, char ** argv) { + log_config::style = FS_Pretty; + log_config::indent_width = 4; + + int n = 4; + + scope log(XO_SSETUP0(), ":n ", 4); + + int fn = fib(n); + + log(":n ", n); + log("<- :fib(n) ", fn); +} diff --git a/include/nestlog/log_config.hpp b/include/nestlog/log_config.hpp index 9b1eff12..ce28665f 100644 --- a/include/nestlog/log_config.hpp +++ b/include/nestlog/log_config.hpp @@ -2,6 +2,7 @@ #pragma once +#include "function.hpp" #include namespace xo { @@ -10,12 +11,18 @@ namespace xo { struct log_config_impl { /* spaces per indent level */ static std::uint32_t indent_width; + /* display style for function names. FS_Simple|FS_Pretty|FS_Streamlined */ + static function_style style; }; /*log_config_impl*/ template std::uint32_t log_config_impl::indent_width = 1; + template + function_style + log_config_impl::style = FS_Streamlined; + using log_config = log_config_impl; } /*namespace xo*/ diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index ac25e043..59c3b4f6 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -27,11 +27,11 @@ namespace xo { std::ostream & ss() { return ss_; } /* call on entry to new scope */ - void preamble(std::string_view name1, std::string_view name2); + void preamble(function_style style, std::string_view name1, std::string_view name2); /* call before each new log entry */ void indent(char pad_char); /* call on exit from scope */ - void postamble(std::string_view name1, std::string_view name2); + void postamble(function_style style, std::string_view name1, std::string_view name2); /* write collected output to *p_sbuf */ void flush2sbuf(std::streambuf * p_sbuf); @@ -44,7 +44,8 @@ namespace xo { private: /* common implementation for .preamble(), .postamble() */ - void entryexit_aux(std::string_view name1, + void entryexit_aux(function_style style, + std::string_view name1, std::string_view name2, char label_char); @@ -107,7 +108,8 @@ namespace xo { template void - state_impl::entryexit_aux(std::string_view name1, + state_impl::entryexit_aux(function_style style, + std::string_view name1, std::string_view name2, char label_char) { @@ -119,24 +121,29 @@ namespace xo { /* mnemonic for scope entry/exit */ this->ss_ << label_char; + if (log_config::indent_width > 1) + this->ss_ << ' '; + /* scope name */ - this->ss_ << name1 << name2; + this->ss_ << function_name(style, name1) << name2; } /*entryexit_aux*/ template void - state_impl::preamble(std::string_view name1, + state_impl::preamble(function_style style, + std::string_view name1, std::string_view name2) { - this->entryexit_aux(name1, name2, '+' /*label_char*/); + this->entryexit_aux(style, name1, name2, '+' /*label_char*/); } /*preamble*/ template void - state_impl::postamble(std::string_view name1, + state_impl::postamble(function_style style, + std::string_view name1, std::string_view name2) { - this->entryexit_aux(name1, name2, '-' /*label_char*/); + this->entryexit_aux(style, name1, name2, '-' /*label_char*/); } /*postamble*/ template diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp index 0f1af013..cd3219fe 100644 --- a/include/nestlog/scope.hpp +++ b/include/nestlog/scope.hpp @@ -16,28 +16,29 @@ namespace xo { class state_impl; //# define XO_SSETUP0() xo::scope_setup(__FUNCTION__) -# define XO_SSETUP0() xo::scope_setup(__PRETTY_FUNCTION__) +# define XO_SSETUP0() xo::scope_setup(log_config::style, __PRETTY_FUNCTION__) /* throw exception if condition not met*/ # define XO_EXPECT(f,msg) if(!(f)) { throw std::runtime_error(msg); } /* establish scope using current function name */ -# define XO_SCOPE(name) xo::scope name(xo::scope_setup(__FUNCTION__)) +# define XO_SCOPE(name) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__)) /* like XO_SCOPE(name), but also set enabled flag */ -# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(__FUNCTION__, debug_flag)) -# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(__FUNCTION__, false)) +# define XOf_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__, debug_flag)) +# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__, false)) # define XO_STUB() { XO_SCOPE(logr); logr.log("STUB"); } /* convenience class for basic_scope<..> construction (see below). * use to disambiguate setup from other arguments */ struct scope_setup { - scope_setup(std::string_view name1, std::string_view name2, bool enabled_flag) - : name1_{name1}, name2_{name2}, enabled_flag_{enabled_flag} {} - scope_setup(std::string_view name1, bool enabled_flag) - : scope_setup(name1, "", enabled_flag) {} - scope_setup(std::string_view name1) - : scope_setup(name1, true /*enabled_flag*/) {} + scope_setup(function_style style, std::string_view name1, std::string_view name2, bool enabled_flag) + : style_{style}, name1_{name1}, name2_{name2}, enabled_flag_{enabled_flag} {} + scope_setup(function_style style, std::string_view name1, bool enabled_flag) + : scope_setup(style, name1, "", enabled_flag) {} + scope_setup(function_style style, std::string_view name1) + : scope_setup(style, name1, true /*enabled_flag*/) {} + function_style style_ = FS_Pretty; std::string_view name1_ = "<.name1>"; std::string_view name2_ = "<.name2>"; bool enabled_flag_ = false; @@ -142,6 +143,8 @@ namespace xo { /* send indented output to this streambuf (e.g. std::clog.rdbuf()) */ std::streambuf * dest_sbuf_ = std::clog.rdbuf(); + /* style for displaying .name1 */ + function_style style_ = FS_Pretty; /* name of this scope (part 1) */ std::string_view name1_ = ""; /* name of this scope (part 2) */ @@ -154,14 +157,15 @@ namespace xo { template basic_scope::basic_scope(scope_setup setup, Tn&&... args) - : name1_{std::move(setup.name1_)}, + : style_{setup.style_}, + name1_{std::move(setup.name1_)}, name2_{std::move(setup.name2_)}, finalized_{!setup.enabled_flag_} { if(setup.enabled_flag_) { state_impl_type * logstate = basic_scope::require_thread_local_state(); - logstate->preamble(this->name1_, this->name2_); + logstate->preamble(this->style_, this->name1_, this->name2_); tosn(logstate2stream(logstate), " ", std::forward(args)...); @@ -240,7 +244,7 @@ namespace xo { logstate->decr_nesting(); - logstate->postamble(this->name1_, this->name2_); + logstate->postamble(this->style_, this->name1_, this->name2_); tosn(logstate2stream(logstate), " ", std::forward(args)...); From 59e7e19ccf232c07442486f325c91303b4edb19b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 15:22:14 -0400 Subject: [PATCH 013/170] nestlog: function printer (missed commit) --- include/nestlog/function.hpp | 190 +++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 include/nestlog/function.hpp diff --git a/include/nestlog/function.hpp b/include/nestlog/function.hpp new file mode 100644 index 00000000..da6a3f6e --- /dev/null +++ b/include/nestlog/function.hpp @@ -0,0 +1,190 @@ +/* @file function.hpp */ + +#include +#include + +namespace xo { + enum function_style { + /* literal: print given name, no alterations */ + FS_Literal, + /* pretty: print name, surrounded by [] */ + FS_Pretty, + /* streamlined: remove extraneous detail, try to print something like class::method */ + FS_Streamlined, + /* simple: remove everything except function/method name */ + FS_Simple + }; + + /* Tag to drive header-only expression */ + template + class function_name_impl { + public: + function_name_impl(function_style style, + std::string_view pretty) + : style_{style}, pretty_{pretty} {} + + function_style style() const { return style_; } + std::string_view const & pretty() const { return pretty_; } + + /* e.g. + * std::vector xo::sometemplateclass::fib(int, char**) + * ^ ^ + * p q + */ + static void print_simple(std::ostream & os, std::string_view const & s) { + std::size_t p = exclude_return_type(s); + std::string_view s2 = s.substr(p); + std::size_t q = find_toplevel_sep(s2, true /*last_flag*/); + + print_aux(os, s2.substr(q)); + } /*print_simple*/ + + /* e.g. + * std::vector xo::sometemplateclass::fib(int, char**) + * ^ ^ + * p q + */ + static void print_streamlined(std::ostream & os, std::string_view const & s) { + std::size_t p = exclude_return_type(s); + std::string_view s2 = s.substr(p); + std::size_t q = find_toplevel_sep(s2, false /*!last_flag*/); + + print_aux(os, s2.substr(q)); + } /*print_streamlined*/ + + private: + static std::size_t exclude_return_type(std::string_view const & s) { + /* strategy: + * - scan right-to-left + * - ignore anything between matching <>, () pairs (i.e. anything nested) + * - stop at rightmost toplevel space --> return suffix following that space + */ + std::size_t nesting_level = 0; + + std::size_t z = s.size(); + for (std::size_t rp = 0; rp < z; ++rp) { + std::size_t p = z-1-rp; + char ch = s[p]; + + if (ch == '<' || ch == '(') + ++nesting_level; + + if (nesting_level == 0) { + if (ch == ' ') + return p + 1; + } + + if (ch == '>' || ch == ')') + --nesting_level; + } + + return 0; + } /*exclude_return_type*/ + + /* e.g. + * xo::ns::someclass::somemethod(xo::enum1, std::vector) + * ^ + * return this pos + * + * last_flag: return pos after last :: + * !last_flag: return pos after 2nd-last :: + */ + static std::size_t find_toplevel_sep(std::string_view const & s, bool last_flag) { + /* strategy: + * - scan left-to-right + * - ignore anything between matching <>, () pairs (i.e. anything nested) + * - count :: pairs + * - remember 2nd-last :: pair; reports pos just after it + * + * note: + * - if no :: pairs, or only one such pair, return 0 + */ + std::size_t nesting_level = 0; + + std::size_t pos_after_last_sep = 0; + std::size_t pos_after_2ndlast_sep = 0; + + for (std::size_t p = 0; p < s.size(); ++p) { + char ch = s[p]; + + if (ch == '<' || ch == '(') + ++nesting_level; + + if (nesting_level == 0) { + if ((ch == ':') + && (p+1 < s.size()) + && s[p+1] == ':') + { + pos_after_2ndlast_sep = pos_after_last_sep; + pos_after_last_sep = p+2; + ++p; /* skipping 1st : in separator */ + } + } + + if (ch == '>' || ch == ')') + --nesting_level; + } + + return last_flag ? pos_after_last_sep : pos_after_2ndlast_sep; + } /*find_toplevel_sep*/ + + /* fib(int, char **) --> fib + * quux(std::vector>) -> quux + * foo::bar>() -> foo::bar + */ + static void print_aux(std::ostream & os, std::string_view const & s) { + //std::cerr << "print_aux: s=" << s << std::endl; + + /* strategy: + * - print left-to-right, omit anything between matching <> or () pairs. + * - don't keep track of which is which, so would also match < with ) etc; + * this acceptable since pretty functions won't visit this corner case + */ + std::size_t nesting_level = 0; + + for (char ch : s) { + if (ch == '<' || ch == '(') + ++nesting_level; + + if (nesting_level == 0) + os << ch; + + if (ch == '>' || ch == ')') + --nesting_level; + } + } /*print_aux*/ + + private: + /* FS_Simple | FS_Pretty (= FS_Literal) | FS_Streamlined */ + function_style style_; + /* e.g. __PRETTY_FUNCTION__ */ + std::string_view pretty_; + }; /*function_name_impl*/ + + using function_name = function_name_impl; + + inline std::ostream & + operator<<(std::ostream & os, + function_name const & fn) + { + switch(fn.style()) { + case FS_Literal: + os << fn.pretty(); + break; + case FS_Pretty: + os << "[" << fn.pretty() << "]"; + break; + case FS_Simple: + function_name::print_simple(os, fn.pretty()); + break; + case FS_Streamlined: + /* omit namespace qualifiers and template arguments */ + function_name::print_streamlined(os, fn.pretty()); + break; + } + + return os; + } /*operator<<*/ +} /*namespace xo*/ + +/* end function.hpp */ From 1c6fffd048c89009ad3e913ecd1c8d4d7c9c5797 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 15:36:11 -0400 Subject: [PATCH 014/170] nestlog: elaborate example ex3 --- example/ex3/ex3.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 58d81dc7..1b3cc8f7 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -6,16 +6,16 @@ using namespace xo; int fib(int n) { - scope log(XO_SSETUP0(), ":n ", n); + scope log(XO_ENTER0(), xtag("n", n)); int retval = 1; if (n >= 2) { retval = fib(n - 1) + fib(n - 2); - log(":n ", n); + log(xtag("n", n)); } - log.end_scope("<- :retval ", retval); + log.end_scope("<-", xtag("retval", retval)); return retval; } @@ -27,10 +27,10 @@ main(int argc, char ** argv) { int n = 4; - scope log(XO_SSETUP0(), ":n ", 4); + scope log(XO_ENTER0(), ":n ", 4); int fn = fib(n); - log(":n ", n); - log("<- :fib(n) ", fn); + log(xtag("n", n)); + log("<-", xtag("fib(n)", fn)); } From f9c583973c3e1c2c8d5689680bdad24991267057 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 15:36:37 -0400 Subject: [PATCH 015/170] nestlog: + XO_ENTER0(), XO_ENTER1() --- include/nestlog/scope.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp index cd3219fe..bb0d0854 100644 --- a/include/nestlog/scope.hpp +++ b/include/nestlog/scope.hpp @@ -15,6 +15,9 @@ namespace xo { template class state_impl; +# define XO_ENTER0() xo::scope_setup(log_config::style, __PRETTY_FUNCTION__) +# define XO_ENTER1(debug_flag) xo::scope_setup(log_config::style, __PRETTY_FUNCTION__, debug_flag) + //# define XO_SSETUP0() xo::scope_setup(__FUNCTION__) # define XO_SSETUP0() xo::scope_setup(log_config::style, __PRETTY_FUNCTION__) @@ -23,7 +26,7 @@ namespace xo { /* establish scope using current function name */ # define XO_SCOPE(name) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__)) /* like XO_SCOPE(name), but also set enabled flag */ -# define XOf_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__, debug_flag)) +# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__, debug_flag)) # define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__, false)) # define XO_STUB() { XO_SCOPE(logr); logr.log("STUB"); } @@ -38,6 +41,8 @@ namespace xo { scope_setup(function_style style, std::string_view name1) : scope_setup(style, name1, true /*enabled_flag*/) {} + static scope_setup literal(std::string_view name1, bool enabled_flag = true) { return scope_setup(FS_Literal, name1, enabled_flag); } + function_style style_ = FS_Pretty; std::string_view name1_ = "<.name1>"; std::string_view name2_ = "<.name2>"; From f7c19c338fd8056db7ddd2cbbbe76ece3ca2c3ff Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 12 Sep 2023 16:42:10 -0400 Subject: [PATCH 016/170] nestlog: minor scope fixes --- include/nestlog/scope.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp index bb0d0854..2648f483 100644 --- a/include/nestlog/scope.hpp +++ b/include/nestlog/scope.hpp @@ -15,19 +15,19 @@ namespace xo { template class state_impl; -# define XO_ENTER0() xo::scope_setup(log_config::style, __PRETTY_FUNCTION__) -# define XO_ENTER1(debug_flag) xo::scope_setup(log_config::style, __PRETTY_FUNCTION__, debug_flag) +# define XO_ENTER0() xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__) +# define XO_ENTER1(debug_flag) xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, debug_flag) //# define XO_SSETUP0() xo::scope_setup(__FUNCTION__) -# define XO_SSETUP0() xo::scope_setup(log_config::style, __PRETTY_FUNCTION__) +# define XO_SSETUP0() xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__) /* throw exception if condition not met*/ # define XO_EXPECT(f,msg) if(!(f)) { throw std::runtime_error(msg); } /* establish scope using current function name */ -# define XO_SCOPE(name) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__)) +# define XO_SCOPE(name) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__)) /* like XO_SCOPE(name), but also set enabled flag */ -# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__, debug_flag)) -# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(log_config::style, __PRETTY_FUNCTION__, false)) +# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, debug_flag)) +# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, false)) # define XO_STUB() { XO_SCOPE(logr); logr.log("STUB"); } /* convenience class for basic_scope<..> construction (see below). @@ -42,6 +42,7 @@ namespace xo { : scope_setup(style, name1, true /*enabled_flag*/) {} static scope_setup literal(std::string_view name1, bool enabled_flag = true) { return scope_setup(FS_Literal, name1, enabled_flag); } + static scope_setup literal(std::string_view name1, std::string_view name2, bool enabled_flag = true) { return scope_setup(FS_Literal, name1, name2, enabled_flag); } function_style style_ = FS_Pretty; std::string_view name1_ = "<.name1>"; From a150913045861407db7866cfeb96ce53a847d8b5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 14 Sep 2023 17:02:50 -0400 Subject: [PATCH 017/170] nestlog: print [file:line] on rhs of log line --- example/ex3/ex3.cpp | 3 ++ include/nestlog/filename.hpp | 70 +++++++++++++++++++++++++++++ include/nestlog/log_config.hpp | 12 +++++ include/nestlog/log_state.hpp | 75 ++++++++++++++++++++++++++----- include/nestlog/log_streambuf.hpp | 36 +++++++-------- include/nestlog/scope.hpp | 52 ++++++++++++++------- 6 files changed, 204 insertions(+), 44 deletions(-) create mode 100644 include/nestlog/filename.hpp diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 1b3cc8f7..05a3c9e4 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -24,6 +24,7 @@ int main(int argc, char ** argv) { log_config::style = FS_Pretty; log_config::indent_width = 4; + log_config::location_tab = 40; int n = 4; @@ -34,3 +35,5 @@ main(int argc, char ** argv) { log(xtag("n", n)); log("<-", xtag("fib(n)", fn)); } + +/* ex3/ex3.cpp */ diff --git a/include/nestlog/filename.hpp b/include/nestlog/filename.hpp new file mode 100644 index 00000000..ead3b65e --- /dev/null +++ b/include/nestlog/filename.hpp @@ -0,0 +1,70 @@ +/* @file filename.hpp */ + +#pragma once + +#include +#include + +namespace xo { + /* Example: + * os << basename("/path/to/basename.cpp") + * prints + * basename.cpp + * on os + */ + + /* Tag to drive header-only expression */ + template + class basename_impl { + public: + basename_impl(std::string_view path) + : path_{path} {} + + std::string_view const & path() const { return path_; } + + /* /home/roland/proj/nestlog/include/nestlog/filename.hpp + * <-basename-> + */ + static void print_basename(std::ostream & os, std::string_view const & s) { + std::size_t p = exclude_dirname(s); + + os << s.substr(p); + } /*print_basename*/ + + private: + static std::size_t exclude_dirname(std::string_view const & s) { + std::size_t z = s.size(); + + if (z == 0) + return 0; + + if (s[z-1] == '/') { + /* ignore trailing '/' */ + return exclude_dirname(s.substr(0, z-1)); + } + + std::size_t p = s.find_last_of('/'); + + if (p == std::string_view::npos) + return 0; + else + return p + 1; + } /*exclude_dirname*/ + + private: + /* some unix pathname, e.g. [/home/roland/proj/nestlog/include/nestlog/filename.hpp] */ + std::string_view path_; + }; /*basename_impl*/ + + using basename = basename_impl; + + inline std::ostream & + operator<<(std::ostream & os, + basename const & bn) + { + basename::print_basename(os, bn.path()); + return os; + } +} /*xo*/ + +/* end filename.hpp */ diff --git a/include/nestlog/log_config.hpp b/include/nestlog/log_config.hpp index ce28665f..d6da65da 100644 --- a/include/nestlog/log_config.hpp +++ b/include/nestlog/log_config.hpp @@ -13,6 +13,10 @@ namespace xo { static std::uint32_t indent_width; /* display style for function names. FS_Simple|FS_Pretty|FS_Streamlined */ static function_style style; + /* if true, append [file:line] to output */ + static bool location_enabled; + /* when .location_enabled, write [file:line] starting this many chars from left margin */ + static std::uint32_t location_tab; }; /*log_config_impl*/ template @@ -23,6 +27,14 @@ namespace xo { function_style log_config_impl::style = FS_Streamlined; + template + bool + log_config_impl::location_enabled = true; + + template + std::uint32_t + log_config_impl::location_tab = 80; + using log_config = log_config_impl; } /*namespace xo*/ diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index 59c3b4f6..73b77960 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -5,7 +5,9 @@ #include "log_config.hpp" #include "log_streambuf.hpp" #include "pad.hpp" +#include "filename.hpp" #include +#include #include // for std::unique_ptr namespace xo { @@ -42,6 +44,12 @@ namespace xo { p_sbuf_phase2_->reset_stream(); } + void set_location(std::string_view file, std::uint32_t line) { + this->location_flag_ = true; + this->file_ = std::move(file); + this->line_ = line; + } /*set_location*/ + private: /* common implementation for .preamble(), .postamble() */ void entryexit_aux(function_style style, @@ -59,6 +67,21 @@ namespace xo { */ std::unique_ptr p_sbuf_phase1_; + /* #of characters found in .p_sbuf_phase1 since last \n. + * this value is established+updated in .flush2sbuf(). + * (in particular ignored by stream .ss()) + */ + std::size_t lpos_ = 0; + + /* whenever .set_location() is called: + * - capture (file, line) + * - print them near right margin with next output line + * - ..and reset .location_flag + */ + bool location_flag_ = false; + std::string_view file_; + std::uint32_t line_ = 0; + /* buffer space for handling scope::log() calls that span multiple lines; * inserts extra characters in effort to indent gracefully */ @@ -99,11 +122,6 @@ namespace xo { /* indent to nesting level */ this->ss_ << pad(this->nesting_level_ * log_config::indent_width, pad_char); -#ifdef OBSOLETE - for(uint32_t i = 0, n = this->nesting_level_; iss_ << pad_char; - } -#endif } /*indent*/ template @@ -124,7 +142,7 @@ namespace xo { if (log_config::indent_width > 1) this->ss_ << ' '; - /* scope name */ + /* scope name - note no trailing newline; expect .preamble()/.postamble() caller to supply */ this->ss_ << function_name(style, name1) << name2; } /*entryexit_aux*/ @@ -153,12 +171,15 @@ namespace xo { log_streambuf_type * sbuf1 = this->p_sbuf_phase1_.get(); log_streambuf_type * sbuf2 = this->p_sbuf_phase2_.get(); - /* expecting sbuf to contain one line of output. + /* generally expecting sbuf to contain one line of output. * if it contains multiple newlines, need to indent * after each one. * * will scan output in *sbuf1, post-process to *sbuf2, - * then write *sbuf2 to clog + * then write *sbuf2 to output stream + * + * note: we inherit .lpos from prec call to .flush2sbuf(), + * in the unlikely event that it's non-zero */ char const * s = sbuf1->lo(); char const * e = s + sbuf1->pos(); @@ -177,6 +198,8 @@ namespace xo { /* for indenting, looking for first 'space following non-space, on first line', if any */ + std::size_t lpos_on_newline = 0; + while(p < e) { if(space_after_nonspace) { ; @@ -191,18 +214,50 @@ namespace xo { if(*p == '\n') { ++p; + /* reset .pos on newline */ + lpos_on_newline = this->lpos_; + this->lpos_ = 0; + break; } else { ++p; + + /* increment .lpos on non-newline */ + ++(this->lpos_); } } /* p=e or *p=\n */ /* charseq [s,p) does not contain any newlines, print it */ - sbuf2->sputn(s, p - s); + if (lpos_on_newline > 0) { + /* charseq [s,p) does not contain any newlines, print it */ + sbuf2->sputn(s, p - s - 1); - if(p == e) { + if (this->location_flag_) { + /* 'tab' to position 80 */ + sbuf2->sputc(' '); + for (std::uint32_t i = lpos_on_newline + 1; i < log_config::location_tab; ++i) + sbuf2->sputc(' '); + + std::stringstream ss; + ss << "[" << basename(this->file_) << ":" << this->line_ << "]"; + + std::string ss_str = std::move(ss.str()); /*c++20*/ + sbuf2->sputn(ss_str.c_str(), ss_str.size()); + + this->location_flag_ = false; + this->file_ = ""; + this->line_ = 0; + } + + sbuf2->sputc('\n'); + } else { + /* control here if .flush2sbuf() called without trailing newline in .p_sbuf_phase1 */ + sbuf2->sputn(s, p - s); + } + + if (p == e) { break; } diff --git a/include/nestlog/log_streambuf.hpp b/include/nestlog/log_streambuf.hpp index 02b4b183..3a467b82 100644 --- a/include/nestlog/log_streambuf.hpp +++ b/include/nestlog/log_streambuf.hpp @@ -36,30 +36,30 @@ namespace xo { protected: virtual std::streamsize xsputn(char const * s, std::streamsize n) override { - /* s must be an address in [this->lo() .. this->lo() + capacity()] */ + /* s must be an address in [this->lo() .. this->lo() + capacity()] */ - assert(this->hi() >= this->pptr()); + assert(this->hi() >= this->pptr()); #ifdef NOT_USING_DEBUG - std::cout << "xsputn: pbase=" << (void *)(this->pbase()) - << ", pptr=" << (void*)(this->pptr()) - << "(+" << (this->pptr() - this->lo()) << ")" - << ", n=" << n << " -> (+" << (this->pptr() + n - this->lo()) << ")" - << ", buf_v.size=" << this->buf_v_.size() - << std::endl; + std::cout << "xsputn: pbase=" << (void *)(this->pbase()) + << ", pptr=" << (void*)(this->pptr()) + << "(+" << (this->pptr() - this->lo()) << ")" + << ", n=" << n << " -> (+" << (this->pptr() + n - this->lo()) << ")" + << ", buf_v.size=" << this->buf_v_.size() + << std::endl; #endif - //std::cout << "xsputn: s=" << quoted(string_view(s, n)) << ", n=" << n << std::endl; + //std::cout << "xsputn: s=" << quoted(string_view(s, n)) << ", n=" << n << std::endl; - if (this->pptr() + n > this->hi()) { - n = this->hi() - this->pptr(); - std::memcpy(this->pptr(), s, n); - } else { - std::memcpy(this->pptr(), s, n); - } - this->pbump(n); + if (this->pptr() + n > this->hi()) { + n = this->hi() - this->pptr(); + std::memcpy(this->pptr(), s, n); + } else { + std::memcpy(this->pptr(), s, n); + } + this->pbump(n); - return n; - } /*xsputn*/ + return n; + } /*xsputn*/ virtual int_type overflow(int_type new_ch) override diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp index 2648f483..04451aaf 100644 --- a/include/nestlog/scope.hpp +++ b/include/nestlog/scope.hpp @@ -1,8 +1,9 @@ -/* @file scopẹhpp */ +/* @file scope.hpp */ #pragma once #include "log_state.hpp" +#include "filename.hpp" #include "tostr.hpp" #include "tag.hpp" @@ -15,38 +16,44 @@ namespace xo { template class state_impl; -# define XO_ENTER0() xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__) -# define XO_ENTER1(debug_flag) xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, debug_flag) +# define XO_ENTER0() xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) +# define XO_ENTER1(debug_flag) xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, debug_flag) //# define XO_SSETUP0() xo::scope_setup(__FUNCTION__) -# define XO_SSETUP0() xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__) +# define XO_SSETUP0() xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) /* throw exception if condition not met*/ # define XO_EXPECT(f,msg) if(!(f)) { throw std::runtime_error(msg); } /* establish scope using current function name */ -# define XO_SCOPE(name) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__)) +# define XO_SCOPE(name) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__)) /* like XO_SCOPE(name), but also set enabled flag */ -# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, debug_flag)) -# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, false)) +# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, debug_flag)) +# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, false)) # define XO_STUB() { XO_SCOPE(logr); logr.log("STUB"); } /* convenience class for basic_scope<..> construction (see below). * use to disambiguate setup from other arguments */ struct scope_setup { - scope_setup(function_style style, std::string_view name1, std::string_view name2, bool enabled_flag) - : style_{style}, name1_{name1}, name2_{name2}, enabled_flag_{enabled_flag} {} - scope_setup(function_style style, std::string_view name1, bool enabled_flag) - : scope_setup(style, name1, "", enabled_flag) {} - scope_setup(function_style style, std::string_view name1) - : scope_setup(style, name1, true /*enabled_flag*/) {} + scope_setup(function_style style, std::string_view name1, std::string_view name2, + std::string_view file, std::uint32_t line, bool enabled_flag) + : style_{style}, name1_{name1}, name2_{name2}, file_{file}, line_{line}, enabled_flag_{enabled_flag} {} + scope_setup(function_style style, std::string_view name1, std::string_view file, std::uint32_t line, bool enabled_flag) + : scope_setup(style, name1, "", file, line, enabled_flag) {} + scope_setup(function_style style, std::string_view name1, std::string_view file, std::uint32_t line) + : scope_setup(style, name1, file, line, true /*enabled_flag*/) {} - static scope_setup literal(std::string_view name1, bool enabled_flag = true) { return scope_setup(FS_Literal, name1, enabled_flag); } - static scope_setup literal(std::string_view name1, std::string_view name2, bool enabled_flag = true) { return scope_setup(FS_Literal, name1, name2, enabled_flag); } + //static scope_setup literal(std::string_view name1, bool enabled_flag = true) { return scope_setup(FS_Literal, name1, enabled_flag); } + //static scope_setup literal(std::string_view name1, std::string_view name2, bool enabled_flag = true) { return scope_setup(FS_Literal, name1, name2, enabled_flag); } function_style style_ = FS_Pretty; std::string_view name1_ = "<.name1>"; std::string_view name2_ = "<.name2>"; + /* __FILE__ */ + std::string_view file_ = "<.file>"; + /* __LINE__ */ + std::uint32_t line_ = 0; + /* true iff output enabled for this scope */ bool enabled_flag_ = false; }; /*scope_setup*/ @@ -155,6 +162,10 @@ namespace xo { std::string_view name1_ = ""; /* name of this scope (part 2) */ std::string_view name2_ = "::"; + /* captured value of __FILE__ */ + std::string_view file_ = ""; + /* captured value of __LINE__ */ + std::uint32_t line_ = 0; /* set once per scope .finalized=true <-> logging disabled */ bool finalized_ = false; }; /*basic_scope*/ @@ -166,14 +177,23 @@ namespace xo { : style_{setup.style_}, name1_{std::move(setup.name1_)}, name2_{std::move(setup.name2_)}, + file_{std::move(setup.file_)}, + line_{setup.line_}, finalized_{!setup.enabled_flag_} { if(setup.enabled_flag_) { state_impl_type * logstate = basic_scope::require_thread_local_state(); + std::ostream & os = logstate2stream(logstate); logstate->preamble(this->style_, this->name1_, this->name2_); - tosn(logstate2stream(logstate), " ", std::forward(args)...); + tosn(os, " ", std::forward(args)...); + + if (log_config::location_enabled) { + /* prints on next call to flush2sbuf */ + logstate->set_location(this->file_, this->line_); + //tosn(os, " [", basename(this->file_), ":", this->line_, "]"); + } logstate->flush2sbuf(std::clog.rdbuf()); From f7882b1ff21211693aa2ee6cb2b8c2144cba9975 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 14 Sep 2023 17:09:07 -0400 Subject: [PATCH 018/170] nestlog: + tag(), use to tidy ex3 --- example/ex3/ex3.cpp | 4 ++-- include/nestlog/tag.hpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 05a3c9e4..b4d1e9e1 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -6,13 +6,13 @@ using namespace xo; int fib(int n) { - scope log(XO_ENTER0(), xtag("n", n)); + scope log(XO_ENTER0(), tag("n", n)); int retval = 1; if (n >= 2) { retval = fib(n - 1) + fib(n - 2); - log(xtag("n", n)); + log(tag("n", n)); } log.end_scope("<-", xtag("retval", retval)); diff --git a/include/nestlog/tag.hpp b/include/nestlog/tag.hpp index 16a3e21a..7ac62023 100644 --- a/include/nestlog/tag.hpp +++ b/include/nestlog/tag.hpp @@ -25,6 +25,8 @@ namespace xo { struct tag_impl { tag_impl(Name const & n, Value const & v) : name_{n}, value_{v} {} + tag_impl(Name && n, Value && v) + : name_{std::move(n)}, value_{std::move(v)} {} Name const & name() const { return name_; } Value const & value() const { return value_; } @@ -67,6 +69,20 @@ namespace xo { return tag_impl(n, ""); } /*xtag_pre*/ + template + tag_impl + tag(Name && n, Value && v) + { + return tag_impl(n, v); + } /*tag*/ + + template + tag_impl + tag(char const * n, Value && v) + { + return tag_impl(n, v); + } /*tag*/ + template inline std::ostream & operator<<(std::ostream &s, From fd2be2a4aec400a83aa689b655e82c5ef072e153 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Sep 2023 13:24:02 -0400 Subject: [PATCH 019/170] nestlog: + terminal colors for entry/exit/code location --- example/ex3/ex3.cpp | 6 +- include/nestlog/code_location.hpp | 56 ++++++++++++++ include/nestlog/color.hpp | 123 ++++++++++++++++++++++++++++++ include/nestlog/function.hpp | 29 ++++++- include/nestlog/log_config.hpp | 26 +++++++ include/nestlog/log_state.hpp | 37 +++++++-- 6 files changed, 265 insertions(+), 12 deletions(-) create mode 100644 include/nestlog/code_location.hpp create mode 100644 include/nestlog/color.hpp diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index b4d1e9e1..64682a8a 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -22,9 +22,13 @@ fib(int n) { int main(int argc, char ** argv) { - log_config::style = FS_Pretty; + log_config::style = FS_Streamlined; log_config::indent_width = 4; log_config::location_tab = 40; + log_config::encoding = CE_Xterm; + log_config::function_entry_color = 69; + log_config::function_exit_color = 70; + log_config::code_location_color = 166; int n = 4; diff --git a/include/nestlog/code_location.hpp b/include/nestlog/code_location.hpp new file mode 100644 index 00000000..e343fb58 --- /dev/null +++ b/include/nestlog/code_location.hpp @@ -0,0 +1,56 @@ +/* @file code_location.hpp */ + +#pragma once + +#include "filename.hpp" +#include "color.hpp" + +namespace xo { + /* Example: + * os << code_location("/path/to/foo.cpp", 123) + * writes + * foo.cpp:123 + * on stream os + */ + + /* Tag to drive header-only expression */ + template + class code_location_impl { + public: + code_location_impl(std::string_view file, + std::uint32_t line, + color_encoding encoding = CE_Ansi, + std::uint32_t color = 31 /*red*/) + : file_{file}, line_{line}, encoding_{encoding}, color_{color} {} + + void print_code_location(std::ostream & os) const { + os << "[" + << with_color(encoding_, color_, basename(file_)) + << ":" + << line_ + << "]"; + } /*print_code_location*/ + + private: + /* __FILE__ */ + std::string_view file_; + /* __LINE__ */ + std::uint32_t line_ = 0; + /* color encoding for file,line */ + color_encoding encoding_ = CE_Ansi; + /* color for file,line */ + std::uint32_t color_ = 0; + }; /*code_location_impl*/ + + using code_location = code_location_impl; + + inline std::ostream & + operator<<(std::ostream & os, + code_location const & x) + { + x.print_code_location(os); + return os; + } +} /*namespace xo*/ + +/* end code_location.hpp */ diff --git a/include/nestlog/color.hpp b/include/nestlog/color.hpp new file mode 100644 index 00000000..8f5a4d74 --- /dev/null +++ b/include/nestlog/color.hpp @@ -0,0 +1,123 @@ +/* color.hpp */ + +#pragma once + +#include +//#include // for std::move +#include + +namespace xo { + enum color_encoding { + CE_None, + CE_Ansi, + CE_Xterm, + }; + + enum color_flags { + CF_None = 0x0, + CF_ColorOn = 0x01, + CF_Contents = 0x02, + CF_ColorOff = 0x04, + CF_All = 0x07 + }; + + template + class color_impl { + public: + color_impl(color_flags flags, color_encoding encoding, std::uint32_t color, Contents && contents) + : flags_{flags}, encoding_{encoding}, color_{color}, contents_{std::move(contents)} {} + + std::uint32_t color() const { return color_; } + Contents const & contents() const { return contents_; } + + void print(std::ostream & os) const { + if ((flags_ & CF_ColorOn) && (color_ > 0)) { + switch(encoding_) { + case CE_Ansi: + os << "\033[" << color_ << "m"; + break; + case CE_Xterm: + os << "\033[38;5;" << color_ << "m"; + break; + } + } + + if (flags_ & CF_Contents) + os << contents_; + + if ((flags_ & CF_ColorOff) && (color_ > 0)) + os << "\033[0m"; + } /*print*/ + + private: + color_flags flags_ = CF_None; + + color_encoding encoding_ = CE_Ansi; + /* .encoding = CE_Ansi: + * 0 = no color + * 30 = black + * 31 = red + * 32 = green + * 33 = yellow + * 34 = blue + * 35 = magenta + * 36 = cyan + * + * .encoding = CE_Xterm: + * see [[https://i.stack.imgur.com/KTSQa.png]] + * 0..7 standard colors (muted: grey, red, green, yellow, blue, pink, cyan, white) + * 8..15 high-intensity colors (grey, red, green, yellow, blue, pink, cyan, white) + * 16..51 chooses hue + * 16..51 + (0..5)x36 increases whiteness + */ + std::uint32_t color_ = 0; + + Contents contents_; + }; /*color_impl*/ + + template + color_impl with_ansi_color(std::uint32_t color, Contents && contents) { + return color_impl(CF_All, CE_Ansi, color, std::move(contents)); + } /*with_ansi_color*/ + + template + color_impl with_xterm_color(std::uint32_t color, Contents && contents) { + return color_impl(CF_All, CE_Xterm, color, std::move(contents)); + } /*with_ansi_color*/ + + template + color_impl with_color(color_encoding encoding, std::uint32_t color, Contents && contents) { + return color_impl(CF_All, encoding, color, std::move(contents)); + } /*with_color*/ + + inline color_impl + color_on_ansi(std::uint32_t color) { + return color_impl(CF_ColorOn, CE_Ansi, color, 0); + } /*color_on_ansi*/ + + inline color_impl + color_on_xterm(std::uint32_t color) { + return color_impl(CF_ColorOn, CE_Xterm, color, 0); + } /*color_on_xterm*/ + + inline color_impl + color_on(color_encoding encoding, std::uint32_t color) { + return color_impl(CF_ColorOn, encoding, color, 0); + } /*color_on*/ + + inline color_impl + color_off() { + /* any non-zero value works here for color */ + return color_impl(CF_ColorOff, CE_None, 1 /*color*/, 0); + } /*color_off*/ + + template + inline std::ostream & + operator<<(std::ostream & os, color_impl const & x) { + x.print(os); + return os; + } /*operator<<*/ + +} /*namespace xo*/ + +/* end color.hpp */ diff --git a/include/nestlog/function.hpp b/include/nestlog/function.hpp index da6a3f6e..42c5752f 100644 --- a/include/nestlog/function.hpp +++ b/include/nestlog/function.hpp @@ -1,5 +1,7 @@ /* @file function.hpp */ +#include "color.hpp" + #include #include @@ -19,11 +21,19 @@ namespace xo { template class function_name_impl { public: + /* color: ANSI escape color (lookup Select Graphic Rendition subset) + * 0 = none + * 31 = red + */ function_name_impl(function_style style, - std::string_view pretty) - : style_{style}, pretty_{pretty} {} + color_encoding encoding, + std::uint32_t color, + std::string_view pretty) + : style_{style}, encoding_{encoding}, color_{color}, pretty_{pretty} {} function_style style() const { return style_; } + color_encoding encoding() const { return encoding_; } + std::uint32_t color() const { return color_; } std::string_view const & pretty() const { return pretty_; } /* e.g. @@ -152,11 +162,16 @@ namespace xo { if (ch == '>' || ch == ')') --nesting_level; } + } /*print_aux*/ private: /* FS_Simple | FS_Pretty (= FS_Literal) | FS_Streamlined */ function_style style_; + /* CE_Ansi | CE_Xterm */ + color_encoding encoding_; + /* color, if non-zero */ + std::uint32_t color_; /* e.g. __PRETTY_FUNCTION__ */ std::string_view pretty_; }; /*function_name_impl*/ @@ -167,19 +182,25 @@ namespace xo { operator<<(std::ostream & os, function_name const & fn) { + /* set text color */ + switch(fn.style()) { case FS_Literal: - os << fn.pretty(); + os << with_color(fn.encoding(), fn.color(), fn.pretty()); break; case FS_Pretty: - os << "[" << fn.pretty() << "]"; + os << "[" << with_color(fn.encoding(), fn.color(), fn.pretty()) << "]"; break; case FS_Simple: + os << color_on(fn.encoding(), fn.color()); function_name::print_simple(os, fn.pretty()); + os << color_off(); break; case FS_Streamlined: /* omit namespace qualifiers and template arguments */ + os << color_on(fn.encoding(), fn.color()); function_name::print_streamlined(os, fn.pretty()); + os << color_off(); break; } diff --git a/include/nestlog/log_config.hpp b/include/nestlog/log_config.hpp index d6da65da..3046ef44 100644 --- a/include/nestlog/log_config.hpp +++ b/include/nestlog/log_config.hpp @@ -3,6 +3,7 @@ #pragma once #include "function.hpp" +#include "nestlog/color.hpp" #include namespace xo { @@ -13,10 +14,19 @@ namespace xo { static std::uint32_t indent_width; /* display style for function names. FS_Simple|FS_Pretty|FS_Streamlined */ static function_style style; + /* color encoding */ + static color_encoding encoding; + /* color to use for function name, on entry/exit (xo::scope creation/destruction) + * (ansi color codes, see Select Graphics Rendition subset) + */ + static std::uint32_t function_entry_color; + static std::uint32_t function_exit_color; /* if true, append [file:line] to output */ static bool location_enabled; /* when .location_enabled, write [file:line] starting this many chars from left margin */ static std::uint32_t location_tab; + /* color to use for code location */ + static std::uint32_t code_location_color; }; /*log_config_impl*/ template @@ -27,6 +37,18 @@ namespace xo { function_style log_config_impl::style = FS_Streamlined; + template + color_encoding + log_config_impl::encoding = CE_Ansi; + + template + std::uint32_t + log_config_impl::function_entry_color = 34; + + template + std::uint32_t + log_config_impl::function_exit_color = 32; + template bool log_config_impl::location_enabled = true; @@ -35,6 +57,10 @@ namespace xo { std::uint32_t log_config_impl::location_tab = 80; + template + std::uint32_t + log_config_impl::code_location_color = 31; + using log_config = log_config_impl; } /*namespace xo*/ diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index 73b77960..fa48adf6 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -6,11 +6,17 @@ #include "log_streambuf.hpp" #include "pad.hpp" #include "filename.hpp" +#include "code_location.hpp" #include #include #include // for std::unique_ptr namespace xo { + enum EntryExit { + EE_Entry, + EE_Exit + }; + // track per-thread state associated with nesting logger // template @@ -55,7 +61,7 @@ namespace xo { void entryexit_aux(function_style style, std::string_view name1, std::string_view name2, - char label_char); + EntryExit entryexit); private: /* current nesting level for this thread */ @@ -129,21 +135,37 @@ namespace xo { state_impl::entryexit_aux(function_style style, std::string_view name1, std::string_view name2, - char label_char) + EntryExit entryexit) { log_streambuf_type * sbuf = this->p_sbuf_phase1_.get(); sbuf->reset_stream(); this->indent(' '); + char ee_label = '\0'; + std::uint32_t fn_color = 0; + + color_encoding encoding = log_config::encoding; + /* mnemonic for scope entry/exit */ - this->ss_ << label_char; + switch(entryexit) { + case EE_Entry: + ee_label = '+'; + fn_color = log_config::function_entry_color; + break; + case EE_Exit: + ee_label = '-'; + fn_color = log_config::function_exit_color; + break; + } + + this->ss_ << ee_label; if (log_config::indent_width > 1) this->ss_ << ' '; /* scope name - note no trailing newline; expect .preamble()/.postamble() caller to supply */ - this->ss_ << function_name(style, name1) << name2; + this->ss_ << function_name(style, encoding, fn_color, name1) << name2; } /*entryexit_aux*/ template @@ -152,7 +174,7 @@ namespace xo { std::string_view name1, std::string_view name2) { - this->entryexit_aux(style, name1, name2, '+' /*label_char*/); + this->entryexit_aux(style, name1, name2, EE_Entry); } /*preamble*/ template @@ -161,7 +183,7 @@ namespace xo { std::string_view name1, std::string_view name2) { - this->entryexit_aux(style, name1, name2, '-' /*label_char*/); + this->entryexit_aux(style, name1, name2, EE_Exit); } /*postamble*/ template @@ -241,7 +263,8 @@ namespace xo { sbuf2->sputc(' '); std::stringstream ss; - ss << "[" << basename(this->file_) << ":" << this->line_ << "]"; + ss << code_location(this->file_, this->line_, + log_config::encoding, log_config::code_location_color); std::string ss_str = std::move(ss.str()); /*c++20*/ sbuf2->sputn(ss_str.c_str(), ss_str.size()); From 5a47539dbbd81881290005fc133d224c0c0629ab Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Sep 2023 15:25:17 -0400 Subject: [PATCH 020/170] nestlog: + explicit+max indent width --- example/ex3/ex3.cpp | 8 ++++---- include/nestlog/color.hpp | 8 ++++---- include/nestlog/log_config.hpp | 20 +++++++++++++++++++- include/nestlog/log_state.hpp | 32 ++++++++++++++++++++++++-------- 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 64682a8a..89d7ad2c 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -12,10 +12,9 @@ fib(int n) { if (n >= 2) { retval = fib(n - 1) + fib(n - 2); - log(tag("n", n)); } - log.end_scope("<-", xtag("retval", retval)); + log.end_scope(tag("n", n), " <-", xtag("retval", retval)); return retval; } @@ -24,7 +23,8 @@ int main(int argc, char ** argv) { log_config::style = FS_Streamlined; log_config::indent_width = 4; - log_config::location_tab = 40; + log_config::max_indent_width = 14; + log_config::location_tab = 70; log_config::encoding = CE_Xterm; log_config::function_entry_color = 69; log_config::function_exit_color = 70; @@ -36,7 +36,7 @@ main(int argc, char ** argv) { int fn = fib(n); - log(xtag("n", n)); + xtag("n", n); log("<-", xtag("fib(n)", fn)); } diff --git a/include/nestlog/color.hpp b/include/nestlog/color.hpp index 8f5a4d74..2c2419c2 100644 --- a/include/nestlog/color.hpp +++ b/include/nestlog/color.hpp @@ -25,7 +25,7 @@ namespace xo { class color_impl { public: color_impl(color_flags flags, color_encoding encoding, std::uint32_t color, Contents && contents) - : flags_{flags}, encoding_{encoding}, color_{color}, contents_{std::move(contents)} {} + : flags_{flags}, encoding_{encoding}, color_{color}, contents_{std::forward(contents)} {} std::uint32_t color() const { return color_; } Contents const & contents() const { return contents_; } @@ -77,17 +77,17 @@ namespace xo { template color_impl with_ansi_color(std::uint32_t color, Contents && contents) { - return color_impl(CF_All, CE_Ansi, color, std::move(contents)); + return color_impl(CF_All, CE_Ansi, color, std::forward(contents)); } /*with_ansi_color*/ template color_impl with_xterm_color(std::uint32_t color, Contents && contents) { - return color_impl(CF_All, CE_Xterm, color, std::move(contents)); + return color_impl(CF_All, CE_Xterm, color, std::forward(contents)); } /*with_ansi_color*/ template color_impl with_color(color_encoding encoding, std::uint32_t color, Contents && contents) { - return color_impl(CF_All, encoding, color, std::move(contents)); + return color_impl(CF_All, encoding, color, std::forward(contents)); } /*with_color*/ inline color_impl diff --git a/include/nestlog/log_config.hpp b/include/nestlog/log_config.hpp index 3046ef44..cf5ea3aa 100644 --- a/include/nestlog/log_config.hpp +++ b/include/nestlog/log_config.hpp @@ -10,8 +10,14 @@ namespace xo { /* Tag here b/c we want header-only library */ template struct log_config_impl { - /* spaces per indent level */ + /* spaces per nesting level */ static std::uint32_t indent_width; + /* max #of spaces to introduce when indenting */ + static std::uint32_t max_indent_width; + /* if true enable explicit nesting level display [nnn] */ + static bool nesting_level_enabled; + /* color to use for explicit nesting level */ + static std::uint32_t nesting_level_color; /* display style for function names. FS_Simple|FS_Pretty|FS_Streamlined */ static function_style style; /* color encoding */ @@ -33,6 +39,18 @@ namespace xo { std::uint32_t log_config_impl::indent_width = 1; + template + std::uint32_t + log_config_impl::max_indent_width = 32; + + template + bool + log_config_impl::nesting_level_enabled = true; + + template + std::uint32_t + log_config_impl::nesting_level_color = 195; + template function_style log_config_impl::style = FS_Streamlined; diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index fa48adf6..8273a6ec 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -126,8 +126,14 @@ namespace xo { } #endif - /* indent to nesting level */ - this->ss_ << pad(this->nesting_level_ * log_config::indent_width, pad_char); + /* indent to nesting level. + * + * note: see also flush2sbuf(), need special indent handling for continuation lines + * (when application sends explicit newlines to this logger) + */ + this->ss_ << pad(std::min(this->nesting_level_ * log_config::indent_width, + log_config::max_indent_width), + pad_char); } /*indent*/ template @@ -161,6 +167,15 @@ namespace xo { this->ss_ << ee_label; + if (log_config::nesting_level_enabled) { + this->ss_ + << "(" + << with_color(log_config::encoding, + log_config::nesting_level_color, + this->nesting_level_) + << ")"; + } + if (log_config::indent_width > 1) this->ss_ << ' '; @@ -257,7 +272,7 @@ namespace xo { sbuf2->sputn(s, p - s - 1); if (this->location_flag_) { - /* 'tab' to position 80 */ + /* 'tab' to position lpos for [file:line] */ sbuf2->sputc(' '); for (std::uint32_t i = lpos_on_newline + 1; i < log_config::location_tab; ++i) sbuf2->sputc(' '); @@ -280,9 +295,8 @@ namespace xo { sbuf2->sputn(s, p - s); } - if (p == e) { + if (p == e) break; - } // { // char buf[80]; @@ -293,14 +307,16 @@ namespace xo { /* at least 1 char following newline, need to indent for it * - minimum indent = nesting level; - * - however if space_after_nonspace defined, indent to that + * - however if space_after_nonspace defined, also indent for that */ - uint32_t n_indent = this->nesting_level_; + std::uint32_t n_indent = std::min(this->nesting_level_ * log_config::indent_width, + log_config::max_indent_width); + /* this is just to indent for per-line entry/exit label */ if(space_after_nonspace) n_indent += (space_after_nonspace - s); - for(uint32_t i = 0; i < n_indent; ++i) + for(std::uint32_t i = 0; i < n_indent; ++i) sbuf2->sputc(' '); s = p; From ad36c16d9156f14e6af2e15482f731b2feea65bd Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Sep 2023 16:30:34 -0400 Subject: [PATCH 021/170] nestlog: + time-of-day column --- example/ex3/ex3.cpp | 6 +- include/nestlog/log_config.hpp | 18 ++ include/nestlog/log_state.hpp | 33 ++- include/nestlog/scope.hpp | 5 + include/nestlog/time.hpp | 362 +++++++++++++++++++++++++++++++++ 5 files changed, 420 insertions(+), 4 deletions(-) create mode 100644 include/nestlog/time.hpp diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 89d7ad2c..a0507147 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -21,10 +21,12 @@ fib(int n) { int main(int argc, char ** argv) { + log_config::time_enabled = true; + log_config::time_local_flag = true; log_config::style = FS_Streamlined; log_config::indent_width = 4; log_config::max_indent_width = 14; - log_config::location_tab = 70; + log_config::location_tab = 80; log_config::encoding = CE_Xterm; log_config::function_entry_color = 69; log_config::function_exit_color = 70; @@ -36,7 +38,7 @@ main(int argc, char ** argv) { int fn = fib(n); - xtag("n", n); + log(tag("n", n)); log("<-", xtag("fib(n)", fn)); } diff --git a/include/nestlog/log_config.hpp b/include/nestlog/log_config.hpp index cf5ea3aa..fa0d3902 100644 --- a/include/nestlog/log_config.hpp +++ b/include/nestlog/log_config.hpp @@ -10,6 +10,12 @@ namespace xo { /* Tag here b/c we want header-only library */ template struct log_config_impl { + /* true to log local time */ + static bool time_enabled; + /* true to log time-of-day in local coords; false for UTC coords */ + static bool time_local_flag; + /* true to log time-of-day with microsecond precision; false for millisecond precision */ + static bool time_usec_flag; /* spaces per nesting level */ static std::uint32_t indent_width; /* max #of spaces to introduce when indenting */ @@ -35,6 +41,18 @@ namespace xo { static std::uint32_t code_location_color; }; /*log_config_impl*/ + template + bool + log_config_impl::time_enabled = 1; + + template + bool + log_config_impl::time_local_flag = true; + + template + bool + log_config_impl::time_usec_flag = true; + template std::uint32_t log_config_impl::indent_width = 1; diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index 8273a6ec..06999ccb 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -7,6 +7,7 @@ #include "pad.hpp" #include "filename.hpp" #include "code_location.hpp" +#include "time.hpp" #include #include #include // for std::unique_ptr @@ -146,6 +147,29 @@ namespace xo { log_streambuf_type * sbuf = this->p_sbuf_phase1_.get(); sbuf->reset_stream(); + + /* e.g: + * + * 14:38:19.914 + * ------------- + * 0123456789012 + * 0 1 + * + * (13 chars including trailing space) + */ + if (log_config::time_enabled) { + if (log_config::time_local_flag) { + if (log_config::time_usec_flag) + this->ss_ << xo::time::hms_usec::local(xo::time::time::now()) << " "; + else + this->ss_ << xo::time::hms_msec::local(xo::time::time::now()) << " "; + } else { + if (log_config::time_usec_flag) + this->ss_ << xo::time::hms_usec::utc(xo::time::time::now()) << " "; + else + this->ss_ << xo::time::hms_msec::utc(xo::time::time::now()) << " "; + } + } this->indent(' '); char ee_label = '\0'; @@ -309,8 +333,13 @@ namespace xo { * - minimum indent = nesting level; * - however if space_after_nonspace defined, also indent for that */ - std::uint32_t n_indent = std::min(this->nesting_level_ * log_config::indent_width, - log_config::max_indent_width); + std::uint32_t n_indent = 0; + + if (log_config::time_enabled) + n_indent += 13; /*strlen("14:38:19.974 ")*/ + + n_indent += std::min(this->nesting_level_ * log_config::indent_width, + log_config::max_indent_width); /* this is just to indent for per-line entry/exit label */ if(space_after_nonspace) diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp index 04451aaf..e343c9a3 100644 --- a/include/nestlog/scope.hpp +++ b/include/nestlog/scope.hpp @@ -118,6 +118,11 @@ namespace xo { } else { state_impl_type * logstate = require_indent_thread_local_state(); + /* indent for timestamp */ + if (log_config::time_enabled) + logstate->ss() << pad(13, ' '); + //logstate->indent(' '); + /* log to per-thread stream to prevent data races */ tosn(logstate2stream(logstate), std::forward(rest)...); diff --git a/include/nestlog/time.hpp b/include/nestlog/time.hpp new file mode 100644 index 00000000..04344195 --- /dev/null +++ b/include/nestlog/time.hpp @@ -0,0 +1,362 @@ +/* @file Time.hpp */ + +#pragma once + +#include +#include +#ifdef NOT_YET +# include +#endif +#include +#include +#include + +namespace xo { + namespace time { + + using utc_nanos = std::chrono::time_point; + + using nanos = std::chrono::nanoseconds; + using microseconds = std::chrono::microseconds; + using milliseconds = std::chrono::milliseconds; + using seconds = std::chrono::seconds; + using hours = std::chrono::hours; + using days = std::chrono::days; + + struct time { + static utc_nanos now() { + return utc_nanos(std::chrono::system_clock::now()); + } + + static utc_nanos epoch() { + return utc_nanos(std::chrono::system_clock::from_time_t(0)); + } /*epoch*/ + + static utc_nanos ymd_hms(uint32_t ymd, uint32_t hms) { + /* e.g. ymd=20220610 -> n_yr=2022, n_mon=06, n_dy=10 */ + + uint32_t n_yr = ymd / 10000; + uint32_t n_mon = (ymd % 10000) / 100; + uint32_t n_dy = ymd % 100; + + uint32_t n_hr = hms / 10000; + uint32_t n_min = (hms % 10000) / 100; + uint32_t n_sec = hms % 100; + + struct tm t; + + t.tm_year = n_yr - 1900; /* 0 means 1900 */ + t.tm_mon = n_mon - 1; /* 0 means january */ + t.tm_mday = n_dy; + + t.tm_hour = n_hr; /* 24 hour clock */ + t.tm_min = n_min; + t.tm_sec = n_sec; + + /* time since epoch */ + time_t epoch_time = timegm(&t); + + return std::chrono::system_clock::from_time_t(epoch_time); + } /*ymd_hms*/ + + /* midnight UTC on date ymd. + * e.g. ymd_midnight(20220707) -> midnight UTC on 7jul22 + */ + static utc_nanos ymd_midnight(uint32_t ymd) { + return ymd_hms(ymd, 0); + } /*ymd_midnight*/ + + static utc_nanos ymd_hms_usec(uint32_t ymd, uint32_t hms, uint32_t usec) { + utc_nanos s = ymd_hms(ymd, hms); + + return s + microseconds(usec); + } /*ymd_hms_usec*/ + + /* .first: UTC midnight on same calendar day as t0 + * .second: elapsed time from .first to t0 (i.e. UTC time-of-day for t0) + */ + static std::pair utc_split_vs_midnight(utc_nanos t0) { + using xo::time::microseconds; + using xo::time::utc_nanos; + + /* use yyyymmdd.hh:mm:ss.nnnnnn */ + + time_t t0_time_t = (std::chrono::system_clock::to_time_t + (std::chrono::time_point_cast(t0))); + + /* convert to std::tm, + * only provides 1-second precision + */ + std::tm t0_tm; + ::gmtime_r(&t0_time_t, &t0_tm); + + /* midnight on the same calendar day as t0_tm */ + std::tm midnight_tm = t0_tm; + { + midnight_tm.tm_hour = 0; + midnight_tm.tm_min = 0; + midnight_tm.tm_sec = 0; + } + + /* convert to UTC epoch seconds */ + time_t midnight_time_t = ::timegm(&midnight_tm); + + utc_nanos t0_midnight = + (std::chrono::time_point_cast( + std::chrono::system_clock::from_time_t(midnight_time_t))); + + nanos t0_tdy = t0 - t0_midnight; + + return std::pair(t0_midnight, t0_tdy); + } /*utc_split_vs_midnight*/ + + /* .first: LOCAL midnight on same calendar day as t0 (but in UTC coords) + * .second: elapsed time from .first to t0 (i.e. LOCAL time-of-day for t0) + */ + static std::pair local_split_vs_midnight(utc_nanos t0) { + using xo::time::microseconds; + using xo::time::utc_nanos; + + /* use yyyymmdd.hh:mm:ss.nnnnnn */ + + time_t t0_time_t = (std::chrono::system_clock::to_time_t + (std::chrono::time_point_cast(t0))); + + /* convert to std::tm, + * only provides 1-second precision + */ + std::tm t0_tm; + ::localtime_r(&t0_time_t, &t0_tm); + + /* midnight on the same calendar day as t0_tm */ + std::tm midnight_tm = t0_tm; + { + midnight_tm.tm_hour = 0; + midnight_tm.tm_min = 0; + midnight_tm.tm_sec = 0; + } + + /* convert local midnight to UTC epoch seconds */ + time_t midnight_time_t = ::timelocal(&midnight_tm); + + utc_nanos t0_midnight = + (std::chrono::time_point_cast( + std::chrono::system_clock::from_time_t(midnight_time_t))); + + nanos t0_tdy = t0 - t0_midnight; + + return std::pair(t0_midnight, t0_tdy); + } /*local_split_vs_midnight*/ + + /* split utc_nanos into + * std::tm + * .tm_year + * .tm_mon (1-12) + * .tm_mday (1-31) + * .tm_hour (0-23) + * .tm_min (0-59) + * .tm_sec (0-59) + * .tm_wday (0=sunday .. 6=saturday) + * .tm_yday (0=1jan .. 365) + * .tm_isdst (daylight savings time flag) + * usec (0-999999) + */ + static std::pair split_tm(utc_nanos t0) { + using xo::time::microseconds; + using xo::time::utc_nanos; + + /* use yyyymmdd.hh:mm:ss.nnnnnn */ + + time_t t0_time_t = (std::chrono::system_clock::to_time_t + (std::chrono::time_point_cast(t0))); + + /* convert to std::tm, un UTC coords, + * only provides 1-second precision + */ + std::tm t0_tm; + ::gmtime_r(&t0_time_t, &t0_tm); + + /* midnight on the same calendar day as t0_tm */ + std::tm midnight_tm = t0_tm; + + midnight_tm.tm_isdst = 0; + midnight_tm.tm_hour = 0; + midnight_tm.tm_min = 0; + midnight_tm.tm_sec = 0; + + /* convert back to epoch seconds */ + time_t midnight_time_t = ::mktime(&midnight_tm); + + utc_nanos t0_midnight = + (std::chrono::time_point_cast( + std::chrono::system_clock::from_time_t(midnight_time_t))); + + uint32_t usec = + (std::chrono::duration_cast( + std::chrono::hh_mm_ss(t0 - t0_midnight).subseconds())) + .count(); + + return std::make_pair(t0_tm, usec); + } /*split_tm*/ + + static void print_hms_msec(nanos dt, std::ostream & os) { + /* use hhmmss.nnn */ + using std::int32_t; + + auto hms = std::chrono::hh_mm_ss(dt); + int32_t h = hms.hours().count(); + int32_t m = hms.minutes().count(); + int32_t s = hms.seconds().count(); + int32_t msec = std::chrono::duration_cast(hms.subseconds()).count(); + + char buf[32]; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%03d", h, m, s, msec); + + os << buf; + } /*print_hms_msec*/ + + static void print_utc_hms_msec(utc_nanos t0, std::ostream & os) { + print_hms_msec(utc_split_vs_midnight(t0).second, os); + } /*print_utc_hms_usec*/ + + static void print_hms_usec(nanos dt, std::ostream & os) { + /* use hhmmss.uuuuuu */ + using std::int32_t; + + auto hms = std::chrono::hh_mm_ss(dt); + int32_t h = hms.hours().count(); + int32_t m = hms.minutes().count(); + int32_t s = hms.seconds().count(); + int32_t usec = std::chrono::duration_cast(hms.subseconds()).count(); + + char buf[32]; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06d", h, m, s, usec); + + os << buf; + } /*print_hms_usec*/ + + static void print_utc_ymd_hms_usec(utc_nanos t0, std::ostream & os) { + using xo::time::microseconds; + using xo::time::utc_nanos; + + /* use yyyymmdd.hh:mm:ss.nnnnnn */ + + //std::tm t0_tm; + //uint32_t t0_usec; + + /* (structured binding ftw!) */ + auto [t0_tm, t0_usec] = split_tm(t0); + + /* no std::format in clang11 afaict */ + char usec_buf[7]; + snprintf(usec_buf, sizeof(usec_buf), "%06d", t0_usec); + + + /* control string | example + * ----------------------------+-------------------------- + * %c - locale-specific string | Fri Jun 10 16:29:05 2022 + * %Y - year | 2022 + * %m - month | 06 + * %d - day of month | 10 + * %H - hour | 16 + * %M - minute | 29 + * %S - second | 05 + * %Z - timezone | UTC + */ + os << std::put_time(&t0_tm, "%Y%m%d:%H:%M:%S.") << usec_buf; + } /*print_utc_ymd_hms_usec*/ + + /* print datetime in format compatible with ISO 8601. + * copying the format javascript uses, e.g: + * 2012-04-23T18:25:43.511Z + */ + static void print_iso8601(utc_nanos t0, std::ostream & os) { + auto [t0_tm, t0_usec] = split_tm(t0); + + char msec_buf[8]; + snprintf(msec_buf, sizeof(msec_buf), "%03d", t0_usec / 1000); + + os << std::put_time(&t0_tm, "%Y-%m-%dT%H:%M:%S.") << msec_buf << "Z"; + } /*print_iso8601*/ + }; /*time*/ + + /* stream inserter that displays time in ISO 8601 format: + * 2012-04-23T18:25:43.511Z + */ + struct iso8601 { + iso8601(utc_nanos t0) : t0_{t0} {} + + utc_nanos t0_; + }; /*iso8601*/ + + inline std::ostream & + operator<<(std::ostream & os, + iso8601 x) + { + time::print_iso8601(x.t0_, os); + return os; + } /*operator<<*/ + + /* stream inserter that display time like: + * hh:mm:ss.nnn + */ + struct hms_msec { + hms_msec(nanos dt) : dt_{dt} {} + + static hms_msec utc(utc_nanos t0) { return hms_msec(time::utc_split_vs_midnight(t0).second); } + static hms_msec local(utc_nanos t0) { return hms_msec(time::local_split_vs_midnight(t0).second); } + + nanos dt_; + }; /*hms_msec*/ + + inline std::ostream & + operator<<(std::ostream & os, hms_msec x) + { + time::print_hms_msec(x.dt_, os); + return os; + } /*operator<<*/ + + + /* stream inserter that display time like: + * hh:mm:ss.nnnnnn + */ + struct hms_usec { + hms_usec(nanos dt) : dt_{dt} {} + + static hms_usec utc(utc_nanos t0) { return hms_usec(time::utc_split_vs_midnight(t0).second); } + static hms_usec local(utc_nanos t0) { return hms_usec(time::local_split_vs_midnight(t0).second); } + + nanos dt_; + }; /*hms_msec*/ + + inline std::ostream & + operator<<(std::ostream & os, hms_usec x) + { + time::print_hms_usec(x.dt_, os); + return os; + } /*operator<<*/ + + + } /*namespace time*/ +} /*namespace xo*/ + +namespace std { + namespace chrono { + inline std::ostream & operator<<(std::ostream & os, + xo::time::utc_nanos t0) + { + xo::time::time::print_utc_ymd_hms_usec(t0, os); + return os; + } /*operator<<*/ + + inline std::ostream & operator<<(std::ostream & os, + xo::time::nanos dt) + { + xo::time::time::print_hms_usec(dt, os); + return os; + } /*operator<<*/ + } /*namespace chrono*/ +} /*namespace std*/ + +/* end Time.hpp */ From 3e62cefe43e032926cd5ddba82248ffb5b65d35d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Sep 2023 16:32:35 -0400 Subject: [PATCH 022/170] nestlog: minor streamlining --- include/nestlog/log_state.hpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index 06999ccb..7384cec0 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -158,16 +158,23 @@ namespace xo { * (13 chars including trailing space) */ if (log_config::time_enabled) { + using xo::time::time; + using xo::time::utc_nanos; + using xo::time::hms_msec; + using xo::time::hms_usec; + + utc_nanos now_tm = time::now(); + if (log_config::time_local_flag) { if (log_config::time_usec_flag) - this->ss_ << xo::time::hms_usec::local(xo::time::time::now()) << " "; + this->ss_ << hms_usec::local(now_tm) << " "; else - this->ss_ << xo::time::hms_msec::local(xo::time::time::now()) << " "; + this->ss_ << hms_msec::local(now_tm) << " "; } else { if (log_config::time_usec_flag) - this->ss_ << xo::time::hms_usec::utc(xo::time::time::now()) << " "; + this->ss_ << hms_usec::utc(now_tm) << " "; else - this->ss_ << xo::time::hms_msec::utc(xo::time::time::now()) << " "; + this->ss_ << hms_msec::utc(now_tm) << " "; } } this->indent(' '); From f5a2ee1af515711684dd7a99cdc061987121d75a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Sep 2023 16:41:18 -0400 Subject: [PATCH 023/170] nestlog: refactor: streamline indenting for lhs timestamp --- include/nestlog/log_state.hpp | 68 +++++++++++++++++++---------------- include/nestlog/scope.hpp | 6 ++-- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index 7384cec0..fee193ec 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -24,6 +24,7 @@ namespace xo { class state_impl { public: using log_streambuf_type = log_streambuf>; + using utc_nanos = xo::time::utc_nanos; public: state_impl(); @@ -35,6 +36,40 @@ namespace xo { std::ostream & ss() { return ss_; } + void check_print_time(utc_nanos now_tm) { + using xo::time::time; + using xo::time::utc_nanos; + using xo::time::hms_msec; + using xo::time::hms_usec; + + if (log_config::time_local_flag) { + if (log_config::time_usec_flag) + this->ss_ << hms_usec::local(now_tm) << " "; + else + this->ss_ << hms_msec::local(now_tm) << " "; + } else { + if (log_config::time_usec_flag) + this->ss_ << hms_usec::utc(now_tm) << " "; + else + this->ss_ << hms_msec::utc(now_tm) << " "; + } + } /*check_print_time*/ + + /* space budget for time-of-day */ + std::size_t calc_time_indent() const { + if (log_config::time_enabled) { + /*strlen("14:38:19.974 ")*/ + return 13; + } else { + return 0; + } + } /*calc_time_indent*/ + + void time_indent() { + if (log_config::time_enabled) + this->ss_ << pad(this->calc_time_indent(), ' '); + } /*time_indent*/ + /* call on entry to new scope */ void preamble(function_style style, std::string_view name1, std::string_view name2); /* call before each new log entry */ @@ -148,35 +183,7 @@ namespace xo { sbuf->reset_stream(); - /* e.g: - * - * 14:38:19.914 - * ------------- - * 0123456789012 - * 0 1 - * - * (13 chars including trailing space) - */ - if (log_config::time_enabled) { - using xo::time::time; - using xo::time::utc_nanos; - using xo::time::hms_msec; - using xo::time::hms_usec; - - utc_nanos now_tm = time::now(); - - if (log_config::time_local_flag) { - if (log_config::time_usec_flag) - this->ss_ << hms_usec::local(now_tm) << " "; - else - this->ss_ << hms_msec::local(now_tm) << " "; - } else { - if (log_config::time_usec_flag) - this->ss_ << hms_usec::utc(now_tm) << " "; - else - this->ss_ << hms_msec::utc(now_tm) << " "; - } - } + this->check_print_time(xo::time::time::now()); this->indent(' '); char ee_label = '\0'; @@ -342,8 +349,7 @@ namespace xo { */ std::uint32_t n_indent = 0; - if (log_config::time_enabled) - n_indent += 13; /*strlen("14:38:19.974 ")*/ + n_indent += this->calc_time_indent(); n_indent += std::min(this->nesting_level_ * log_config::indent_width, log_config::max_indent_width); diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp index e343c9a3..848e9d4e 100644 --- a/include/nestlog/scope.hpp +++ b/include/nestlog/scope.hpp @@ -118,10 +118,8 @@ namespace xo { } else { state_impl_type * logstate = require_indent_thread_local_state(); - /* indent for timestamp */ - if (log_config::time_enabled) - logstate->ss() << pad(13, ' '); - //logstate->indent(' '); + /* indent for timestamp (not printed on this line) */ + logstate->time_indent(); /* log to per-thread stream to prevent data races */ tosn(logstate2stream(logstate), std::forward(rest)...); From db9e34d8e9d073f11d1eb9ca9b43639b035383e7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Sep 2023 16:42:46 -0400 Subject: [PATCH 024/170] nestlog: bugfix: timestamp indent to account for msec/usec --- include/nestlog/log_state.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index fee193ec..d833307e 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -58,8 +58,13 @@ namespace xo { /* space budget for time-of-day */ std::size_t calc_time_indent() const { if (log_config::time_enabled) { - /*strlen("14:38:19.974 ")*/ - return 13; + if (log_config::time_usec_flag) { + /*strlen("14:38:19.123456 ")*/ + return 16; + } else { + /*strlen("14:38:19.974 ")*/ + return 13; + } } else { return 0; } From 5339e9b124d1922b30c4c2e8b362c8b0fdad46a9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Sep 2023 17:39:35 -0400 Subject: [PATCH 025/170] nestlog: log levels --- example/ex1/ex1.cpp | 2 +- example/ex2/ex2.cpp | 4 ++-- example/ex3/ex3.cpp | 9 ++++---- include/nestlog/log_config.hpp | 7 ++++++ include/nestlog/log_level.hpp | 42 ++++++++++++++++++++++++++++++++++ include/nestlog/scope.hpp | 32 ++++++++++++++------------ include/nestlog/time.hpp | 4 ++-- 7 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 include/nestlog/log_level.hpp diff --git a/example/ex1/ex1.cpp b/example/ex1/ex1.cpp index 60922607..db0ce39e 100644 --- a/example/ex1/ex1.cpp +++ b/example/ex1/ex1.cpp @@ -3,7 +3,7 @@ using namespace xo; void A(int x) { - XO_SCOPE(log); + XO_SCOPE(log, info); log("x:", x); } diff --git a/example/ex2/ex2.cpp b/example/ex2/ex2.cpp index 3d246f0e..016fe177 100644 --- a/example/ex2/ex2.cpp +++ b/example/ex2/ex2.cpp @@ -6,7 +6,7 @@ using namespace xo; int fib(int n) { - scope log(XO_SSETUP0(), ":n ", n); + scope log(XO_ENTER0(info), ":n ", n); int retval = 1; @@ -26,7 +26,7 @@ main(int argc, char ** argv) { int n = 4; - scope log(XO_SSETUP0(), ":n ", 4); + scope log(XO_ENTER0(info), ":n ", 4); int fn = fib(n); diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index a0507147..0d9121dc 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -6,7 +6,7 @@ using namespace xo; int fib(int n) { - scope log(XO_ENTER0(), tag("n", n)); + scope log(XO_ENTER0(info), tag("n", n)); int retval = 1; @@ -21,6 +21,7 @@ fib(int n) { int main(int argc, char ** argv) { + log_config::min_log_level = log_level::info; log_config::time_enabled = true; log_config::time_local_flag = true; log_config::style = FS_Streamlined; @@ -34,12 +35,12 @@ main(int argc, char ** argv) { int n = 4; - scope log(XO_ENTER0(), ":n ", 4); + scope log(XO_ENTER0(info), ":n ", 4); int fn = fib(n); - log(tag("n", n)); - log("<-", xtag("fib(n)", fn)); + log && log(tag("n", n)); + log && log("<-", xtag("fib(n)", fn)); } /* ex3/ex3.cpp */ diff --git a/include/nestlog/log_config.hpp b/include/nestlog/log_config.hpp index fa0d3902..b0a3780e 100644 --- a/include/nestlog/log_config.hpp +++ b/include/nestlog/log_config.hpp @@ -2,6 +2,7 @@ #pragma once +#include "log_level.hpp" #include "function.hpp" #include "nestlog/color.hpp" #include @@ -10,6 +11,8 @@ namespace xo { /* Tag here b/c we want header-only library */ template struct log_config_impl { + /* display log messages with severity >= .log_level */ + static log_level min_log_level; /* true to log local time */ static bool time_enabled; /* true to log time-of-day in local coords; false for UTC coords */ @@ -41,6 +44,10 @@ namespace xo { static std::uint32_t code_location_color; }; /*log_config_impl*/ + template + log_level + log_config_impl::min_log_level = log_level::default_level; + template bool log_config_impl::time_enabled = 1; diff --git a/include/nestlog/log_level.hpp b/include/nestlog/log_level.hpp new file mode 100644 index 00000000..f5d5f4db --- /dev/null +++ b/include/nestlog/log_level.hpp @@ -0,0 +1,42 @@ +/* @file log_level.hpp */ + +#include + +namespace xo { + enum class log_level : std::uint32_t { + /* control log message severity + * silent > severe > error > warning > info > chatty + */ + chatty, + info, + warning, + error, + severe, + silent, + + default_level = error + }; /*log_level*/ + + inline bool + operator>(log_level x, log_level y) { + return (static_cast(x) > static_cast(y)); + } + + inline bool + operator>=(log_level x, log_level y) { + return (static_cast(x) >= static_cast(y)); + } + + inline bool + operator<(log_level x, log_level y) { + return (static_cast(x) < static_cast(y)); + } + + inline bool + operator<=(log_level x, log_level y) { + return (static_cast(x) <= static_cast(y)); + } + +} /*namespace xo*/ + +/* end log_level.hpp */ diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp index 848e9d4e..f15515df 100644 --- a/include/nestlog/scope.hpp +++ b/include/nestlog/scope.hpp @@ -16,16 +16,16 @@ namespace xo { template class state_impl; -# define XO_ENTER0() xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) -# define XO_ENTER1(debug_flag) xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, debug_flag) +# define XO_ENTER0(lvl) xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) +# define XO_ENTER1(lvl, debug_flag) xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, debug_flag) //# define XO_SSETUP0() xo::scope_setup(__FUNCTION__) -# define XO_SSETUP0() xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) +//# define XO_SSETUP0(lvl) xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) /* throw exception if condition not met*/ # define XO_EXPECT(f,msg) if(!(f)) { throw std::runtime_error(msg); } /* establish scope using current function name */ -# define XO_SCOPE(name) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__)) +# define XO_SCOPE(name, lvl) xo::scope name(xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__)) /* like XO_SCOPE(name), but also set enabled flag */ # define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, debug_flag)) # define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, false)) @@ -35,17 +35,21 @@ namespace xo { * use to disambiguate setup from other arguments */ struct scope_setup { - scope_setup(function_style style, std::string_view name1, std::string_view name2, - std::string_view file, std::uint32_t line, bool enabled_flag) - : style_{style}, name1_{name1}, name2_{name2}, file_{file}, line_{line}, enabled_flag_{enabled_flag} {} - scope_setup(function_style style, std::string_view name1, std::string_view file, std::uint32_t line, bool enabled_flag) - : scope_setup(style, name1, "", file, line, enabled_flag) {} - scope_setup(function_style style, std::string_view name1, std::string_view file, std::uint32_t line) - : scope_setup(style, name1, file, line, true /*enabled_flag*/) {} + scope_setup(log_level level, function_style style, std::string_view name1, std::string_view name2, + std::string_view file, std::uint32_t line) + : log_level_{level}, style_{style}, name1_{name1}, name2_{name2}, file_{file}, line_{line} {} + scope_setup(log_level level, function_style style, + std::string_view name1, std::string_view file, std::uint32_t line) + : scope_setup(level, style, name1, "" /*name2*/, file, line) {} + + bool is_enabled() const { return (this->log_level_ >= log_config::min_log_level); } //static scope_setup literal(std::string_view name1, bool enabled_flag = true) { return scope_setup(FS_Literal, name1, enabled_flag); } //static scope_setup literal(std::string_view name1, std::string_view name2, bool enabled_flag = true) { return scope_setup(FS_Literal, name1, name2, enabled_flag); } + /* threshold level for logging -- write messages with severity >= this level */ + log_level log_level_ = log_level::error; + /* FS_Pretty | FS_Streamlined | FS_Simple */ function_style style_ = FS_Pretty; std::string_view name1_ = "<.name1>"; std::string_view name2_ = "<.name2>"; @@ -53,8 +57,6 @@ namespace xo { std::string_view file_ = "<.file>"; /* __LINE__ */ std::uint32_t line_ = 0; - /* true iff output enabled for this scope */ - bool enabled_flag_ = false; }; /*scope_setup*/ /* nesting logger @@ -182,9 +184,9 @@ namespace xo { name2_{std::move(setup.name2_)}, file_{std::move(setup.file_)}, line_{setup.line_}, - finalized_{!setup.enabled_flag_} + finalized_{!(setup.is_enabled())} { - if(setup.enabled_flag_) { + if(setup.is_enabled()) { state_impl_type * logstate = basic_scope::require_thread_local_state(); std::ostream & os = logstate2stream(logstate); diff --git a/include/nestlog/time.hpp b/include/nestlog/time.hpp index 04344195..1d93dd26 100644 --- a/include/nestlog/time.hpp +++ b/include/nestlog/time.hpp @@ -1,4 +1,4 @@ -/* @file Time.hpp */ +/* @file time.hpp */ #pragma once @@ -359,4 +359,4 @@ namespace std { } /*namespace chrono*/ } /*namespace std*/ -/* end Time.hpp */ +/* end time.hpp */ From beeb927082ced8e34b8cadfb055b2c97bdf18928 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Sep 2023 20:15:58 -0400 Subject: [PATCH 026/170] nestlog: streamlining + comments + markdown --- README.md | 81 +++++++++++++++++------------------ example/ex2/ex2.cpp | 7 +-- example/ex3/ex3.cpp | 6 +-- include/nestlog/color.hpp | 14 +++++- include/nestlog/log_level.hpp | 17 +++++++- include/nestlog/scope.hpp | 12 ++++-- 6 files changed, 84 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 4e934ad7..2edcca0b 100644 --- a/README.md +++ b/README.md @@ -33,65 +33,64 @@ output: #include "nestlog/scope.hpp" + using namespace xo; + int fib(int n) { - XO_SCOPE(log); + scope log(XO_ENTER0(info), ":n ", n); int retval = 1; if (n >= 2) { - log(":n ", n); retval = fib(n - 1) + fib(n - 2); + log && log(":n ", n); } - log(":n ", n, " -> :retval ", retval); + log.end_scope("<- :retval ", retval); return retval; } int main(int argc, char ** argv) { - XO_SCOPE(log); + log_config::min_log_level = xo::log_level::info; + log_config::indent_width = 4; - int n = 4; - int fn = fib(n); + int n = 4; - log(":n ", n, " :fib(n) ", fn); + scope log(XO_ENTER0(info), ":n ", 4); + + int fn = fib(n); + + log && log(":n ", n); + log && log("<- :fib(n) ", fn); } output: - +main - +fib - :n 4 - +fib - :n 3 - +fib - :n 2 - +fib - :n 1 -> :retval 1 - -fib - +fib - :n 0 -> :retval 1 - -fib - :n 2 -> :retval 2 - -fib - +fib - :n 1 -> :retval 1 - -fib - :n 3 -> :retval 3 - -fib - +fib - :n 2 - +fib - :n 1 -> :retval 1 - -fib - +fib - :n 0 -> :retval 1 - -fib - :n 2 -> :retval 2 - -fib - :n 4 -> :retval 5 - -fib - :n 4 :fib(n) 5 - -main + 20:13:12.992909 +(0) main :n 4 [ex2.cpp:30] + 20:13:12.992968 +(1) fib :n 4 [ex2.cpp:9] + 20:13:12.992986 +(2) fib :n 3 [ex2.cpp:9] + 20:13:12.992999 +(3) fib :n 2 [ex2.cpp:9] + 20:13:12.993002 +(4) fib :n 1 [ex2.cpp:9] + 20:13:12.993012 -(4) fib <- :retval 1 + 20:13:12.993022 +(4) fib :n 0 [ex2.cpp:9] + 20:13:12.993032 -(4) fib <- :retval 1 + :n 2 + 20:13:12.993049 -(3) fib <- :retval 2 + 20:13:12.993059 +(3) fib :n 1 [ex2.cpp:9] + 20:13:12.993069 -(3) fib <- :retval 1 + :n 3 + 20:13:12.993085 -(2) fib <- :retval 3 + 20:13:12.993095 +(2) fib :n 2 [ex2.cpp:9] + 20:13:12.993105 +(3) fib :n 1 [ex2.cpp:9] + 20:13:12.993115 -(3) fib <- :retval 1 + 20:13:12.993124 +(3) fib :n 0 [ex2.cpp:9] + 20:13:12.993134 -(3) fib <- :retval 1 + :n 2 + 20:13:12.993145 -(2) fib <- :retval 2 + :n 4 + 20:13:12.993155 -(1) fib <- :retval 5 + :n 4 + <- :fib(n) 5 + 20:13:12.993172 -(0) main diff --git a/example/ex2/ex2.cpp b/example/ex2/ex2.cpp index 016fe177..23bb2b3e 100644 --- a/example/ex2/ex2.cpp +++ b/example/ex2/ex2.cpp @@ -12,7 +12,7 @@ fib(int n) { if (n >= 2) { retval = fib(n - 1) + fib(n - 2); - log(":n ", n); + log && log(":n ", n); } log.end_scope("<- :retval ", retval); @@ -22,6 +22,7 @@ fib(int n) { int main(int argc, char ** argv) { + log_config::min_log_level = xo::log_level::info; log_config::indent_width = 4; int n = 4; @@ -30,6 +31,6 @@ main(int argc, char ** argv) { int fn = fib(n); - log(":n ", n); - log("<- :fib(n) ", fn); + log && log(":n ", n); + log && log("<- :fib(n) ", fn); } diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 0d9121dc..d20f0f65 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -26,14 +26,14 @@ main(int argc, char ** argv) { log_config::time_local_flag = true; log_config::style = FS_Streamlined; log_config::indent_width = 4; - log_config::max_indent_width = 14; - log_config::location_tab = 80; + log_config::max_indent_width = 30; + log_config::location_tab = 100; log_config::encoding = CE_Xterm; log_config::function_entry_color = 69; log_config::function_exit_color = 70; log_config::code_location_color = 166; - int n = 4; + int n = 9; scope log(XO_ENTER0(info), ":n ", 4); diff --git a/include/nestlog/color.hpp b/include/nestlog/color.hpp index 2c2419c2..20ea0bb1 100644 --- a/include/nestlog/color.hpp +++ b/include/nestlog/color.hpp @@ -33,6 +33,8 @@ namespace xo { void print(std::ostream & os) const { if ((flags_ & CF_ColorOn) && (color_ > 0)) { switch(encoding_) { + case CE_None: + break; case CE_Ansi: os << "\033[" << color_ << "m"; break; @@ -45,8 +47,16 @@ namespace xo { if (flags_ & CF_Contents) os << contents_; - if ((flags_ & CF_ColorOff) && (color_ > 0)) - os << "\033[0m"; + if ((flags_ & CF_ColorOff) && (color_ > 0)) { + switch(encoding_) { + case CE_None: + break; + case CE_Ansi: + case CE_Xterm: + os << "\033[0m"; + break; + } + } } /*print*/ private: diff --git a/include/nestlog/log_level.hpp b/include/nestlog/log_level.hpp index f5d5f4db..55c4f2a4 100644 --- a/include/nestlog/log_level.hpp +++ b/include/nestlog/log_level.hpp @@ -5,13 +5,28 @@ namespace xo { enum class log_level : std::uint32_t { /* control log message severity - * silent > severe > error > warning > info > chatty + * silent > always > severe > error > warning > info > chatty > never + * + * never: + * used internally e.g. by XO_ENTER1() + * a log message with this severity will never be printed + * + * always: + * use with XO_ENTER1(): + * scope log(XO_ENTER1(always, mydebug_flag)); + * to log message whenever mydebug_flag is true (for any .min_log_level except silent) + * + * silent: + * use in log_config to suppress all log messages */ + never, + verbose, chatty, info, warning, error, severe, + always, silent, default_level = error diff --git a/include/nestlog/scope.hpp b/include/nestlog/scope.hpp index f15515df..fac759c2 100644 --- a/include/nestlog/scope.hpp +++ b/include/nestlog/scope.hpp @@ -17,7 +17,13 @@ namespace xo { class state_impl; # define XO_ENTER0(lvl) xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) -# define XO_ENTER1(lvl, debug_flag) xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, debug_flag) +# define XO_ENTER1(lvl, debug_flag) XO_ENTER2(lvl, debug_flag, __PRETTY_FUNCTION__) +# define XO_ENTER2(lvl, debug_flag, name1) xo::scope_setup((debug_flag ? xo::log_level::lvl : xo::log_level::never), xo::log_config::style, name1, __FILE__, __LINE__) + +# define XO_DEBUG(debug_flag) XO_ENTER1(always, debug_flag) +# define XO_DEBUG2(debug_flag, name1) XO_ENTER2(always, debug_flag, name1) + +# define XO_LITERAL(lvl, name1, name2) xo::scope_setup(xo::log_level::lvl, FS_Literal, name1, name2, __FILE__, __LINE__) //# define XO_SSETUP0() xo::scope_setup(__FUNCTION__) //# define XO_SSETUP0(lvl) xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) @@ -27,8 +33,8 @@ namespace xo { /* establish scope using current function name */ # define XO_SCOPE(name, lvl) xo::scope name(xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__)) /* like XO_SCOPE(name), but also set enabled flag */ -# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, debug_flag)) -# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, false)) +//# define XO_SCOPE2(name, debug_flag) xo::scope name(xo::scope_setup(xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__, debug_flag)) +# define XO_SCOPE_DISABLED(name) xo::scope name(xo::scope_setup(xo::log_level::never, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__)) # define XO_STUB() { XO_SCOPE(logr); logr.log("STUB"); } /* convenience class for basic_scope<..> construction (see below). From 3437ef1b3faa876f7340ebd14cc92753bcdce659 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Sep 2023 20:30:44 -0400 Subject: [PATCH 027/170] nestlog: ++ README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 2edcca0b..df0a4a8a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,18 @@ Nestlog is a lightweight header-only library for console logging. +## Features + +- easy-to-read format uses indenting to show call structure. + indentation has user-controlled upper limit to preserve readability with + deeply nested call graphs +- colorized output using vt100 color codes (ansi or xterm) +- automatically captures + displays timestamp, function name and code location. + supports several function-name formats to reflect tradeoff readability for precision +- application code may issue logging code that contains embedded newlines; + logger preserves indentation. +- logger is 'truthy', so you only pay for formatting for entry points that are enabled. + ## Examples ### 1 From 794196c3f8df9eaa3cd3b635f9f5fdc20c736433 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 12:38:36 -0400 Subject: [PATCH 028/170] nestlog: bugfix: color_off() must use CE_Ansi instead of CE_None --- include/nestlog/color.hpp | 2 +- include/nestlog/log_state.hpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/nestlog/color.hpp b/include/nestlog/color.hpp index 20ea0bb1..6f1d52f8 100644 --- a/include/nestlog/color.hpp +++ b/include/nestlog/color.hpp @@ -118,7 +118,7 @@ namespace xo { inline color_impl color_off() { /* any non-zero value works here for color */ - return color_impl(CF_ColorOff, CE_None, 1 /*color*/, 0); + return color_impl(CF_ColorOff, CE_Ansi, 1 /*color*/, 0); } /*color_off*/ template diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index d833307e..b878724b 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -211,6 +211,14 @@ namespace xo { this->ss_ << ee_label; if (log_config::nesting_level_enabled) { + /* e.g. + * (^[[38;5;195m7^[[0m) + * <-----a---->b<-c-> + * + * a = color on + * b = level - displayed in color + * c = color off + */ this->ss_ << "(" << with_color(log_config::encoding, From d4207c1f33b521f82609a8218766fa0586623f9e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 14:18:38 -0400 Subject: [PATCH 029/170] nestlog: bugfix: suppress timestamp when disabled --- include/nestlog/log_state.hpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index b878724b..4b894a92 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -42,16 +42,18 @@ namespace xo { using xo::time::hms_msec; using xo::time::hms_usec; - if (log_config::time_local_flag) { - if (log_config::time_usec_flag) - this->ss_ << hms_usec::local(now_tm) << " "; - else - this->ss_ << hms_msec::local(now_tm) << " "; - } else { - if (log_config::time_usec_flag) - this->ss_ << hms_usec::utc(now_tm) << " "; - else - this->ss_ << hms_msec::utc(now_tm) << " "; + if (log_config::time_enabled) { + if (log_config::time_local_flag) { + if (log_config::time_usec_flag) + this->ss_ << hms_usec::local(now_tm) << " "; + else + this->ss_ << hms_msec::local(now_tm) << " "; + } else { + if (log_config::time_usec_flag) + this->ss_ << hms_usec::utc(now_tm) << " "; + else + this->ss_ << hms_msec::utc(now_tm) << " "; + } } } /*check_print_time*/ From 643e0a2edc41fb3ac45a5c8130b7931b0afbbd24 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 14:19:18 -0400 Subject: [PATCH 030/170] nestlog: bugfix: indent accounting skips non-printing vt100 escapes --- include/nestlog/log_state.hpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index 4b894a92..9bf6fefb 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -281,6 +281,11 @@ namespace xo { */ char const * space_after_nonspace = nullptr; + /* true on VT100 color escape (\033); in which case false on terminating char (m) + * don't advance lpos during escape + */ + bool in_color_escape = false; + while(true) { bool have_nonspace = false; @@ -302,18 +307,29 @@ namespace xo { } } - if(*p == '\n') { + if (in_color_escape && (*p != '\n')) { + /* in color escape -> don't advance .lpos */ + if (*p == 'm') + in_color_escape = false; ++p; - /* reset .pos on newline */ + } else if (*p == '\033') { + /* begin color escape sequence */ + in_color_escape = true; + ++p; + } else if (*p == '\n') { + /* reset .pos on newline; also drop any (incomplete + ill-formed) color escape */ + + in_color_escape = false; + lpos_on_newline = this->lpos_; this->lpos_ = 0; + ++p; break; } else { - ++p; - /* increment .lpos on non-newline */ ++(this->lpos_); + ++p; } } @@ -358,7 +374,7 @@ namespace xo { // std::clog.rdbuf()->sputn(buf, strlen(buf)); //} - /* at least 1 char following newline, need to indent for it + /* control here only for continuation lines (application logging code embedding its own newlines) * - minimum indent = nesting level; * - however if space_after_nonspace defined, also indent for that */ From 5b80fe2d202205b2231e5e822fd7e0a2bf9d3cb3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 14:21:09 -0400 Subject: [PATCH 031/170] nestlog: examples/ex3.cpp: minor tweaks --- example/ex3/ex3.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index d20f0f65..452998f8 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -21,19 +21,22 @@ fib(int n) { int main(int argc, char ** argv) { + //std::cerr << "0 1 2 3 4 5 6 7 8 9 10" << std::endl; + //std::cerr << "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" << std::endl; + log_config::min_log_level = log_level::info; log_config::time_enabled = true; log_config::time_local_flag = true; log_config::style = FS_Streamlined; log_config::indent_width = 4; log_config::max_indent_width = 30; - log_config::location_tab = 100; + log_config::location_tab = 80; log_config::encoding = CE_Xterm; log_config::function_entry_color = 69; log_config::function_exit_color = 70; log_config::code_location_color = 166; - int n = 9; + int n = 3; scope log(XO_ENTER0(info), ":n ", 4); From d46c7349502e435edde72546f29c93bc7a8ac104 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 14:21:43 -0400 Subject: [PATCH 032/170] nestlog: colorize tag inserter --- include/nestlog/concat.hpp | 37 ++++++++++++++++++++++++++++++++++ include/nestlog/log_config.hpp | 2 +- include/nestlog/tag.hpp | 7 +++++-- include/nestlog/tag_config.hpp | 34 +++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 include/nestlog/concat.hpp create mode 100644 include/nestlog/tag_config.hpp diff --git a/include/nestlog/concat.hpp b/include/nestlog/concat.hpp new file mode 100644 index 00000000..31bd6b43 --- /dev/null +++ b/include/nestlog/concat.hpp @@ -0,0 +1,37 @@ +/* @file concat.hpp */ + +#pragma once + +#include +#include // for std::move() + +namespace xo { + template + struct concat_impl { + public: + concat_impl(T1 && x1, T2 && x2) + : x1_{std::forward(x1)}, x2_{std::forward(x2)} {} + + T1 const & x1() const { return x1_; } + T2 const & x2() const { return x2_; } + + private: + T1 x1_; + T2 x2_; + }; /*concat_impl*/ + + template + concat_impl concat(T1 && x1, T2 && x2) { + return concat_impl(std::move(x1), std::move(x2)); + } /*concat*/ + + template + inline std::ostream & + operator<<(std::ostream & os, concat_impl const & x) { + os << x.x1() << x.x2(); + return os; + } /*operator<<*/ + +} /*namespace xo*/ + +/* end concat.hpp */ diff --git a/include/nestlog/log_config.hpp b/include/nestlog/log_config.hpp index b0a3780e..00e49249 100644 --- a/include/nestlog/log_config.hpp +++ b/include/nestlog/log_config.hpp @@ -4,7 +4,7 @@ #include "log_level.hpp" #include "function.hpp" -#include "nestlog/color.hpp" +#include "color.hpp" #include namespace xo { diff --git a/include/nestlog/tag.hpp b/include/nestlog/tag.hpp index 7ac62023..258b432f 100644 --- a/include/nestlog/tag.hpp +++ b/include/nestlog/tag.hpp @@ -2,7 +2,10 @@ #pragma once -#include "nestlog/quoted.hpp" +#include "tag_config.hpp" +#include "concat.hpp" +#include "quoted.hpp" +#include "color.hpp" #include // STRINGIFY(xyz) -> "xyz" @@ -93,7 +96,7 @@ namespace xo { if(PrefixSpace) s << " "; - s << ":" << tag.name() + s << with_color(tag_config::encoding, tag_config::tag_color, concat((char const *)":", tag.name())) << " " << unq(tag.value()); return s; diff --git a/include/nestlog/tag_config.hpp b/include/nestlog/tag_config.hpp new file mode 100644 index 00000000..d4a67cb7 --- /dev/null +++ b/include/nestlog/tag_config.hpp @@ -0,0 +1,34 @@ +/* @file tag_config.hpp */ + +#pragma once + +#include "color.hpp" +#include + +namespace xo { + /* Tag here b/c we want header-only library */ + template + struct tag_config_impl { + /* color encoding */ + static color_encoding encoding; + /* color to use for tags + * os << tag("foo", foovalue) + * to produces output like + * :foo foovalue + * with :foo using .tag_color + */ + static std::uint32_t tag_color; + }; /*tag_config_impl*/ + + template + color_encoding + tag_config_impl::encoding = CE_Xterm; + + template + std::uint32_t + tag_config_impl::tag_color = 245; + + using tag_config = tag_config_impl; +} /*namespace xo*/ + +/* end tag_config.hpp */ From 7b233acf2941e0ebe3a77768575a83ca92ba67c8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 14:22:07 -0400 Subject: [PATCH 033/170] nestlog: + quoted_char inserter --- include/nestlog/quoted_char.hpp | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 include/nestlog/quoted_char.hpp diff --git a/include/nestlog/quoted_char.hpp b/include/nestlog/quoted_char.hpp new file mode 100644 index 00000000..010eefa3 --- /dev/null +++ b/include/nestlog/quoted_char.hpp @@ -0,0 +1,43 @@ +/* @file quoted_char.hpp */ + +#pragma once + +#include + +namespace xo { + template + class quoted_char { + public: + quoted_char(CharT ch) : ch_{ch} {} + + void print(std::ostream & os) const { + switch(ch_) { + case '\033': + os << "\\033"; + break; + case '\n': + os << "\\n"; + break; + case '\r': + os << "\\r"; + break; + default: + os << ch_; + } + } + + private: + CharT ch_; + }; /*quoted_char*/ + + template + inline std::ostream & + operator<<(std::ostream & os, quoted_char const & x) { + x.print(os); + return os; + } /*operator<<*/ + +} /*namespace xo*/ + + +/* end quoted_char.hpp */ From efdcacf9b5b791d30e6a012d33bdb6c8c6cee826 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 14:22:51 -0400 Subject: [PATCH 034/170] nestlog: README.md tweaks --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index df0a4a8a..6847b7d7 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,20 @@ -# nestlog -- logging with automatic indenting according to call graph +# nestlog -- logging with automatic call-graph indenting Nestlog is a lightweight header-only library for console logging. ## Features +- header-only; nothing to link - easy-to-read format uses indenting to show call structure. indentation has user-controlled upper limit to preserve readability with deeply nested call graphs - colorized output using vt100 color codes (ansi or xterm) - automatically captures + displays timestamp, function name and code location. supports several function-name formats to reflect tradeoff readability for precision -- application code may issue logging code that contains embedded newlines; +- application code may issue logging code that contains embedded newlines and/or color escapes; logger preserves indentation. -- logger is 'truthy', so you only pay for formatting for entry points that are enabled. +- logger is 'truthy' -> only pay for formatting when entry points is enabled. +- also provides family of convenience stream-inserters ## Examples From 3e457e4435467cb3b041d43e98fb679f25a25cb9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 14:36:30 -0400 Subject: [PATCH 035/170] nestlog: README: try embedding screen capture --- README.md | 19 +++++++++++++++---- img/ex3.png | Bin 0 -> 47158 bytes 2 files changed, 15 insertions(+), 4 deletions(-) create mode 100755 img/ex3.png diff --git a/README.md b/README.md index 6847b7d7..d54dc2e5 100644 --- a/README.md +++ b/README.md @@ -67,21 +67,32 @@ output: int main(int argc, char ** argv) { - log_config::min_log_level = xo::log_level::info; + log_config::min_log_level = log_level::info; + log_config::time_enabled = true; + log_config::time_local_flag = true; + log_config::style = FS_Streamlined; log_config::indent_width = 4; + log_config::max_indent_width = 30; + log_config::location_tab = 80; + log_config::encoding = CE_Xterm; + log_config::function_entry_color = 69; + log_config::function_exit_color = 70; + log_config::code_location_color = 166; - int n = 4; + int n = 3; scope log(XO_ENTER0(info), ":n ", 4); int fn = fib(n); - log && log(":n ", n); - log && log("<- :fib(n) ", fn); + log && log(tag("n", n)); + log && log("<-", xtag("fib(n)", fn)); } output: + [ex3 output](img/ex3.png) + 20:13:12.992909 +(0) main :n 4 [ex2.cpp:30] 20:13:12.992968 +(1) fib :n 4 [ex2.cpp:9] 20:13:12.992986 +(2) fib :n 3 [ex2.cpp:9] diff --git a/img/ex3.png b/img/ex3.png new file mode 100755 index 0000000000000000000000000000000000000000..6355c003aa7b859469ab7697ca0714d313628c39 GIT binary patch literal 47158 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
R6&ci!@wi{0wF2H%6LuZ*7ft_<3~xa!aZ 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

E>$_e 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 Date: Sat, 16 Sep 2023 14:37:46 -0400 Subject: [PATCH 036/170] nestlog: README: img instead of link to img --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d54dc2e5..42232319 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ output: output: - [ex3 output](img/ex3.png) + ![ex3 output](img/ex3.png) 20:13:12.992909 +(0) main :n 4 [ex2.cpp:30] 20:13:12.992968 +(1) fib :n 4 [ex2.cpp:9] From 833a20d8a6e3a61cb3af5c2fe8ea73d95780a494 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 14:46:39 -0400 Subject: [PATCH 037/170] nestlog: README + ex2 output image --- README.md | 75 ++++++++++++++++++++++++++++++++-------------------- img/ex2.png | Bin 0 -> 69441 bytes 2 files changed, 46 insertions(+), 29 deletions(-) create mode 100755 img/ex2.png diff --git a/README.md b/README.md index 42232319..27c8e73d 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,48 @@ output: return retval; } + int + main(int argc, char ** argv) { + log_config::min_log_level = xo::log_level::info; + log_config::indent_width = 4; + + int n = 4; + + scope log(XO_ENTER0(info), ":n ", 4); + + int fn = fib(n); + + log && log(":n ", n); + log && log("<- :fib(n) ", fn); + } + +output: +![ex2 output](img/ex2.png) + +### 3 example exposing runtime configuration options + + ``` + /* examples ex3/ex3.cpp */ + + #include "nestlog/scope.hpp" + + using namespace xo; + + int + fib(int n) { + scope log(XO_ENTER0(info), tag("n", n)); + + int retval = 1; + + if (n >= 2) { + retval = fib(n - 1) + fib(n - 2); + } + + log.end_scope(tag("n", n), " <-", xtag("retval", retval)); + + return retval; + } + int main(int argc, char ** argv) { log_config::min_log_level = log_level::info; @@ -89,33 +131,8 @@ output: log && log("<-", xtag("fib(n)", fn)); } + /* ex3/ex3.cpp */ + ``` + output: - - ![ex3 output](img/ex3.png) - - 20:13:12.992909 +(0) main :n 4 [ex2.cpp:30] - 20:13:12.992968 +(1) fib :n 4 [ex2.cpp:9] - 20:13:12.992986 +(2) fib :n 3 [ex2.cpp:9] - 20:13:12.992999 +(3) fib :n 2 [ex2.cpp:9] - 20:13:12.993002 +(4) fib :n 1 [ex2.cpp:9] - 20:13:12.993012 -(4) fib <- :retval 1 - 20:13:12.993022 +(4) fib :n 0 [ex2.cpp:9] - 20:13:12.993032 -(4) fib <- :retval 1 - :n 2 - 20:13:12.993049 -(3) fib <- :retval 2 - 20:13:12.993059 +(3) fib :n 1 [ex2.cpp:9] - 20:13:12.993069 -(3) fib <- :retval 1 - :n 3 - 20:13:12.993085 -(2) fib <- :retval 3 - 20:13:12.993095 +(2) fib :n 2 [ex2.cpp:9] - 20:13:12.993105 +(3) fib :n 1 [ex2.cpp:9] - 20:13:12.993115 -(3) fib <- :retval 1 - 20:13:12.993124 +(3) fib :n 0 [ex2.cpp:9] - 20:13:12.993134 -(3) fib <- :retval 1 - :n 2 - 20:13:12.993145 -(2) fib <- :retval 2 - :n 4 - 20:13:12.993155 -(1) fib <- :retval 5 - :n 4 - <- :fib(n) 5 - 20:13:12.993172 -(0) main +![ex3 output](img/ex3.png) diff --git a/img/ex2.png b/img/ex2.png new file mode 100755 index 0000000000000000000000000000000000000000..8e5546365725205bcee5035ab7239f00a71cd508 GIT binary patch literal 69441 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 Date: Sat, 16 Sep 2023 15:03:35 -0400 Subject: [PATCH 038/170] nestlog: README: tweak ex1 --- README.md | 31 +++++++++++++++++-------------- img/ex1.png | Bin 0 -> 15819 bytes 2 files changed, 17 insertions(+), 14 deletions(-) create mode 100755 img/ex1.png diff --git a/README.md b/README.md index 27c8e73d..4943e8f0 100644 --- a/README.md +++ b/README.md @@ -20,26 +20,29 @@ Nestlog is a lightweight header-only library for console logging. ### 1 - /* examples/ex1/ex1.cpp */ +``` +#include "nestlog/scope.hpp" - #include "nestlog/scope.hpp" +using namespace xo; - void A(int x) { - XO_SCOPE(log); // i.e. xo::scope log("A"); +void inner(int x) { + scope log(XO_ENTER0(always), ":x ", x); +} - log("enter ", ":x ", x); - } +void outer(int y) { + scope log(XO_ENTER0(always), ":y ", y); - int - main(int argc, char ** argv) { - A(66); - } + inner(2*y); +} + +int +main(int argc, char ** argv) { + outer(123); +} +``` output: - - +A - enter :x 66 - -A +![ex12 output](img/ex1.png) ### 2 diff --git a/img/ex1.png b/img/ex1.png new file mode 100755 index 0000000000000000000000000000000000000000..89e37ca42146167d845242a26d5413ead97b05b8 GIT binary patch literal 15819 zcmeAS@N?(olHy`uVBq!ia0y~yV2)y7V94NLV_;x-@uP7m0|NtNage(c!@6@aFBupZ zSkfJR9T^xl_H+M9WMyDr;4JWnEM{QfI}E~%$MaXDFfiCAc)B=-RK&fV%ehD7>fHDK zrQc(B#H0w`bnVpH)RPh6;_Aq>h(}pCvgN1E#L7N@fh#=c4y*p^*d)`zBev+Isvi%?A@WPU zW~iEJhVDGZ*SUVq37$^AE5{Cf|0@6XH^|&$Tu#0pxB?`U;tnlYnVWRWA~=1Dm)wT^ z*Tq>MmqzAY&NVpM>EW2OCsb@uGpv25PAm9NfE`@44;%iZOsE30RG z`FSaP^U`g<-Ddu0YpZ2#D zKh6}MsaROcClkH#R%gb6BlcHw4e#?gws;25e!#ios#E;#|BLru`TXebNB$=Dn-=I6?gSmT9-uU)ZfZyX$#y{Ml)3x9lo51pL?$)LSR2BcOf% z;#Z^n|98*v;D5CB+H=jwR{d|=Dz?eS-####)&JTo)9etVnYYcJqGrWJTw;6??0{uPVQHvX;45%G4{i`t8B7NS9ksN-zzt5|8VB^ zTg^86uy@_NZ<3GS6eONYZMuKC$T?wVeO=zn%{${>{%Vt1zdyM{xnQ|x=sSgTn*Gab zFB}ilKk2;OI9GN`c))K7E_v%}z4hvh#c6lG&)s?M-M+L}`AycfYCo=Oi>`cC>Lm#qXl&uXblS?}@V`13( zINf;~6-)ko%m07v=HesF-(Ia=@3lc^cVof4?f2`V_kK9U{YiFB%+8=*2}7r~5gQM6 zg5uX`v74MOPiohe>-8(gB)Ye)}gY+pawDEcn^|%jRv)VMdXxixX{@hD5eG zoj$|rRhK&bc*~Ffr9u`SGriv!CH|Ya{fq|tx#s1YJcRGB`2OEqw&sY-x{k69+rzZ0 zU$ZIkxXJNYOT;&FkptS_lO{3ZAc z`vX1eZ>df*zB$VG$E>75<#Y0Iy#-oD{* zc=hyh_~qE(pLc&OU1wcqUYBtEQSxF!)Q*CMuWoEy%whDQS^kg1T&q&Av-8&0XUP8h z&~9%rA5=2DSuyj%rKY7heg78!>#utKr?$y4>45yFRf?vJ&MyqM@U(IBu-h0OlYi57 z)XI{luD9})jL52aH_EncH&8hvrzr ze5-#}>W;b%MF$c-Nrf2v*4xvA#@XIP~F@^Q(UwR>$qiH7Mc8 z&1kb%^?ysZQk~kY~Q|7(W=+%*Lk1K=Nn)5XG<5mEMRa6OY`g-a2@T=a^r{2A8Rez_jB7a8RtO7TVou}WuwST!HOJ28ZLi_gG zCHpesb-N1oUOblZdckky*xw91-<=~L20BD1+z3;f@k^QI=|sN!Rex7+zT6&CYkJ03 z;>YfVzc(^|HM%bKci*GyWmfCewHOP(?))p6`h9k{NX7dUhtR!WK88Lwti7uJ@703Z zBG;StFF(J!pKZMV;$MX&+Zx!j4m2<-E!y+t?d|Z|KOc|3x|u$Is$%Pnx_>{PXFWKu z**<9h@4N3);;!dzzpM6nL%}}r_?kc$2~ZWHou#tn!e%+pLc(p`d`lcK*~9#!##psxo43iSKx$` zdxc$Q?8{ow{q3aa4*j$5g&WFw4~uPR zUmYSp98kQhxF)f2f|NzYeJ(%3Ps`v9_r3O0<*T`OEm;0}#`cMQ2AO|e@hEdwwi|9r zZC#&~`$XsJ?S_Z(GwdI`om$%Ju6DqhdHpQLIA)2^8OtYX2BqopoMN^qNL;ZiZe8}% z^1Vhcr4#qWUMjOYzARgw=Pb*$r{Bb8>@1Hn%9S^~z<#5Y_t4z@Z9lHsKCW80eo>qq z$e$YfrDMO^&A-n(Q-0a!26G91Re?wUGvA+X^LaP-z&^oE>p@;t)A07)bLYXe=w@!~ zq9-1qK|zbe^yA*_USfSDd~@2_BhF9xB=lae74LlTvdNq~Zf!`VkQ0aEO#xjUoj(&l z@06Os&f;vc?!Vd3vymNtm+oC#vbT8o13l~9KgqwXdDdp|KaaWoy2D6zOJURdXLCG) zf0X~S$=;IqQTT7HbeD(p|F!piuAQsKBcUYnc6GC!vD3l$>}Ypso2l|I_smKBlX!~f zw?do|t>;lpY|6k6X^r`CQ z-p6n&PFN#CG7f;NtT58vR-qiQHU53Am{^9FizIK#d zyuURucdOm@-b>s1_bm%c{_A)@ct<+d`>Xf28fee1-}Ww}yJH{w(lzF<7QDBe`FZ(m z^@ZyVFSYLU=XESSzap;x)t7pnb>TCr4L+1R#|JNUmH(x;PW9DFuD7)U@f!UrcgJYg z_CDPuv(0|7Pto1dpT0kr$g|zGo+ru}{Ehbw|Hs=w;%}K#9*V{8(>V2-=da8BR*TQS zWj}4}W?XIb$YS-(x$Rej^1r_Ks0sf1T28ED{;_^}eQl<^ySuJ-+Ma&gZ@;eW?X9KL zbU1%(yqsXzlf7=In`!1H7qPtup1UXoeho@q6Jb&LDP`tz)AVyPl35jpdCgB4I6r=R z$gA~mJHNQ$wS~^?qW#B1&(E_By}mBC_B5!~Ua>N?Uo5QpFiWPfryBQ3*io*(cOzZ-Kd(6R!RXA# ziIonsO1`h09a8#z?eycXmA^XuUcMrHSGLxE=_r>I?~nPvwfK4Wg3{&}@^9Ynm{uga z<-_5R0wS9%+TXo?x2s+C!@Z9aHs!axSY3M6j)9*gz-~Ep1lKFv8S7#cdAlrrnwtdR;1e`cHn?s|bUS-cp zp3(X9aOQyLpQe`=~FY3f$IUh$4w0Mih-s0D5x1ai*+11r`MSK08MRnhI-?yy3 z)cpPNgS}?Q`{l#C#r4DLe;k&dV+%IAlsiXi&;IkgaYz20v#zlZiv4s#xxXX#<+EqA z^TST2+&v{%wZ&sE)4~>cl@1-9yESia7^eGMd*$BO-`JeqFYNuQ%isR*mQ{aWe^%VH-km%D!2ZwYtV7qw z?R|1rRpZI#^LDS_Z2cJgMnU>2-&M+!MPS1Xs#D++odHYM}nq1H+60nsflr5RG|-|c*!QvLmIx%aJK zi`Ja|A0jI5AF$MV-|HhW5-l&21r9wv-XFfV`unu^b=R*fd3kB6_uMbeP8^CV;XiIB zY;_dZUgj2Ybk+Q>mELPsM9s5U`%ks<)Xm!koZ0Q^i@1BrwexMF7Q6LMdKlr}CsUZz z6uGZvXNj8dww#-f-f*(pNUiwu>+9>MKmPvyzItWw^03c73THb6m4lXXI?wo=67)T! zWuv4UND|h<(+!;#i&&{>AHheC$EN*k!S)qxo zdjiv@$W|_DPGin%Dt&$JWPhLhWHsNQX{jrp&#%ANxzg{38B50I>+$umc{?U5yIXBs zqQ`mp_`I4=o>%u&7E3C<+PCaSqN#(%;lr7~9&XFMy+nSIJ!p8tW#z$D0leF|t~$Q{ zGmBB=*ffsh^Ut~WIb}aRH8rSFR6ESV@Zg(UTfIegbJopk$-KObRqBqxlJD>CYG;Wa zKR?el`Us2EtqEGZJf-FPFDAywk6Meg<(*kZj(p2zK!XD$_JJeKc7xtdgcUs>5H42 zpIg42!+mROw))o(uZ@}|aRbpEB=*TKNwth7UtCAHtjK3_JJexm1;=Ix+ ztUgDiMZn49@YA@}E`PJPv{so{ZHyAiT=uTRr082l^_i|!@h>b`l20C}{+d0vu53xC z@Zu|0q3ia^+pnsdYw`9-%K3uT9-o{m1ty#?U(1xfKIpvr>{UOlY(zBIdVSvUuV<6g zp(Tb(HeEe@Luh5rn_C;gvzyjmIF+KK9HMR`$KmL;$+?|xQ||3;Yjf@%m~eYza(m6O zj|RIgRu~-OO}r$LH7k7GvBFt<5)^(tZT-0GgO8(wWY5N*_p0BY6k8zdWV1l{>&wgT z`*zR&*X*soH)Pw39LFWA#n17cn`5aQ&HU+Dz|mU_&s#6>C{2Eyci>;z*;$tN4>21u zH;QQf)(e?c2tlXHiG@MXv4o{x{(0zdzDH`_8K+%x6?u{pit0t+JfZ&|jaf z@rQBle(};@)h=k8dwu4bN8-GJt@TxoqB8%@LodErziHNg(USN*U#~^)<7Y5%5v>)@ zm78Ypz0aI?PqgEL`OX|pa~`r=W_U0twg_AbXgDFYxb^C*Ba)`tAJ<0B*9rgr(xOAQ zKtnRTdy;ynyKcZgzvIm(CmwqhVze->fS32q%rzx;S9zXT$8sw@X?fVbdUEQj)YGmwx7=!KPvs0bZpfl&aKiWeTmP`%q-d?DVNgo+aUAK6_xcdf>Xppww>gbJz0^( z^Y{1n>F1g_r?8z#y}7e^InR3My8;G17w(>WvEoI7DdW?I6^FLEu(PdjUzW?P$gx<0 z(O-t)RL-MALDR2uhnVe-jTB`MUHpI6iY~r0!AIl&HOtmt{Ql+t!+Cu!{`uFNvU=^# z&wpZVH@l&>%}aNV!n!WLKQ7-C_rG{~J|uOr;->pr_w(ng7dnYu)3Et+e$|5)MxvJ) zk4XP*%`sMdvCpCY@C6$lNz(;yFS2jTyZh?M6*=>J6^nE3*Z;4*DRrU$!uf}1kA7gR zh~iXinb3AlVRb`eDl`ifxzjo~XWYJf?x*-ZD9w@$AniN$tS4ePL z_PYyC9M9*@`xAERQ`0tEg(?5y>dPC>0%vRw^%z0Cz zl)aGkFvsC)10Igszu)hV?=jQ4^q_tI_NAGZmp$L{W6$B{LrXpiO_@IZmQ>di-#E7` z342zSFOr-0>-=2naJ9dV36-}c{r?%-ZC!RCxuH0bJJ2Ncl!#zK;ygVG19yIN{wBem zca=4XC!g)Q-r{oc>D40wc83>F(aCsv z*zJy7wd>6OVhXc*HJWxbe>f!cD(<5=%c=HX$}+Z9A&>5S{&D9(vzSQw z87sEjapo3$uyYmvg=;(V!sBbVc0`{!dAj6A!mpYN0^0Fp{FI#f@bVcf=r>&_v7ajlXagQ^6l$Xw-_{1>b07K=g zeuK0#5;xn|&a4&{d(!XMW0}%#|8K{W&&Q%?ri~fc(0&*Wq9!NNGC_brSn73$JScpx?I|ltp(r2C?n&4Qm`N37G z7m~}SYdRi3{Q8Rj`|PKiGg@c+t@`!PdrikDufqnJJS%f1m84`PUsu0)=+Gf~%lWGh z2q;O!+}&M1oiqDmMU2*!t=ZRCRZ1JY5oBL1@7>!kXB#yw;ogSCW{KRq2eJpN3oj_# ztCU|Gyj<)49_P4;wP9 z*KBxX%il8Px6QpWw_iuQ#lyMT`D6l^+4-hyGdN}Mvv-2{smklIzTeK@FWUU;!^6XVZz2u0zxnlg{q#>&w^>pywK1%|@!+nv{@yQ>Zf(z>FD%`c zvSgx;m0*5RvsgrINagC^DH`z)7sh7^ZVSG2#Cu)X$7AdV5xDVe1szEf+35 z%G}=-a%&OK--VlAa)|2hb$ow4^Q+m#A5x;WJ5SzQUvHv4tAE<(l^LCO_fvoEx&Fdd z(6YT_&#~Gsh1XZ6teM$0<^9#nsMl|&7uA?8*`zigcTdcu|CL?UjihlQk~}M~50!P3(~Fkkc*< z5|#ZkQ_EuCCC`Pa0grZw*~o^bPL|#pv1-D?I)RYRMSfPbGrQ()Xl>$9(p{!-y^+0;}+{MfP&)@XO{p&u)RYI#d;=b4lhHVsn>kz!86xitv!13cvMf#+Q)|NuLW0!)GlVd zaQR%5$c*1C7mHfOg7z1>oZdU}Sk?wRF(vLTL4vxwxI&b5zIA|YvGAx-%mZa zUe9z-JykqYEaGp8)Ewr-?r8~m3t1;_^RA!2==0IKYRCS|p@;N+q@1;8tMuqj?9^lU zs<{O;3HfTP`VzjzI^pyf}v($CRIE zgSnaPGYX^+GfzKRc!ce3ySh`wcNUxFA2_Q1JAfMeDl!{V_q<(b~)t98TrsR zvrWM>p-$)0&mDhy_j7Mei*xYmHplMFYoIQAn!eKVqEVXxjC)3#kTsJ#YPqJnqM!Mhvv?H zfBM<)sx2S*8m!;%3I6)(s&|}5cUQ&rdEddE)Vygk^fWaC+xcXJyr=7ho}Q*#{O#76 z8HUdHzE9S|+DT>kuy1kU<6|qE+4-%i-|o5a@xr%fcb-MHoYkIQy52kBoolxk>po_! z$yJH}KcBbP&sREry1MZ0rl((0xkJC4;S2q-e7?1z3Xj0f$H)8ESN(Ur@OR#-^SeFE z--A4{Q|apc#W9zTcC8c)+xTjE(kmhDRnye{R@ZyZEBa#=vNd??ivbJh0x1GT8_d2|0%{4~tGq;m6+@YCaOx8IlB6_?R}J+9jK$j1{CmFM1g zlkw%KNY@&jiccriLq9(|oBCtJkr*(#H1 zp|ufVtM&veFL{1)$-9*Xm1k$0uh&{XS=~QuwfKPo(<$tXm4^@9-&ebP^YuC-rt@6$ z?l_PdbkF}J>zs(_bTrCmh9_(w+^p=-x#_&EHy+wMn7hC-rZf6 zh7UEfjh*Md`1yNP!7uCeuWr1m6)EIMeLH`ZSNr+ALrWM>yifVgyXk+*_41HP@92`I zQ_Hr${Gq#v|DNd^3xwTj1CJh$^b`sL;2t4BJ8 zpFTagLyTKoZ;G8&$%_DW*By59&+dT+v0lxpUMuu<{Y9}?cV8UM@?0`=m-3|(Hy8h( z7Zv!GTedynU(q2VyP1ED9%1QZp5MOz?mj2&$)^qkGxRe%O=w?<)Vp+m^)9C=1|--> zLmD74u^yAfd0h7IF^CiAl9fG~z;p8Zy=wn$46=Ml0#0lF=i7a{`!_{Crt0O=O|5~i z+;8lW%2IFhmQ*r2kvhkBZ^7DGrrFPGxc%SEzPhU7KELV`CBf{aLauW|4o-|;`Qqi< zRf}%MhYEWt#7cFn>FPed`o_l4N%3#a?+<*sRz5^j_t>d_FJAhW{t?!~>{wcgw?r&s zxf}oDzJSY%?jO1g{I*{vaD;ui>vQMlz1OVor-{cDe|We1{i$pGHVY2!HBLV_=RkG4 zfD^|`Z-q_AG7`616}p}Es#$$a{q)sZE50Ol8Lwkk7d`R38pu6m|K*PfMN2kXP4!tJ z9^=ehuBJWL-<0{M-}NRA%fufKU!}}^wbJ!k$?A=B4=fD56f`~KWxJ8`U4_~^_ao9- zl{hA|E!lMS?EQBkW%nIPLU_sx}+lV9E5zP{?&%ygI9D#PT^k1e-)qi39* zV;S7nzFR=TS<6St-1MY&ILp)4<-gSQB_;>F$Sb_EzrNlu!tnZuhDt5#@^@1zomWUR z-C6mr%+0;kfa8$<`ntcrJmY4rITJqp!LdV^`B?6hFqE1X{^Vj243qTPeJNo}NcV!{ zAr~7ftGX*wJ*Qqdv`Q-TQb^WAmcr1I2kMjLFDd>%rRJQnKXhOGqqRpkMf0zCi^~0K z)w0;-bF}2Z&PTofoGzt0UHHp-VY&tZ0hs$Q?O{#wW_xt_w zq)Xo`6W+~zKCfEu10*p|atvE27M^M}KdV_R^2WP>sju8*^KByb`-iPC-x|=U(A>Ua zdROMhQZJW?bvvE873Y*!eTvpR&3!AaA>dc_-@Cra+Kc90__*xM{1>`ydb>Ei9?M>y zbZQz$@^>?pO=3|7RS(V`7Ld<*zyE)o;R=I`clhn|y)Q5GJuewl^5_WX^U1z5OyZh8 zeVX*n=H?{dIDvG5#2J^L*8b{O|5g0_+*DVa3m5miQ2#V-Aj>wKb;Z}@ZX}`6uIiIt^5Vvm@_*xiz}Iv{zW-6 z$mtq~Tx>by{Qu3HwekhFMU20U#Ex0i{Mb*eyfH(u4&{rK=u^LNcENWS7n^b+4I z{1z_Va-sGA8ne8MiZA^rTkbLQ1~!h3YzEx($0 zX~#;>xS5mm^ppQAKh5pk@7%KU=xWBdua4b4SFx$zhK)xe;AxVqaazxt!(xx4_bxfL zT9HZIxNXBTuHv-@@3rS|)Z*(3*Zy|aI`pupV9)ba+c;i*PB_*hc}e|YV^g?x=q-f{ z|7JXI-M6RkvD?R4yZ7#~u;;k^d@qyD)qD}f7J;DK2ZFC$>gsAgCHug&sCj3Mgb_!+ z*q$h6+rwXsR9{q7%>DJUc5RK=+JeiTq4(=MMFZn9CBShr;ncg_3>R*0?)oP+>zF=w zepn(=tYeUM2qCMhko4iyfN^lUH|sE z6YD-cI(qd`BQyJz1C7i}b@$wpf5OT?J3emamA!h7d-wnS7Hzoe;oT2SKdr9E*YCY@ z`}Q`4%T=}?4lu9sp04+5>GZgu-{0OACmn7S7gd+~8r1nnZ`G$o?=`gxy&^x_pZ@MK zGj`jlXZNS)9^ANjwZgRRyZl}K-v?|I-sZtI`Pe1A$vZW zR{6WQYVn^kIOOu!PAjfzuGg_yD?NV3&0V(jUY+LgbmvvSx&MkB?zs4T0|TqrDM$Mw z&NF@L6bxOqxcAF_GGNf3bj;G{$BV`NPTwo*>75BcG6SV z#x3&bD=+P3TvL|b%4)nETi^F$|7!P8r%MS(_p>W4HS&Kwf0FuD(}_-z=l(i}2CBwv z2zuxsd)-;SdMBS}ZH>EbiC+JaE6?Y(8p&OLzRNmjkzeGiIVAV$RD=G${Wg1X|F*WX zZQ+NWDDRWgmGGExp|6W6MC!g^{(%Yea&K=tx#?!bqMk~T865o!i{g4VaxFf2`h5Mr zVoSc`k8L8R^6OtHeDd|%?f0jxogGqo{A@t{g0n%oZ#z#;F*qe(^TF}Hx=KWfO3vO5 zPc*(QJi9qkW67UMzpu>XD^_U$jg9SlE~Jwa_~omyR^)}KsatD(K569toe&fi(s*i_ zvI<`+!>0J@>(yB9#(!|~ooVD+`}67aqO}auO7rjR*jV+bQ{Cv5ecBDRJzYD*-c8_~ z;W7I(B&k@e6UfoJ-zI{(w(z!qH9lZ{|GMcr_fv51 z>XrBDc2DM@o3EbVzMr>x%a$wmm%Do~Gqu@0`*w_+Cbj zFlcrs_`?Blrh~orITp9E+?&WMX<_@XSN5Uv43nKqm$~=w$3Oh~Nl$G${|`P{l_d)q z3t9E=*8e$Pf8tcpjO|a&&lq%=<=#3`eas*R-2F`A1U1kO33ne2F_D^@*sR9lTbrSg z5TW2AvM1iL#dEUunJGf$(#aW#c250bAhjHdN2b?&&M;Nc*aBT;s&YJK?;dN2T#GYD`ZUYabu)Kh0gxeDCH|&W-!Gg%s@%`slmo zDA-^#z6k6Za}&u71@tHbpx1$FM7`15A-d8_K&KXE76HdSg$ z$Jw-*J4~N4WrcG)-^!)l(^sXQo@QB{i+^U11v;~*{=VBtL4OZBS8o2fxBJ9aoIcEN zzh>R8S6Z6<_pGLDm zzb7QIi0$xw77hi8?|FgE#f}~i)?UBSU!oherQn;ErTV8=cXnlz zTXF(4m&&oz;iG7jcKA9GM@TP6Vo$GRoUrg88wP`C*Vjg?#|i5jd;?9f$+5}USAWYf ze5Y8!v+`0z*w?~H+>>lq!INyvps}KJaknqCoaaKCWP4}n^5F(UOt*r;629Ym{(L$e zBsYh-%|}Y%=h^a4v!nwrK1{#t@_W9m7__$oT8kmzRMfuyLXq^x zmkrAq4qp>!vhk6%Dw&Xbds}YmYc}VtWp8dM&M&m-N#zicINxTF$zys}8$5By+W2Vt z^?A0{N0M0>Q^8Yj_p9IA-els??QrDSYFGQ~M7i=Bp6PK_D{~YDnhwaQ@L0A)IN$71 z&pzD78+2^L)06H2`W#0T3}>7*J-RjP+M1c4b!|TSPg?a!)Ov}_e5*^xfg`snydx z0?t_;Zzp_Bl1Q5&^^6C3ekkcgwc+R12fl@m#nOz^&rNx3=)-rQf(_Dy*{P(VU(x3i zXYlW#X;Js$e}8{>D;$ndc7A_v@6~g2tyAv_ylQJmYxHWSf4`?n+&v+oxySEeLg=sd-cxF;#5I?4xN1K!-rcf6IM1HkTOo|xwWHkamBiA zxwq8{>zs8OciVhreD=%HfW5WN?^DA+e{RKtIkro@nJ=;irna#wIRqT6e(HXx>{*wD z&g?X93y|Xkf~-??w>)4h!%wr|@u->zo6*pjfP_lA-z)3eI8vAe@gF`pN;N&Yb9 zZt;2B=Nyp*r**e`?1`^@#dJmZt%S&(gbdXqE8=Z8u@+yJVtRD3s7))Z^(tq&KDdxx zslQ1qN@8DYVqspwn?o=Svx-biBH_ zxc$=g=&hNTm%Xx)SoHn<|9|iO^2{{&_Y~AUJ?U=X{uVUJQ1yH5o*5@iS@~@~G^{!H zkJ<8o-N1HYh~o-%Umy<`{my{t9M@BkxQ-KP3XHk%eL~{*K9~wP5U4k zHKUmI@x3(<+NWTU$I`SmNGve|A|MD99Z#>2`z3+NiBUkL{6$*CpPWuAI*J`OXCSTjyR29*NPa z2;Zy8CF*#=yQ4mrnc(+aX z(a%5UdxU%6r?jVSl=@&`}3o)^1Wy{j|$ioKN)PJmc%s% zRDHSV?ut1Ce0uZq^Yisj@4jvxroMF1-?!p?pypl61a9H@ezAMbCC}%UuZr7Sb+S9* z`kKha^J>3ErmyGSBVaIL@1GyX?Ze*h`P}zeSEk?QQwL}{t`^pzUtT#Ii_}>LORW88 z>}ppH-P?5Q{Dy>sO!tc%14`c92<(+M_mj1$xNtN3`PY}r=X-&dD6zi!^x-i7>ecIZ zd7WyW{wwd!j*YL5?wL7FU3`HbXmqcL<*Dqle1PT{u}W;tFS>1dQu-Fcjt zqq-8W*bLK|SOi>}qJ6;2i-OGW*KB^{zDrCu%A)%1^e?a#Mn>7!bOa+U^iMSxJ**Kh z%4<5+{CZBdn(wS7I;Vrq+yCDq96WbJE=RyI(ApxFo1o#{2yn^l^ol)x;nt$3UVyg;9cOgP&4*CJ3Bjk>h+V8)mLBTPPid`s<~m0qR6)V`|sXtwe|gQ;Xt%$*_#N{ z%1*xUFP=`1pZ4j2j7I$VdA6&!CI(baI(f(cY4-JXbFV0$ z_?@z@dY74r0`I!??Rj_4y%bMuP+yf%=OU`xvEtB9!H-@$C;pI3&zI!kcbOxprg8l7 z?qV6x!iv0eC$oRt{QGPV2P=Qnrt?dBeb>~LnA6YAnYfnm`B4KGfo(QBSt^}xuufdZ`}Y9S zYMd!H3qor4>T0EOB(N2)eKcPs^r^Pz)Ph+8^L-E4HO~ouF8cq5=YG?bN!xE1D(pMm z=l{=Bb9Kb=@7qG2de!#zdW!Bf+iV1>{(mWgh9eD3&q%&P8jd{j`q9xd;!Wm9d3(|i zpP6a=w1P*R*^Qya^YJpZ%BNim_B=>6taQ9^F#Cy^``_Q+#SK4xJT7l-==Js8-RQS> zb_TayUzo=s;r1dgy~B&6N16Z&p1;sSY%`5dQVTg?Xk+fU?V z@89+;xMCNU8JiQk?DAT_jvw9i8S}62iZKJ1AS(SQqcZmX|M%OdC->2j&P^cZQH|qD zymdb+qi31rR-F@AFRbooF+T^o(xl}1$!R&Cj1IAXp19}mms#fd>zdG$qfcV{Xx&p zZQK&EtJ)!C=EFt~0sjwiKPMKrOjaOPNnj=DA!Y=*Rt=s4F&hzi_ z1g-a2>&eb9&$3a_Mj%fhE<*0E_L~E`+wUkj9ba#=(&1;o{{;`&;>?d4%ziWAx zbAx3nFXP9Ioo!-X5obfWz@_&&@l9e;AG#7erb|nlHJJCef#Cylo26KafrG?>$&bEW zfW&*M*RDN1;cBsQ5q@$^ht3~Tg;bOUbj8Me)`C0^i8IHm{(L7I~;y%&+TWFi#tt?=F4lgf)1c9pXW5@FaaGdwVN1_wKIHO9wW%%kCFB0tH0dUL+3h-)^acY z`{m!fs{co=*4}g56`_@AlD+g^eRJRC=Z6apdSusJV}H1@-L8GlhaIc?b_dDFuX@b) z+G6e2$?5U4-N3c>Cz<$#t%_*|1!uYHbfdS4FmKzjBVzB@YtcgOOAkHlZE)m2yubGM zx1=rSAq}C4_ZPeK8~)nM_Gy{#>?0G7d1n^R%P`SOO1!!%)Q`*BcXim>BR}}Pl0Bw} z@A}-bayMhr8nv%R4u2dR7QEdfcQE(%w$ABntF0f|L}?yI$HnwQ_ss~9a}E_R$TCC8qe3}1)FZYs1@~6eZ#7o z>nL(PQ~!GA?w1R;3xs#}p8Kc&rQTxtIquaQNrgNdYme~hzWTCpW3-N_^wSQV-Z$5O z9sdnPv?ttP~ z-d3@b+z(t^ZZw@Zl@cfM>_lRO;+~SNmh&N*e1gvc#GLr#udABDWmAiQ(;uX{a>C6f tE?sawaN;;=D1ul*ju Date: Sat, 16 Sep 2023 15:08:37 -0400 Subject: [PATCH 039/170] nestlog: README improvements --- README.md | 71 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 4943e8f0..8145c91a 100644 --- a/README.md +++ b/README.md @@ -42,53 +42,60 @@ main(int argc, char ** argv) { ``` output: -![ex12 output](img/ex1.png) +![ex1 output](img/ex1.png) + +- nestlog types are provided in the `xo` namespace. + macros are prefixed with `XO_` +- indentation reflects call structure. We don't see anything for `main()`, + since we didn't put any logging there ### 2 - /* examples ex2/ex2.cpp */ +``` +/* examples ex2/ex2.cpp */ - #include "nestlog/scope.hpp" +#include "nestlog/scope.hpp" - using namespace xo; +using namespace xo; - int - fib(int n) { - scope log(XO_ENTER0(info), ":n ", n); +int +fib(int n) { + scope log(XO_ENTER0(info), ":n ", n); - int retval = 1; - - if (n >= 2) { - retval = fib(n - 1) + fib(n - 2); - log && log(":n ", n); - } - - log.end_scope("<- :retval ", retval); - - return retval; - } - - int - main(int argc, char ** argv) { - log_config::min_log_level = xo::log_level::info; - log_config::indent_width = 4; - - int n = 4; - - scope log(XO_ENTER0(info), ":n ", 4); - - int fn = fib(n); + int retval = 1; + if (n >= 2) { + retval = fib(n - 1) + fib(n - 2); log && log(":n ", n); - log && log("<- :fib(n) ", fn); } + log.end_scope("<- :retval ", retval); + + return retval; +} + +int +main(int argc, char ** argv) { + log_config::min_log_level = xo::log_level::info; + log_config::indent_width = 4; + + int n = 4; + + scope log(XO_ENTER0(info), ":n ", 4); + + int fn = fib(n); + + log && log(":n ", n); + log && log("<- :fib(n) ", fn); +} +``` + output: ![ex2 output](img/ex2.png) ### 3 example exposing runtime configuration options - ``` +``` /* examples ex3/ex3.cpp */ #include "nestlog/scope.hpp" @@ -135,7 +142,7 @@ output: } /* ex3/ex3.cpp */ - ``` +``` output: ![ex3 output](img/ex3.png) From 0260ca79c1737d2bfbbaf95300ccb1a315e3d0f0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 15:16:10 -0400 Subject: [PATCH 040/170] nestlog: expand ex2 --- README.md | 5 ++++- example/ex1/ex1.cpp | 12 ++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8145c91a..1c2df2a3 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ output: - indentation reflects call structure. We don't see anything for `main()`, since we didn't put any logging there -### 2 +### 2 slightly more elaborate ``` /* examples ex2/ex2.cpp */ @@ -89,6 +89,9 @@ main(int argc, char ** argv) { log && log("<- :fib(n) ", fn); } ``` +- global configuration settings live in the `xo::log_config` class. see [log_config.hpp](include/nestlog/log_config.hpp) +- the recommended form `log && log(...)` tests whether logging at this site is enabled /before/ evaluating/formatting the log message; + when logging is disabled, this saves the cost of computing and formatting that message. output: ![ex2 output](img/ex2.png) diff --git a/example/ex1/ex1.cpp b/example/ex1/ex1.cpp index db0ce39e..1258e2a5 100644 --- a/example/ex1/ex1.cpp +++ b/example/ex1/ex1.cpp @@ -2,13 +2,17 @@ using namespace xo; -void A(int x) { - XO_SCOPE(log, info); +void inner(int x) { + scope log(XO_ENTER0(always), ":x ", x); +} - log("x:", x); +void outer(int y) { + scope log(XO_ENTER0(always), ":y ", y); + + inner(2*y); } int main(int argc, char ** argv) { - A(66); + outer(123); } From 335083579e5b33db98146865ca88198870a69fe4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 15:20:16 -0400 Subject: [PATCH 041/170] nestlog: README: format nits --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1c2df2a3..587893f9 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ output: - indentation reflects call structure. We don't see anything for `main()`, since we didn't put any logging there -### 2 slightly more elaborate +### 2 slightly more elaborate example ``` /* examples ex2/ex2.cpp */ @@ -89,13 +89,13 @@ main(int argc, char ** argv) { log && log("<- :fib(n) ", fn); } ``` +output: +![ex2 output](img/ex2.png) + - global configuration settings live in the `xo::log_config` class. see [log_config.hpp](include/nestlog/log_config.hpp) - the recommended form `log && log(...)` tests whether logging at this site is enabled /before/ evaluating/formatting the log message; when logging is disabled, this saves the cost of computing and formatting that message. -output: -![ex2 output](img/ex2.png) - ### 3 example exposing runtime configuration options ``` From 8268eef8b288c62a9d5552e481567e4315bf06cb Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 15:20:29 -0400 Subject: [PATCH 042/170] nestlog: fix defualt indenting --- include/nestlog/log_config.hpp | 4 ++-- include/nestlog/log_state.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/nestlog/log_config.hpp b/include/nestlog/log_config.hpp index 00e49249..76ecf63f 100644 --- a/include/nestlog/log_config.hpp +++ b/include/nestlog/log_config.hpp @@ -19,7 +19,7 @@ namespace xo { static bool time_local_flag; /* true to log time-of-day with microsecond precision; false for millisecond precision */ static bool time_usec_flag; - /* spaces per nesting level */ + /* spaces per nesting level. 0 -> no indenting */ static std::uint32_t indent_width; /* max #of spaces to introduce when indenting */ static std::uint32_t max_indent_width; @@ -62,7 +62,7 @@ namespace xo { template std::uint32_t - log_config_impl::indent_width = 1; + log_config_impl::indent_width = 2; template std::uint32_t diff --git a/include/nestlog/log_state.hpp b/include/nestlog/log_state.hpp index 9bf6fefb..01566380 100644 --- a/include/nestlog/log_state.hpp +++ b/include/nestlog/log_state.hpp @@ -229,7 +229,7 @@ namespace xo { << ")"; } - if (log_config::indent_width > 1) + if (log_config::indent_width > 0) this->ss_ << ' '; /* scope name - note no trailing newline; expect .preamble()/.postamble() caller to supply */ From 61441f25137acd3d7e83917933a3e38bc306a30e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 15:24:25 -0400 Subject: [PATCH 043/170] include/nestlog -> include/indentlog --- include/{nestlog => indentlog}/array.hpp | 0 include/{nestlog => indentlog}/code_location.hpp | 0 include/{nestlog => indentlog}/color.hpp | 0 include/{nestlog => indentlog}/concat.hpp | 0 include/{nestlog => indentlog}/filename.hpp | 0 include/{nestlog => indentlog}/fixed.hpp | 0 include/{nestlog => indentlog}/function.hpp | 0 include/{nestlog => indentlog}/log_config.hpp | 0 include/{nestlog => indentlog}/log_level.hpp | 0 include/{nestlog => indentlog}/log_state.hpp | 0 include/{nestlog => indentlog}/log_streambuf.hpp | 0 include/{nestlog => indentlog}/pad.hpp | 0 include/{nestlog => indentlog}/printer.hpp | 0 include/{nestlog => indentlog}/quoted.hpp | 0 include/{nestlog => indentlog}/quoted_char.hpp | 0 include/{nestlog => indentlog}/scope.hpp | 0 include/{nestlog => indentlog}/tag.hpp | 0 include/{nestlog => indentlog}/tag_config.hpp | 0 include/{nestlog => indentlog}/time.hpp | 0 include/{nestlog => indentlog}/tostr.hpp | 0 include/{nestlog => indentlog}/vector.hpp | 0 21 files changed, 0 insertions(+), 0 deletions(-) rename include/{nestlog => indentlog}/array.hpp (100%) rename include/{nestlog => indentlog}/code_location.hpp (100%) rename include/{nestlog => indentlog}/color.hpp (100%) rename include/{nestlog => indentlog}/concat.hpp (100%) rename include/{nestlog => indentlog}/filename.hpp (100%) rename include/{nestlog => indentlog}/fixed.hpp (100%) rename include/{nestlog => indentlog}/function.hpp (100%) rename include/{nestlog => indentlog}/log_config.hpp (100%) rename include/{nestlog => indentlog}/log_level.hpp (100%) rename include/{nestlog => indentlog}/log_state.hpp (100%) rename include/{nestlog => indentlog}/log_streambuf.hpp (100%) rename include/{nestlog => indentlog}/pad.hpp (100%) rename include/{nestlog => indentlog}/printer.hpp (100%) rename include/{nestlog => indentlog}/quoted.hpp (100%) rename include/{nestlog => indentlog}/quoted_char.hpp (100%) rename include/{nestlog => indentlog}/scope.hpp (100%) rename include/{nestlog => indentlog}/tag.hpp (100%) rename include/{nestlog => indentlog}/tag_config.hpp (100%) rename include/{nestlog => indentlog}/time.hpp (100%) rename include/{nestlog => indentlog}/tostr.hpp (100%) rename include/{nestlog => indentlog}/vector.hpp (100%) diff --git a/include/nestlog/array.hpp b/include/indentlog/array.hpp similarity index 100% rename from include/nestlog/array.hpp rename to include/indentlog/array.hpp diff --git a/include/nestlog/code_location.hpp b/include/indentlog/code_location.hpp similarity index 100% rename from include/nestlog/code_location.hpp rename to include/indentlog/code_location.hpp diff --git a/include/nestlog/color.hpp b/include/indentlog/color.hpp similarity index 100% rename from include/nestlog/color.hpp rename to include/indentlog/color.hpp diff --git a/include/nestlog/concat.hpp b/include/indentlog/concat.hpp similarity index 100% rename from include/nestlog/concat.hpp rename to include/indentlog/concat.hpp diff --git a/include/nestlog/filename.hpp b/include/indentlog/filename.hpp similarity index 100% rename from include/nestlog/filename.hpp rename to include/indentlog/filename.hpp diff --git a/include/nestlog/fixed.hpp b/include/indentlog/fixed.hpp similarity index 100% rename from include/nestlog/fixed.hpp rename to include/indentlog/fixed.hpp diff --git a/include/nestlog/function.hpp b/include/indentlog/function.hpp similarity index 100% rename from include/nestlog/function.hpp rename to include/indentlog/function.hpp diff --git a/include/nestlog/log_config.hpp b/include/indentlog/log_config.hpp similarity index 100% rename from include/nestlog/log_config.hpp rename to include/indentlog/log_config.hpp diff --git a/include/nestlog/log_level.hpp b/include/indentlog/log_level.hpp similarity index 100% rename from include/nestlog/log_level.hpp rename to include/indentlog/log_level.hpp diff --git a/include/nestlog/log_state.hpp b/include/indentlog/log_state.hpp similarity index 100% rename from include/nestlog/log_state.hpp rename to include/indentlog/log_state.hpp diff --git a/include/nestlog/log_streambuf.hpp b/include/indentlog/log_streambuf.hpp similarity index 100% rename from include/nestlog/log_streambuf.hpp rename to include/indentlog/log_streambuf.hpp diff --git a/include/nestlog/pad.hpp b/include/indentlog/pad.hpp similarity index 100% rename from include/nestlog/pad.hpp rename to include/indentlog/pad.hpp diff --git a/include/nestlog/printer.hpp b/include/indentlog/printer.hpp similarity index 100% rename from include/nestlog/printer.hpp rename to include/indentlog/printer.hpp diff --git a/include/nestlog/quoted.hpp b/include/indentlog/quoted.hpp similarity index 100% rename from include/nestlog/quoted.hpp rename to include/indentlog/quoted.hpp diff --git a/include/nestlog/quoted_char.hpp b/include/indentlog/quoted_char.hpp similarity index 100% rename from include/nestlog/quoted_char.hpp rename to include/indentlog/quoted_char.hpp diff --git a/include/nestlog/scope.hpp b/include/indentlog/scope.hpp similarity index 100% rename from include/nestlog/scope.hpp rename to include/indentlog/scope.hpp diff --git a/include/nestlog/tag.hpp b/include/indentlog/tag.hpp similarity index 100% rename from include/nestlog/tag.hpp rename to include/indentlog/tag.hpp diff --git a/include/nestlog/tag_config.hpp b/include/indentlog/tag_config.hpp similarity index 100% rename from include/nestlog/tag_config.hpp rename to include/indentlog/tag_config.hpp diff --git a/include/nestlog/time.hpp b/include/indentlog/time.hpp similarity index 100% rename from include/nestlog/time.hpp rename to include/indentlog/time.hpp diff --git a/include/nestlog/tostr.hpp b/include/indentlog/tostr.hpp similarity index 100% rename from include/nestlog/tostr.hpp rename to include/indentlog/tostr.hpp diff --git a/include/nestlog/vector.hpp b/include/indentlog/vector.hpp similarity index 100% rename from include/nestlog/vector.hpp rename to include/indentlog/vector.hpp From f71c009a0f959f5eb0355899a5ce2667af7b21e3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 15:25:17 -0400 Subject: [PATCH 044/170] indentlog: update README --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 587893f9..0948f28f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# nestlog -- logging with automatic call-graph indenting +# indentlog -- logging with automatic call-graph indenting -Nestlog is a lightweight header-only library for console logging. +Indentlog is a lightweight header-only library for console logging. ## Features @@ -21,7 +21,7 @@ Nestlog is a lightweight header-only library for console logging. ### 1 ``` -#include "nestlog/scope.hpp" +#include "indentlog/scope.hpp" using namespace xo; @@ -44,7 +44,7 @@ main(int argc, char ** argv) { output: ![ex1 output](img/ex1.png) -- nestlog types are provided in the `xo` namespace. +- indentlog types are provided in the `xo` namespace. macros are prefixed with `XO_` - indentation reflects call structure. We don't see anything for `main()`, since we didn't put any logging there @@ -54,7 +54,7 @@ output: ``` /* examples ex2/ex2.cpp */ -#include "nestlog/scope.hpp" +#include "indentlog/scope.hpp" using namespace xo; @@ -92,7 +92,7 @@ main(int argc, char ** argv) { output: ![ex2 output](img/ex2.png) -- global configuration settings live in the `xo::log_config` class. see [log_config.hpp](include/nestlog/log_config.hpp) +- global configuration settings live in the `xo::log_config` class. see [log_config.hpp](include/indentlog/log_config.hpp) - the recommended form `log && log(...)` tests whether logging at this site is enabled /before/ evaluating/formatting the log message; when logging is disabled, this saves the cost of computing and formatting that message. @@ -101,7 +101,7 @@ output: ``` /* examples ex3/ex3.cpp */ - #include "nestlog/scope.hpp" + #include "indentlog/scope.hpp" using namespace xo; From 2f78963bed5d70cbbbcd7c425c39505a35813bd8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 17:45:27 -0400 Subject: [PATCH 045/170] indentlog: function: special-case printing operator() method --- include/indentlog/function.hpp | 80 +++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index 42c5752f..e6e6600f 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -50,16 +50,30 @@ namespace xo { } /*print_simple*/ /* e.g. - * std::vector xo::sometemplateclass::fib(int, char**) - * ^ ^ - * p q + * <----------------------------------- s2 ---------------------------------------> + * <--------------------- s3 -----------------> + * <----------------- s4 -----------------> + * std::vector xo::sometemplateclass::fib(int, char**) const + * ^ ^ ^ + * q r p + * + * sometemplateclass ::fib <- .print_aux() + * */ static void print_streamlined(std::ostream & os, std::string_view const & s) { - std::size_t p = exclude_return_type(s); - std::string_view s2 = s.substr(p); - std::size_t q = find_toplevel_sep(s2, false /*!last_flag*/); + std::size_t p = exclude_const_suffix(s); + std::string_view s2 = s.substr(0, p); /*no const suffix */ + std::size_t q = exclude_return_type(s2); + std::string_view s3 = s2.substr(q); /*no return type*/ + std::size_t r = find_toplevel_sep(s3, false /*!last_flag*/); + std::string_view s4 = s3.substr(r); /*no namespace qualifier (unless function)*/ - print_aux(os, s2.substr(q)); + //std::cerr << "print_streamlined: s=[" << s << "], p=" << p << std::endl; + //std::cerr << "print_streamlined: s2=[" << s2 << "], q=" << q << std::endl; + //std::cerr << "print_streamlined: s3=[" << s3 << "], r=" << r << std::endl; + //std::cerr << "print_streamlined: s4=[" << s4 << "]" << std::endl; + + print_aux(os, s4); } /*print_streamlined*/ private: @@ -91,10 +105,23 @@ namespace xo { return 0; } /*exclude_return_type*/ + static std::size_t exclude_const_suffix(std::string_view const & s) { + constexpr std::uint32_t c_prefix_z = 6 /*strlen(" const")*/; + + if ((s.size() > c_prefix_z) + && (s.substr(s.size() - c_prefix_z) == " const")) + { + return s.size() - c_prefix_z; + } + + return s.size(); + } /*exclude_const_suffix*/ + /* e.g. * xo::ns::someclass::somemethod(xo::enum1, std::vector) * ^ * return this pos + * (pos just after 2nd-last non-nested separator) * * last_flag: return pos after last :: * !last_flag: return pos after 2nd-last :: @@ -135,7 +162,9 @@ namespace xo { --nesting_level; } - return last_flag ? pos_after_last_sep : pos_after_2ndlast_sep; + std::size_t retval = (last_flag ? pos_after_last_sep : pos_after_2ndlast_sep); + + return retval; } /*find_toplevel_sep*/ /* fib(int, char **) --> fib @@ -143,7 +172,7 @@ namespace xo { * foo::bar>() -> foo::bar */ static void print_aux(std::ostream & os, std::string_view const & s) { - //std::cerr << "print_aux: s=" << s << std::endl; + //std::cerr << "print_aux: s=[" << s << "]" << std::endl; /* strategy: * - print left-to-right, omit anything between matching <> or () pairs. @@ -152,17 +181,44 @@ namespace xo { */ std::size_t nesting_level = 0; + /* index of next match within string 'operator()'. + * if we would print 'operator', and it's followed by trailing paren pair, + * then don't exclude the trailing () + */ + std::int32_t match_operator_ix = 0; + constexpr char const * c_target_str = "operator("; + for (char ch : s) { - if (ch == '<' || ch == '(') + //std::cerr << "print_aux: ch=[" << ch << "]" << ", nesting_level=" << nesting_level << ", match_operator_ix=" << match_operator_ix << std::endl; + + /* looking for match on 'operator(' at nesting level 0 */ + if ((nesting_level == 0) && (ch == c_target_str[match_operator_ix]) && (match_operator_ix < 9)) + ++match_operator_ix; + else + match_operator_ix = 0; + + /* don't increment nesting level if immediately after 'operator' */ + if (ch == '<') { ++nesting_level; + } else if (ch == '(') { + if ((nesting_level == 0) && (match_operator_ix == 9)) { + /* special case: + * 012345678 + * operator( + * at toplevel; don't count the '(' here toward nesting level + */ + ; + } else { + ++nesting_level; + } + } if (nesting_level == 0) os << ch; - if (ch == '>' || ch == ')') + if (nesting_level > 0 && ((ch == '>') || (ch == ')'))) --nesting_level; } - } /*print_aux*/ private: From 238edb1619068fb28f5b73b3c525a69e49558b24 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 17:46:09 -0400 Subject: [PATCH 046/170] indentlog: bugfix: rename include paths --- example/ex1/ex1.cpp | 2 +- example/ex2/ex2.cpp | 2 +- example/ex3/ex3.cpp | 2 +- include/indentlog/quoted.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/ex1/ex1.cpp b/example/ex1/ex1.cpp index 1258e2a5..91e321e2 100644 --- a/example/ex1/ex1.cpp +++ b/example/ex1/ex1.cpp @@ -1,4 +1,4 @@ -#include "nestlog/scope.hpp" +#include "indentlog/scope.hpp" using namespace xo; diff --git a/example/ex2/ex2.cpp b/example/ex2/ex2.cpp index 23bb2b3e..f329b9d4 100644 --- a/example/ex2/ex2.cpp +++ b/example/ex2/ex2.cpp @@ -1,6 +1,6 @@ /* examples ex2/ex2.cpp */ -#include "nestlog/scope.hpp" +#include "indentlog/scope.hpp" using namespace xo; diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 452998f8..281a6e33 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -1,6 +1,6 @@ /* examples ex3/ex3.cpp */ -#include "nestlog/scope.hpp" +#include "indentlog/scope.hpp" using namespace xo; diff --git a/include/indentlog/quoted.hpp b/include/indentlog/quoted.hpp index 5e4cc8b4..15d7a397 100644 --- a/include/indentlog/quoted.hpp +++ b/include/indentlog/quoted.hpp @@ -5,7 +5,7 @@ #pragma once -#include "nestlog/tostr.hpp" +#include "tostr.hpp" #include #include #include From 4785ae6805b5bf9864883b824c1b67582924d974 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 17:46:35 -0400 Subject: [PATCH 047/170] indentlog: + example/ex4 --- example/CMakeLists.txt | 1 + example/ex4/CMakeLists.txt | 2 ++ example/ex4/ex4.cpp | 44 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 example/ex4/CMakeLists.txt create mode 100644 example/ex4/ex4.cpp diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 06512248..7f8eb99d 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -10,6 +10,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") add_subdirectory(ex1) add_subdirectory(ex2) add_subdirectory(ex3) +add_subdirectory(ex4) # ---------------------------------------------------------------- # make standard directories for std:: includes explicit diff --git a/example/ex4/CMakeLists.txt b/example/ex4/CMakeLists.txt new file mode 100644 index 00000000..02c1f301 --- /dev/null +++ b/example/ex4/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(ex4 ex4.cpp) +xo_include_options(ex4) diff --git a/example/ex4/ex4.cpp b/example/ex4/ex4.cpp new file mode 100644 index 00000000..82e361db --- /dev/null +++ b/example/ex4/ex4.cpp @@ -0,0 +1,44 @@ +/* @file ex4.cpp */ + +#include "indentlog/scope.hpp" + +using namespace xo; + +class Quadratic { +public: + Quadratic(double a, double b, double c) : a_{a}, b_{b}, c_{c} {} + + double operator() (double x) const { + scope log(XO_ENTER0(info), tag("a", a_), xtag("b", b_), xtag("c", c_), xtag("x", x)); + + double retval = (a_ * x * x) + (b_ * x) + c_; + + log.end_scope("<-", xtag("retval", retval)); + + return retval; + } + +private: + double a_ = 0.0;; + double b_ = 0.0; + double c_ = 0.0; +}; + +int +main(int argc, char ** argv) { + //log_config::style = FS_Pretty; + log_config::style = FS_Streamlined; + log_config::min_log_level = log_level::info; + + scope log(XO_ENTER0(info)); + + Quadratic quadratic(2.0, -5.0, 7.0); + + double x = 3.0; + double r = quadratic(3.0); + + log && log(tag("x", x)); + log && log("<-", xtag("quadratic(x)", r)); +} + +/* end ex4.cpp */ From 814879fd7b85178ee5c9aa8691a78ed0f14a6b38 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 17:52:38 -0400 Subject: [PATCH 048/170] indentlog: ex4 exercise signature styles --- README.md | 129 ++++++++++++++++++++++++++++++++------------ example/ex4/ex4.cpp | 15 ++++-- img/ex4.png | Bin 0 -> 39790 bytes 3 files changed, 107 insertions(+), 37 deletions(-) create mode 100755 img/ex4.png diff --git a/README.md b/README.md index 0948f28f..5d65bc86 100644 --- a/README.md +++ b/README.md @@ -99,53 +99,114 @@ output: ### 3 example exposing runtime configuration options ``` - /* examples ex3/ex3.cpp */ +/* examples ex3/ex3.cpp */ - #include "indentlog/scope.hpp" +#include "indentlog/scope.hpp" - using namespace xo; +using namespace xo; - int - fib(int n) { - scope log(XO_ENTER0(info), tag("n", n)); +int +fib(int n) { + scope log(XO_ENTER0(info), tag("n", n)); - int retval = 1; + int retval = 1; - if (n >= 2) { - retval = fib(n - 1) + fib(n - 2); - } - - log.end_scope(tag("n", n), " <-", xtag("retval", retval)); - - return retval; + if (n >= 2) { + retval = fib(n - 1) + fib(n - 2); } - int - main(int argc, char ** argv) { - log_config::min_log_level = log_level::info; - log_config::time_enabled = true; - log_config::time_local_flag = true; - log_config::style = FS_Streamlined; - log_config::indent_width = 4; - log_config::max_indent_width = 30; - log_config::location_tab = 80; - log_config::encoding = CE_Xterm; - log_config::function_entry_color = 69; - log_config::function_exit_color = 70; - log_config::code_location_color = 166; + log.end_scope(tag("n", n), " <-", xtag("retval", retval)); - int n = 3; + return retval; +} - scope log(XO_ENTER0(info), ":n ", 4); +int +main(int argc, char ** argv) { + log_config::min_log_level = log_level::info; + log_config::time_enabled = true; + log_config::time_local_flag = true; + log_config::style = FS_Streamlined; + log_config::indent_width = 4; + log_config::max_indent_width = 30; + log_config::location_tab = 80; + log_config::encoding = CE_Xterm; + log_config::function_entry_color = 69; + log_config::function_exit_color = 70; + log_config::code_location_color = 166; - int fn = fib(n); + int n = 3; - log && log(tag("n", n)); - log && log("<-", xtag("fib(n)", fn)); - } + scope log(XO_ENTER0(info), ":n ", 4); - /* ex3/ex3.cpp */ + int fn = fib(n); + + log && log(tag("n", n)); + log && log("<-", xtag("fib(n)", fn)); +} + +/* ex3/ex3.cpp */ ``` output: ![ex3 output](img/ex3.png) + +### 4 example: function signatures + +``` +/* @file ex4.cpp */ + +#include "indentlog/scope.hpp" + +using namespace xo; + +class Quadratic { +public: + Quadratic(double a, double b, double c) : a_{a}, b_{b}, c_{c} {} + + double operator() (double x) const { + scope log(XO_ENTER0(info), tag("a", a_), xtag("b", b_), xtag("c", c_), xtag("x", x)); + + double retval = (a_ * x * x) + (b_ * x) + c_; + + log.end_scope("<-", xtag("retval", retval)); + + return retval; + } + +private: + double a_ = 0.0;; + double b_ = 0.0; + double c_ = 0.0; +}; + +int +main(int argc, char ** argv) { + //log_config::style = FS_Pretty; + log_config::style = FS_Streamlined; + log_config::min_log_level = log_level::info; + + scope log(XO_ENTER0(info)); + + Quadratic quadratic(2.0, -5.0, 7.0); + + double x = 3.0; + double r = 0.0; + + log_config::style = FS_Pretty; + + r = quadratic(x); + + log_config::style = FS_Streamlined; + + r = quadratic(x); + + log_config::style = FS_Simple; + + r = quadratic(x); +} + +/* end ex4.cpp */ +``` + +output: +![ex4 output](img/ex4.png) diff --git a/example/ex4/ex4.cpp b/example/ex4/ex4.cpp index 82e361db..05ca39e0 100644 --- a/example/ex4/ex4.cpp +++ b/example/ex4/ex4.cpp @@ -35,10 +35,19 @@ main(int argc, char ** argv) { Quadratic quadratic(2.0, -5.0, 7.0); double x = 3.0; - double r = quadratic(3.0); + double r = 0.0; - log && log(tag("x", x)); - log && log("<-", xtag("quadratic(x)", r)); + log_config::style = FS_Pretty; + + r = quadratic(x); + + log_config::style = FS_Streamlined; + + r = quadratic(x); + + log_config::style = FS_Simple; + + r = quadratic(x); } /* end ex4.cpp */ diff --git a/img/ex4.png b/img/ex4.png new file mode 100755 index 0000000000000000000000000000000000000000..efbeb8206b23c3d2e70bff94949cb0024db4a85e GIT binary patch literal 39790 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�%R`1>fYum72Pkd_p49>W5 zdzIa6ev`39YKd6O!w&1^4! ziSW91GgaPOJ$4uT_cBVwzdYD9b){?!!`&-0FYswTcx`m+O3903J?&EXf4Qb}J^b3yWp+NStQba%VHk##E+Txyje#t*OsD z`zo*9{&eTVQL{VyD&&kVO)5P7=jM+em(TxXc8|$1(F=)p2`=Uinj~b<%~@b{va_%2 zL1yTihpv9JUrulfu+4P29cz2_)g{@WPlp5cY<7#A=iBD&yHw{^GlNRd zruTB)rnx>0+ZWI9To|La@BPIHUk&LSK?hp$1ci?sar(BGV@BnFzX@ml+5LX!ofaRV zbFcfIpw4;sExH#ro;TFl9-lF5W`((OO!Be2I{Q`E%n4h@*tXfq_S`;q%ivo^ttOJQ z)jpM9b1_;nf0_ThhPBq;Jfh#MSjt&7Pfqym3=$6@b(e2;9-+%J*?f(i5*=b|<6Q%fvIBvZu2@vu(+bV1Il+ z+|hmULvU8ma8N#OvgV0&MKLInWFWbtksMk&ON>DzkKxcnS9FM zHrAdqeEE7I_cq6**LrI6<{SM^Tzj;^JfhBj(|OTJJc|>LibuwpMSS@o-z~2c`P}d6 zsm#?fmlnxf;+U#&P#=jfc`u{rJ&)wV8`*klLC|=s-gzpL;6H7WQ9=+7mI)%$o zP3hAKQ$b
{li3%9({`Na0D;P=B>-N_r<_eQ>a` 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 Date: Sat, 16 Sep 2023 17:53:45 -0400 Subject: [PATCH 049/170] indentlog: README: tweak formatting --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5d65bc86..1db16b19 100644 --- a/README.md +++ b/README.md @@ -209,4 +209,5 @@ main(int argc, char ** argv) { ``` output: + ![ex4 output](img/ex4.png) From 77d58d6a3e63d0d62bd28c9acadb5d9a1cf6c5c7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 16 Sep 2023 17:57:54 -0400 Subject: [PATCH 050/170] indentlog: update ex4 screen capture for consistency --- img/ex4.png | Bin 39790 -> 40417 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/img/ex4.png b/img/ex4.png index efbeb8206b23c3d2e70bff94949cb0024db4a85e..56e7796dbf38af02ed4e92fd22016d7b7efe6f02 100755 GIT binary patch literal 40417 zcmeAS@N?(olHy`uVBq!ia0y~yU|z$(z_6Qxje&t7kwN$u0|NtNage(c!@6@aFBupZ zSkfJR9T^xl_H+M9WMyDr;4JWnEM{QfI}E~%$MaXDFfhz5^K@|xsfc^Kmwk@R(V5@l zjW_Q;rJ>9zAmrFEp@$(+#~>m_a%PIrGuDqxcAF~sb8>ok**OgC4*x!s9hdUE@5^+{ z$>$mzCHQ>yDbGqdlQ`*w5R>AX9huMK?=Rn7R$aY2eN}mS_~u7H>q1_=eK%{}g{xP; zu3o;%%Dm#kgGqrRu23{ZN?ATn6vh)-x-8(}Dvhp15OhUFD*`SzWtI!;YN&)pSJ31N z?rXd9rHnr`_Vp#lF8%l9-QT#AZhsdZ`?CMoj5|9%9EfWAApP&6*q-$*?56_s&PCO& za?hXAyR~qC*3vWAwX%)tS1><%Ke_0{&zKM8`Gq$U+hAnM^_B{M)OEz@p>eSvgi}K^;U!$6_=HV{qm=l);x*tDYzI^58-r&v0W?Wj7 zP@fxEzohr{J~RG4ZvH6?-wFJdFZ^e5qx_4@&zC2EH(B@#XPbta9jbZv|MWY1@xUi_ zvUh&gm8!pGe!u>W{n|fYM5}h?tU3EfbDvmc{~kfPHHHFfdV71*PEJyNCaOuOx%aap4Pxfy3{?7i*xu|~~ zfv-0^GKW42V(a{TBBj1|?Vl@eQ;!~teCXFROH10;<<{RjHDhP|F*rH{WtS_qhM8&D1?!*ji_D%VXf>CHM+V}GbCN@W*U@9{q>w{QFo zu24{US?9V|{NlroC$^bol@luB7ym5Is8DL!J+1hUTJIK%a4q`>ZJVdxR6VF*T-kGLX-Mb^TTXAR0 zQ;$uHc7CxI|2n_*$nVfJyX2^!jeeC9JD2bK>i^~D1F4UD3ZKXR`xyPbd`ry)wU}tT z$J@KbjugG@x_tTPobRo_L4b&D6j{4cTj6~pfO;0^bK6*RWr%F_P) z;c%GZ@dHM?5)LwL?6_BUJNH@rzw`ek=NTGZ|GI2;p3wButgKUBKls0D^}0#54d zOzX;w1P3Z#$kjuq1UCO^+omXT&U;b0&8-KSl^gyDnCo!){?A&!+3`X_6Pxxuuhl)7 zXEY-2#+sB9gi)hv(B%17Ws05UiJAM<(VEg73OPC;nj(m z(p$H@Ro(XE-uS66rmSoEEvmZqPspz2`@ZrQf8WV&@k;#U?D;o@4F!GwJ!B6I|FvLm zjmzJu)oisVqujri{Co1|GsE3&_ij~jC(5q(uA0TnZxirr?Y#nLmzmK5t0UaxYrh13 z-aP;B8Jq8Siqp=`u{5fY_;GgY^|)-adlkvW=PaL}*!chJ{(sXWcNQ((`DBuJiu|$u z?X5R2315o_<+n)jmFp6=9$J5qOY@oP#;M8M44);)Mc)?KKILIQkL1#aZihKfGxJVM zyPYTSFs1NXx5;y<<}c@*AL}>$*m8Dy*V)~w=dyE>CtGZsnmp0s@(cHZ3%mQ}cOJX{ z=Hpx^ep`l*3l2(%3z^hJ=5+jcx@N`O@;Zf>*r>-3=Cc{_o>x(Mo9=!o_4BekHua`s zn#aAh-f?l^*UvdK^s3KaS`lJ)U@EUp%oEnbhMO-utSg;(<@eO0|EH(Q&rjbO^p|-__x(pH zD?aaM|MzIxMJ1)LTOZ^fNxT$uw&?r<{m54S8cIii{>bd;677zct|CQX7 z>)-UX_*jpmlAHI^KFKYI`K)IwpI3G2&!6Y^;u|Y}KAk@MdR+C{H=DexQ@_Xm{~B-f zUNo`#AglO^um8Tr|G!%E>7@EX{^Vo5(&~qM!ByDD#jBb`U-LV$-`S>pAz;zLW>co_ zxGe{zV>?t%?sSWIefVJ6f!;<}p>BrWtrkai%IJ7FGxsY_@Dq8yeS`X`h;^$RP0sR3 zHJPMjDy*|Rm-qa3taezY$)%2-!%6nbF8WKL{~eCXZEQiaiW52uuklM|l#^v_<#(9?Es=h5jmgxc5an5cH7wNF}d*1UsEZ@HUFo}HQb?CJD) zzrRy>#lqT{-S76A-;^RRfO>E5`zBT?PS~KgXiFR%lb@SB}dzf`VApMi_uBOZ_6W?a+ zem}7~?%lrM6H*@bPYyHFdb)YZ=^)M63k!296r9rCKG-b1cvm#h@seD%nep<~K0iO! zPCI?o-l+as+d&O>tImS8_1x!5TXoJS1pRBs-&LhtpK?%D+FfTW&(otHdE*kIGyfG@ zc7&INIEHI{e>vmtx7+7=q)b*^z7xu>RCZ%S;3yzkx)0Sk8Z6y^H=e{{CF5OnBw%W1n`Vs%bo!_j!-)y^Tf4lZ} zz_I+-^|vOUX12F8NLjz3xzz03j$h3=)~C#VM9tfhXe<8XW2f=k!@FwVm~Puzzdrr( zuEG!7HE$dX{=G$IVV-|=-KMYU(hG&Y$$hixZ&!D&`IB&P2OS=7Qp z@STL;?PsGu?R>bq>^|4rW7@Yb`^7zZyLZBlcUg1yvKwu`_00d`G|@k$JL0EoZu$Lm z!j^o|IQ>cA^p*_@s|XJ4{n;&2>IZmQLNi z%`U6<*seaQi`;7#y318A;W#E9Ut?%<>s;mYx$4^A&&{9zDIp^5{Jh+4xAUxxQ%(p( z#&quQKDy}Vm*DEfx)A~Xc0W^Q9zW&eZM??d@2~6o^|(zp{t$Yo)Ui14;v!cg{%Jps zw)1O)x(7+OnICQoPk0)4{WV`iht-?@&GqvWq%Guc9`m(0vNdy_ZJzYAzvuYA)h0fT z7h@~*JF+S_CG~IFa-C0~UO)K0=9HFLbMo7N7cMxngk3n|r5MI8ohD>g7j;;%?c%XC zF^O+yYPL-Kzri}SZM~8IM9bnOojVL7pUVi7jGu^;z=bw+7tM^W|4}Dtv zdrpmR2m6QZ98V42tf~3n7_hPKPvLV#tuNGv+bHNPWN$K-5zi@L5*dYhI|daibv&B3^877O2!Tvmq=70Ih|-(2Y7bp$x$o!M{8_c%?_U4%`uh1h6_0zL?f>_B{~_b4 z4|jLO|Gsto%%;@SPZt0A|M&iX*?Ez_O?oZwKDoXp_0_(JZtq2)Dy8dE_Jw5+cb^Tc z`?h)hO#6R<`?+t<2KB(EY)hSTxBPx=c>85%~_ZGgNyE3Ip_hjCAV6%HVHy_xFPfH)HTt3g}``z;S zJ6gHL+uWz#d$e?VT-NFTQATMRbrq2jpq@kV5kdDED}$GxGJn0}=Jfcw$_lfc-!)E| zUXMx6+x>Q1!Frp_>t3&Vi#|Hd$=UPq*s~3X`Ha1%>2RL^Rd~+w`HboDb&>1d9_njr zePH?Ng!0)Xo|B&({95V3yJDCsJqpKRKVd^Qh?N`_(_T9NxU`>fEiNx@&6L z^|@a+vdd{4*0KNnX7dLRqc0IV?s3bovMrpTqM=pz`|bAAhu_}$eBNGu9_Ile^Za`@ znmH}b70T{?Jm-HoGA=)mx9{h(hZD~!lx_Gnk?m1qg|g3~^Il8;Je+mp`9*j6sT=Hm zy-+T`mASlhgV3)ZjaxRH2>;-@yMMlpLY;i&6Ty{xCR@DQ@z_Uix^Z|+p=-qw<$am# zmwx5{|CS$A_;&mKx`!9Ho^B}j58MbIF7dj0(=I%p?<~K8u&<)cro0E2`PQdJ$FB6< z!}2<|{BA0!%zd}#^SKWmMm$H4eCm2^-qE`M&r|(}H_QC&|9;tYi1l90XWy5dMS59^ zkIO~;&isxD1r^4e#wU-&>*?rJai|>fYR-PVZvVfkPWG3J%+ro`i7w=?fArHh;Xni5 z&t{40_j|uTu}M5T*E+mKO_q&M-hM)vevJPl|68?xLMHQ?-Eer9_$AK$qwj8J`#JZE zPV1`5?%Tq1_xhR{pVBYyc-Xq>sL`u`X|Fl{*y`UIqi?W&&tH+4>=BxZxlb- zQ@q-I?@77065@RiVN zvfB86-rw_Q`8oR~j4#SHw=N6ab~iC>-TW5!nu3;Qg|e7HiL7;7-ktgLz|7u$TfK02 zd%wK<&TUme)-sFUe#qK(b?U7n-W$|74{G!rJ>J#cQ1WK$^|(#74;tB1q*E97noWAU zqwsOcY!A2DmdPn)O=Fsd*03~E%q*T zam4n0EC0VKUsn3zy3e|gvcVC5#V_0B)K{xjq&}H-Z~OCnLHo+;eW`nG&&=wrQ+qB` z8n0vU*WSWE#*$<8jeOyq)3}#sUMYMS2`;m)xq|wd;v&~)ba$UVyLhQu@g&=}j26|U zVaDsXT=LoA^xmaf#_uG*(P}T(;?T^gZw~*su<2KddHa8%cadQcLYLkiy_)8@@}kei zq_1o4EI8nN;@8qSlDW5?k4V-VzkR=Na<=%b2anlnN*uSy{`+v4Uwzx*-Iv3{vu3Z- z+10Y3G)(_^pY=P9rY6s4g?A$As+=C}c)0wG_uZ7qzGwKX-z4bmeq*$8iPbXS*=hGG z9`j0Co!VN!!{7I-a0+)fJF{ajCyU|r|V&@XYuQY zC)exM@qbsfh{on#SAV6>sd78i-_6js%Uo~PapBOb@F(xv{PRtIhRV8g zE9m^z{k79V^4;&3rOQeWT;U4~`?Eo-;ONvw?&h^CY{S=G{m=aD{WPDGT@jGri%okb zwZ#mrE z3a%*>5bxl4Cbi5r&2RH9+aC{_ldjo+yOEq){c7d%t{YZ=J{)$IX9QK=)8ndE-pt*8 z_m)`nA^%Gk&TrZ9qBBu0MfHd6!#UOOb}rkvF;GrNu4mn(DfZ6od~Zd*{|I1{w=Z0j z==#xfcmBUA%{z~WI9aHlTl{%)?Mts))lx?^oy+e|xHnC)y5;!tlV;pMk8Sr|r+FfK zdnl;BOTF8sxG6&J?uJO2rjiAs)qw&v+-oPy$^D!3wMT!+k$kbJg}3jjwg~Jyf9ti& zQG+JSUHtElw8<$?V?VZJMZdgzRJ3f(t%q0hR%>r{?dQ0*_xru*Z5`*=Bq;XqIl6V& zeZNy|BxAzm>^yhBiT%@#s5crHEYk0$&Mwi_nUX%Qa#@E@n@;)E+HW`AxAEJ4nUK@S zezr3_%=GcXVrR)YQ!gL)mwCtPq+g|9bLrmHKb}q1&U*^Ir|V5kzWDQGpu{s@cNd{p zPiuqn?dk`*cBMVCxoq?zJE>AM-E}#*k>e${VMEfC$a41P`8io-ZI6_)wCaaSF@hOOl@?Sp}PC zbP9=^dDh8zCMMdpNE)Yk=<~e0;LJZYIcKKyY!}sq)26M{$o$#7W42MM*ADTP)>4zK zr(Zq_t7_`Z-%@T`zl-_s9!aiwZr8T#{(PppG--QOf~)RR_E~k^>$9ZA=EUEvY%~O? z$0;ToV)`~U33X>)Nxa%~DCYXgWqxZ`M??xP<=g&1Xxgp$&)Pezk8KNVcsq?#o87%$ zo>lur_}iUcO68Mpn7Tjzq^7sA_K!u)t@8mZW%=ytrtEWFxNzaa`G@ugC$4+2CUWzc zCnqPTCY5AoujXji-FD;9o*$387p`Y$d%kIki8j~q^Oh1^r@l|x@aO1Xg$X;%m`aXx z2tJ$O%s271?Z+d+xrd_!gMUaHr}ao0rFgL0f2^FCnfUQLulbz|2X&*ioOrY8wB9G_ z^uNhZH*pH9b$qy)xBKlGPW3qo{D*Y6-?^0eHRf5UT?7Du&KHlXP_&V9 zsM?UTt3>eHkB^Vf{`vX&_MuN7AA9T;x6Ax~cD|0l{imm=pWf5tZ~xcC<`!RZTKT=o zbWZim)JHm*?C)gnKiTze*XuLv@-+f-YkfBUSGm0D-aMoKCig#e{<*v1$#qa6>s$CB zi*m8f<+#Yv&`a$=QE* zzj-d*Y_Xl^|F)dh_WALxyEFez&iS!^)-F;1Hpq0s%WMO!-fhCUSC(u$<)!_A@61>8 z=*Wwa`M3EW=gdyp^w&E7_9SoLz&{C&f8**loJsy$zjSKa@0#YBnNnvSFNk7N&BJx{xY%mT;mupFHvV?}{o$B& zK2N{K*1qYjqLZz(KPw3_9z0PuY31F>d+&BWm%FL<@W|og^7T5mHJ;C}-&bSb$y&AH z)!8|g!C`xQ>;6nXI&B93Ny|SQ41(|UFOG?@Q@HT+n)<^Ht=a2#ss(PS{qeAUldkx+ zZ@2UHZ!h`t^QnHl=F5VYNndYQMA+5IyoHXjL zz6({~+O%Zuscs_|%T7JBP+hLm^LfGr<|SUsDe26VENjS&u!=voF{(fzZS4n{+DUVc zJ8ryxgzq=FeNa=mbN`i$bvo+|Ue9h?bFRDe%acC}#wv4OcP{<>6Iy-f~v~+*=T&Gf~v~Lc-SYMRvJl+o09drWjqcX_s>6+Ze+O4HBlsK>+&8=+ve*N5?o*E3apHn zA7B5s^z%ve`6u>VTk`O5W{<3O*gnV81`n*??NGJ>xBR*;{l0Sb>P)AF3eLfEy=O~Z z4NusipCpoPv3O25?g!T=1EC_Sal< z3j`JL;9_N0H%b==qZ<>Mo~T(l&EWm@_48|FtX@Aa{BiEXrqt7Cc+Kxj`1LkI{@PL1 zw^LtTGI>@qIsWssmA@bD`_K_|8r0r1;kQ08PhM|RtOs?6_I&7= z#CpGGomj^@Q|VYGCFA|4xYkYkCTj5cZ1+=%!YJdyd3SD`oQhTNoL42cl3(jOr(^Af zyA~-Y=kIe{T6E(1wV1#6=ki@BojTdi%5%=5Dazi~UMuagH_LtAv>|Wn)v#wB%6$gG z%l%9jyZ2A)h^zbg^x@4X^ZGTe#}xPOe7o)Tp}n7$#A>fpKYElqaO1~g(z6fqS)b8~ z+@xaj`ncuuImvN#KT~&ZQ0)!eKlwYd&E zXPD>D3(4{P8Mo5L{oxqVAa}|rzs(+iKefGQB^Y@3av#hRt zbGBi7KQG@A4bz+i>A1^J@}(|+o&R^;tHKVa3g5;4M!K)xW_tZ>Y<&8(yV~dQqxd$v zs%i61r7uXlZ}Z8+_{Y_kW$SB9cUK+Sx@^OorSL7?-n$Fbp`cBIF&&xMm?`(>A)A{^j zXXt*b#JtdX(-rFLGC!x+&bD{I@#m+3&E@iwL40$kF1n_>W*x6VZdAel%ePdn9_YLp z|Myk+rnjD(wistO>g1k?S~M&7#JVkucj4A^Z1kL~yCc8mBtpI86y=La7KF%uU~Nmq*&^P(pwKCF?yBV$zk`K&pA ze+k>frm1}<0{lmG6NT!+w4U-`SF!8xKJ@Fw;{G$4%jc?nEcx-n^8KFAXL=-!Z$0XX zuPgrba(TO5)9W+yYOz-|kALv?{@MR$>1P?ymSD?+jQRV1F8i{`;<)q6 z2jv}_K9}L$Q=3>lojfPK>615HdT?vU>-GEN9y#uM;Tf?p$@RtI`4#_oBn%cf|5MPq zU;WB06qjrdCjTaWST=Wyqr{Sn`BR9QPhWYI^?M{oIGx~;jU|GPONCqp1P*J+Cx z|I%Uw5BH*7^WIO;n;s@UeThlvsr2$#&iq4Li|#G$|5Fsg)&2X3<(kzG)@fev|je^&KVwV!%whIG)oQ~Y|G>mOh5oYtH3Q|5>E z{PXT7?dq+?&!%@wznZaY(f7?UH4AR!2W!qR?9LRL@;s(+s^+aC@%nk%vFbb5lr4+d z<#0(vGhA=2=lA_qrB1(U`-AoBYd%!!X-$8gU{SKg=JWdguBM z^V`S#0rgH|`?l*py)`p(#guiiWjBw`DLf{b`~As}$NlEP%X~P`{|a8oJF|6*#pL@( zM4!*FC|q=h|IysmU_Z;H;kPG5xYfr?B)-${G5P%Y@R@^Q6;^J~xt?ABCUNen+2o?q zXZP3s-}zJVq2TPWY96s!VK>X#BX`yb$$dO1$k%kE&^2+z&P%(DKR4h0^XJAt-x%3B z>z^DC^m{+y`_x-|J4UkMBo@&98XWX|{Rq`BIsSTkQXQIBa@* z_H%`|A#XCBMYN_qS2-~|@o-yf_0^@BcPuY8G*^`&iBT;N}f7M;Rxl zMn`;{k|TSjFnNVSZ&`ei?|bik4?gw2_n37p=gZ~~ISxx}^w!j!T=rD`+js8NIK}S6 z5BME>Hv*yg%t$&+nDC(!!3s z!cDnv4?#{N?O(mR4vdXZ!gx#qK_$MwLKFS#BS#~uCQ zu<`zpgncX3TRbECF4xU{Vznys4!_OomMT=fmBr3)S3u~%B9otd$T zZMMa}+!H!Wj?Vn_X}SGh&vWu67aWUnuC0k&wsPgkKmWe(pZ<5v7dL64ja{iFj)lED zckH-h6P0D8elxklEg~q(^s|@tSr+Xtep`+|obpFu^QsV&@Tp-Z?RxliSNoS0|ImLp zFSS)w@orp9uGkc*vm)AI=TGr+*|e;QKQ;5>wt1@Oe$39S|2{Wn_XRe2`vAZ9Kekk_ z{<|j}G_K;JGgexyz~s4E+U#M=)_(aN zFBWw#IrLmclv%W{q_6pX>4M#v>&1>V_c6)HiXGTndiQ5&%b-&cuZmI zkKBk)*&oBxW&cI7*SP)(`mY9o~R4AyuszQ?sxyvr$W- zT{Nk%?oPoqjm*T0uMbPS_4-hKDAB_uIeD=Nm)s$wk*W=x^7aisY`$D@UYfKZysxW0 zS?^qoy5B8<-mK+&R~u|^VHbSvQdjcNGk)n6gSc%qmyS&QlF6-ObnzH}eX`)Iu2QA@ zLL8dxy;eG+kqR+VD=t3FH`%l?U@b4l?1eRX9rLqQb{|cu`E1!`?H{+fK&UswgFjpP zW|;81>bs|wyM|bHgx?AXk~%rnVh!wuDg0)Drg z^Pa}GNbblDUvT$OQh&sWN7H8LEIBIq=&e9YTy5=dfm2>Cw>dq}J-mJHj8oLEjMe-8 z|NAX_M6PLr_M`KHxz1(nMc4?o} z&D&J;k^SNCHGBO+c$8->{{6u(=Y?TXWr9!FuOEd=Ud~+;^15=pnypgA_j}e6E(^6+ z&FSe(GyG=y`~<p#^-5%8?H_@Btwb)#x))OyHyu!_J;bTr@t{}i#g^Ac3Nzc^ zE!n%epuf}nT?P-^;ll z*7sR-hpl_bd^3!xTYCP949PF1l4+WHYO7Yc3S8T|S7_SeDe=~G8SX0X&G~V0_IDHR zGds^Had`hc_%L2JbHCr$S1VQpeYH}Yx#iEth1=(G>)eUR-1uSkwW-Tee=sV=Z1$;t z;al-tw)9G1+MgdE(>^{r`e>S7tkk@>Qd{~XCa`ixhKE(W)#6!v)@jS!2~TA9y*-mP z(Y56Fgez@tI3?I(bgLHgcD9OYr(HR_y)<`@=*}l*UL|#!tC=6G&1$-GDQEJt-f4^9 z@7>9K=kvKMOl~>XxNMaoBF!Wp3a=G-wB+jsg)I`xq*}Qo1ch3Y11J5lm~?2-b&d#M zamV(st;cvNy+O8NWUXZ_M_(VX*tc4yYroR%ooUL3$DkkFSkr8nzYarnHs zCZATvdGf0BeeWp{xLu}iArbV>s&>C$hCEaJyM5D7&-eOaBYt(y`zx+IQ`2sk%-3u> z@aX=|!-{YBePi+L{`29TvqEBR@!=-HwXu!m@}I3UG@pTi}&d?dC^uYDhFS+$9`^J&o((J5zak7m7+ z2|KHCru68iu2NBL?L}7}ip3lX`hEG2K;iKgW#1clGdC0!eEA-@p{efbywxg2=AE&{ zC3^W`M_)P1+w;luPI9~Sd7hb9S#Cf^M#hijAKr&Z_?=qv`s8Hw(@XAMyA~#B9i6kW zwesUpap!nOp7W_Uv$RhBuw-{O{&9_8Y{L$D7M1JI9?BUewOBrx;QXXYN8(AF{f7?^ z`r9*4Oi+~lAGV4gTFkhF{q%Zo@x+VXR`vh>Y}=sqb74_>)BkJH`MP^2 zCm-+2JuTmMdWW3l{0);Xo%`-F`O>}FknvMySN;H*XKL^Fd_GrXKl#zjr8dl~pKd&4 zRP49w)2AiEjYY0MdycE$|FTb1U~|snZn@)&as&K~&K~C5!n?6|$;6QDN*Qmaeqv5B zl#p6?v~IG`aK-KSs8c6@AM>< z5AScgE|pZYwthSBx>%pfGwMaMz4r6}UwL_hL+AAcZ<}88-nzJj@9yy{y8QFjtO z;kS1=WYXGr?L5oJ?BFXetui0*MQyZLvX~&RfnE_j+ENcye!(@dS=jFgX;Wyo1Y&)VOz98o@3va z4KcqAKM1eCb})YX$E}6iZ!bE#_|U2JCwuOAA5!68g-<}Vjs1xb^f>NDL$89Oioo?P&fbI zs>@qX#V+6Lw?KJ$%v=Kl#n|RUC3_X?{=9BE$XR-bHMjB&$E%hPRdZjp9P=r4y8I$| zN%5-t%lA*KIl)#u;k3QD-B0IR3;%uob~NRK_}TQfrMq80p5=2qL!V{=T)EjC;#sQ`}-fi z9$h|n#%X8CM7CQDxAXV!)yXG*xs=`oXTMY}#!4;Ed+i`-?7VQ2Tt_p%U4+c>nNRv0 z9wjDUs*&MxTDqan@|lESo99pGTY?jMq}5|vog7^S%9^?H5L_*b(U$S`IGK_-i*yn|F)F zk=3OOa!=f5)8ajSXx9F%rheS3|7S_>@K&`u61~p-PPmO8Z(clCcFvAg#cxu-Z|zWu zY446Wy6BmQ-}QZFv9rB)Ma*&gl=foYLDN^qJ3KmmDZZWhX=Z-1S+8xd3-<)IL%n8c zp3wr=;x=xudbas5y8(WP^PSAIm7$rcV=HQ+!Y$)DxXgETf9La zX-|2^{|&G7-pk!m>oAtuyl>jh_jTWQZ%Vz({YbhrwzE2F4&%XB_l}lqx%}|VA_pCX z(A=6^Gb1&o>q-6ZXr8F--erF)-{RTUGS>~$vYpcubuo+2L?_B4yTC?QxniJKh>?X_KejH&{KSMfa-v*~o ziwYht-u^aUpnmqurk}w+e=N^bu>I@@rAC_reOzo ztCH&{Xa6#=S#?FKrd{;4O!2RMYZ79ge71^66MVnM?{(YWPnIHfPnndm?A}i)wec+M zLJy?Z1f28F-(>dMP@jACqA#WbDrGUxzh-(TWZH{rhU|%pG^R$1-wurM7hLmwx>PeW z=L7arKVSM@OS4@j7Umk5#ni@W*2}eT@rm}Iiw`$Vz2%_01~g-KsrJ{R*3#TXO`(BP zW;u!#OB$SgGV7lI9OvbbIjowU0VpflY(L2&mcqHd)I;5`)y|^*T1Th(+^5?$Hgn&* zr2bvQd;jOt=BG9Fr@rql^?Z?@JH_jY>=fgr{XLnrZmS>fb4WZs=j8bf`WOCLUf#4I zqw8VG>qBeiX!>maUNqBC_kWNt?_=5o-5)SxT~-3np>p0W5K+- zUoVv`?pHpS{rsp~KkeTdUZ?U`S5~I||NDJ9e+{U+{qSba4*od%uUCRUP0XAB^v3VM zM)^g}y_)-^mr+Mk$xNYC=}uaqL?PPUT6{hyb;i?%GZ6>N`MwEUA~(d-+4?i?~Z zr(F|fW`C9In(`+#`mMCPBXqR$P+xng2;?ve_W?#$D{Kw;3&6eA1*UVop zynK@8(wdda?vze?QSQrsmGk)xtAoe3n!jq%`FZ*JiV(iV^P4krbEoou|9*}A`)@8` zb-yX!pSsJ}ipZ_BvwpLo+4AEN;j?FE8Xx7Ax7!mfd#P*D7rr>LYiqaNIwezhMDS9D zylvH%o$vSkKJ#>XyxctBZ3?bCpUuiXle_({*t@CfZ=*cLG{x7SHM@NV?>fA#m;J0~ zD)-x5@|k6Fl1IiOVBh=B8$00Z@Zuu00uL$aZogNRy?oE=C+*cG-)^SQ&fRu%neMrM zyI&dY)z2oc^ZLFwO!405XJ>^QXH0n?dFkj+?R7hxq{NG#ojDn^Phn+DD3jvVUlAv_ z+=+^1Y)(j({km+v_+e#3w;OKPpE)kxl-HMg#4hTuMahA-@a^&EM7C{B{ARrDOKUEV zee&Two6B3G{hu0NkLDlQ z@AH^e^kU80ti-n`9NA@6-cIY*+ofR>R4cGzi)7-rH#aZ++x_{Rb*jDgzFf{*Gk3q; z7Jaj9?jnt+A7>q|deF#z>cfficE5FOCh_bIvDt7=v8lph_osw=b-&+UI#B-Z=kxje z=UEaQou>pm6y|%_D`RP7^O}88?{qfXs!WBT4O=F%J#u{NHlt!M2AdHe9(UHA^e$YxXw5KT~p9?nf9cZQWM5r`)gYMBU7c zeY?K9?7CF?>KmU`&8+!&{)ZOnk3Icl!R`4}t1BY6EHCq5r#f6uFTkKKWaQLO}Kq#*<*i4t38)Q zCAWFReERnNqe(L|ydoq#8@p{7=Ho2CvfCoiz(D zKAduHzO}e-vd9{{Wc$2gh%0%Y5BD_kFO;r|?se-M!m&uLo+ys&8DAcQY^rXLwez>!@|b@=9(;}oIVEo{V-+>;@%I?F#y9zgEpE-T-?6u6 z<~4;}p|*6(k`HzXCBfxwEXfzG|NVHpw72+#V*82TcgtD)!vtd7WlN`Q5ngn-bn)Tr zjZsM^2OjM>E>}InF!|Vw@c3MRo42yJTIM`1Z)W42w9@R|ormr6dixp8W5l1gz44oA zbaYP9Da~d3_U(IHUhw6j`{~k`CGnfneA_KPeqS~_PwR4}g*dx?x48bhPZJX6Z)0I= z*JnHXL|8}KGe#6G^wMZM4|3MBfH#$+$p_gw>-8zKGr)qSLjQW zVGf)4`_4mA9SyD%eCON6vgkM)Ptp(=f~(> zSFEpK+{rc1B>66A+3XoM=^TaQ2afY6o#mZ)Z2#*@SA(PN@~)S^emKlu?hziY{c$UA zX8OIXTLG)rE$OzAGs}tC5gz-B|McuT5x1x9y3MtHx7W5rsd*g=-BWL{MP*LRRkxK| z(%mM+d*RHD6ax|dZneXSpD*Xg@O@pyb!)f+b!>}~9`RZjiao(f?vGm$%D=ao@6zcvTUutRgt!&HTz|GZ*&1 zYTnWG!}`P8?e~nh#dHK#t2zl?{Pp8;|7q)K+gO_f?*!bx9#`%A=kxBl<@X|8tn9BK5n_-ZgWD}TeIUoK0bDxAjE#4pt0g;VULAkTQ$@CZ7u$@eFLYQN~u;}dce8+ zse#s?vO9(Dl?F52C61qczWd*=*N2tgCiF6C&Ga?9>7upgwBBx?Bh!;_ZOMGrYkqIS z&ej<2;~yTZkayp?L11Hu%+v?02fs?XdHYKi+ird^**-9^?jWnU$E>>_V!|DN|6qJp zA8@hw+}4()EqeQq?9UwF@uKV>#TU zXn)H-ca52sj7q-8?fQs|*`GyUb5uMnw)k>!4d@Qb4-RGXJ=<2U^jx#Jr0cPSCEK|K zhiX2 zdcAIPwt)Hf+4qiYKf6rBD|MAp#N!VWJ{cHYF+F=~YTDH$PBuTEOiqnZza8vv8`=`P zr@iOY^Gn|PQ#;?}ZB+e}u(fBhn3!$D#fQ3?AF2;oe!o-fo1DCOk3xlJ$)&V60NsWq35D9+#3 zVQbc5Em-uhP|7Ju@KsZ((mtV;CR={BTF<+%V6oz<3C_*#HR?-?$Rd#22s*2t6t;d&dpRg(Gf2r1L!%fRp>)3{>M{K+=T-tQL_~C5( zpt`&7h309m*?!^uqXjZaOPA)X5tY!oz4z7t8;gg z+<5-GZUL=~$>kI53^n6^_lqNRd#XlBh{xtj2Dt|(`&oI)JZ!rCO>N7~M=D!yiny-y z>E{T0*5(xc>~~^s58vhmMaveYM7WA*={?s!>uDbiywcjS@mi%LSbg?r$?3JsBRriY5wqHIv?-BgX^ZqFRwAdC6v6sSr77HgoV4be_ z!f#iV&^yDI{>6b3dVcM0K~cN8y7ks>{=&aqQZU;q<;UzDtZ&8oye?Gu9E#i`A@qt> zyKi11>)EiKA3iHA^;@(mt7Y}zgBbRp`JNwKE&j$DE2?Ndlp|+%kx)PSErVUO!NO1n_fJv zJT?DO8^62kwHrD+5)TTi8C+44;FH<9?$f>Wb-KqlK6o@u&-dls*Q|?v&b^ivEONA8 zPH>IR$FqkeMCTP=(y8RoZS!+kDAc95i{;}(Sx?Za%u{_!{Ywt?E{+Z&@xn8T80;hHRq(9s}=i|bP zBuR%8t;bVuD2TNf-OufbGZxk6kvMm9!#R~pQdfDl9u5+O&ME}f==)UXSQt5f*im=I zN=S8{-o_nYHy7@_Y}R-9Vb#%c>t)By=W8n_-gGP5x#3Ysx`*cX*tWE`!wK3Cjq451 z_UB6`=cS5hDu*>#t_n1(d6zlIWOaD-E~lD#b4>)!-TQv|p7BPOTlbG-?)E#h)W50bRh9QQo-+!Wm3aA+q@4GyfahC^B76m$wnPf7=diz5 zen$AM=bf4>>l#kT*i>wg5L=)^(=>b9Oq?tH(MrFe4W z1;xzNj1#l;!WN~ux<5NSVSl9Nb}s|%D6z5=C%G0J=vv)6H)7?bF0UrP zHGMWdH#1rGF1qsY9qng3c3!oMRGmCEB=YH`%9b@>G!Ng;snpTk+Us;XV6vzq`;Fw) zYv-@D46ZLInEUL%zJyL@k-Z}P{?+ZT8*#~H?&Mf@~ryL(=Ajr?pqv6YJabLU^Wf9T7U zlj%~kT6NdVU)%I!hU&K)A0EhA-dHaZ7X9n3;-5+L?s&Yup7(ij&aFdrS}q)qZ1yiK zJ+s>ROJV$*eY=-C%z7Ph@`~BEr*;Ll(*J+FTK)C^1b(q@&TxI-MQh~yjntklzjy5L zw*5t_udlx|cAxSmJNo5Tr<*U{*5r9l-|H5%%j)R!;A$N)dG@5wGn|IfrN(Ti3WZ{C$}GGB7qyLJ7mZy%03{w(q0zJ0e(N!;+Bs@pDDAzxBH zHDSTzc|R9Lysg--QmeU8YJ-se;`NWTzbHvn?%ybDkkG&pd@HYGi$<%{!J4Pq@q&(> z4l(tAzove@S7VnyO*dO#=Evf__-T9n zsZ9OlW0CoLzdpI~>FH_fmg7zVI(04)clf_ub}13E%kA{aHFFL8^Fe6M8P%taj~iK9 zc=^l!|NHy&vPPgpU)O$by`3soA9<>}xHf6@*l!5g7m^k7qGJuO`JI3^v0_{H)o+71 z0~;T;vvSB)zuCxFC-d}B*JKqPKD!?Yg)-?2RpK~0tn6Ba+r3r?MI4tY?g$>PMHKModotL}fjZuhpQikZ89y;^-+%=Ck2_|D&T@ArN`wK1wioORLM zEt_YA{E0JIf7CpdquNgR$fJlS#o-$25evUWo_uorX4}-k^MTylx6wz9szB^If$$$zL3POS^QtUP?I(8t0zvA8}6q zQLn+0gW20nUUfgbmG<>G>tU|DN(M#sJJ*$(JUaNaI4|e7X~EI!Z+FgkaHfCzxqGW0 z1%Hd_nxXal`0^f4=KFH$=TB&NcIyg%ioNtfSYzrbxBTbDOG|zpIeu`fK<<&lHF@8I zKg~SPF8Yn*)3Lj!HHu`TpA~vucl7y|H8+8E?vmLCr>=4ySSd(NbJ20Se*uLPEt^pr0xl4$+zXv&g3WuDM#huN%&-%n|;FWJCz>8D?mz-otC zKeq7BeHk(4Rotw1r#=>IxgPj|m>^&P3`RK`m z?;T*0^)AtIg8#a>YJT zyO;M9!mkE1o4z<)KHRN3Kk-2M zokI7DE!kJDUiDnBbuILH#KE2F)kl8I@NP4@Wtsj-x#+F4_taU=Iziv!Cw=|sefX8a z-=*J~PA}A96YVoP)4%2E_xxj9?t~j1O-_rk;*E(1y?hsd27g6d1FNJ(*K{qq!l&G`M&Pu1?xbfIG(p3^ zi!|c(P__kda-Rclw+C+$@H)G&DHOg(V5Mh?$A(Sk4n0r#(Ze7w@VvS_(mwledEL)v z()WG3>vsE|^t(LcvTxnl=w*8Yf(`Wbn`E>g5=97Ef1J~_*CRKbpcYAB~Q_tODLHSd< z#TO+#?lm`Smo1wSxhci7;#z<4Im_dF{(L%Jlq+6lqSJC}qPtwCn(wR>Ha;1R``@2P z&k~QTSUBgqqW8ZG%qGRpd^o$e+^KrKcJ8NjljPrByqP{fciYXh+1o7af4x{N`%W^% z%lgNUm8KfvpP!wbJl#2HU%1x!K#TgLqTw?F7rV{0EPj@v7r(TP*XQz!$v&s6s%Hh& zB_z!J^+@jWh9A=x_RnKI81?_=d+2)p{$m^M4bCd}8#Tw@wX>OY?iJ_tS%+qYSL@z= zEfo1_=WYd;@cgR9D}Vn!yzKw)`~3Z7ZAE*l9{xT|1~wIdXmojQ&9@1t2azr;U?|yv*_~d+~x0|vCX>f(_OjfN=n&D z(;4%hw9nXi^y#Mi;U6=dDwi#O)Wiz&@b?Y*1{e`#l_s7cRAuq9S?JeNQe{y2t z!$^CL2O>Aln%}pvxg_br6=rqG!A2mz#q&qx$|?3SlYc1aalT&MZ)XHL0pZByhmW7{ z`FzgUIPFYEw{hLivoDv=m;3d>dw2i*t&E~)mHTa!^cz+BtlwGOOp^3{)WFR5LF@d1 zzdL_Eo4s`5ru%ijTiyRUt})}keg8^r-S(IN4^|qr2xTifr|kFPsrW7;y1KUES)h%z z<>masPn#b*EHKmgDgLr0GcJGrhm71$m*@Yx!Xs}Nvy9c{wU3nJYo@99rfzjJz0JAT z(eyS$*QLoh^H-anpgf?S8lG^qG0Kx9?OwpZjoPiiDHr zdiK8i7f$>?9dC8M(8*$|u*`>Nv-7?DrxfqGAoHhhI>)oxHLKL;*KBH;nes?qT#VIn z`f1OI%!1rIU$4jOe^iM5a%@e+Mx`$g{cY;mcqA?;)(f=1-}`;u9Q8Fji=Ur5J*WNZ z!^iE@wJRS!>WN>_KI2OhXp{F9CFz_EjZ5sK(iYvR{eCy@=}kwubul|HdZNF|43G7#NVz=xm$X58=KbM`=a(cydYoV-_E2{pJm$`*^d9y$$KhR zZ<2lNztftSK&IC>d>iMV^gnUooW{FdLibv-pW6Jpk$-2y-KYRfoi>SLzSZ&;`**zf zko^4oPKDmNnR10QBDenBzy0^-LT{<8t`pB|Oh7}M&U0dBc}gd`AKc|(bCO?t{*pa? z@#?d#-~43x;riSfwly0vUv}L)U-YptX}|B%;G@TryeiL$hRak<-J@}ScQg4*A2y&ku)KW9q!=Eoln z^NZU*pI4nX{qbAxo#m-wT1&I1$CeqU&na}fZEN}O$K$h8G=mRq{uffk51M>^VqSRE zQq6CU#`ormbj6jt46&Ka8eUR(mb!02Ug{ow?5$x$MpWu;*|ev>JS&c{yIXK19T#m~ z_{{6|xikEEpFb!6HZLsw@uP4`_Ug}PLbEo9?w%K(#jk&GmI}*a1F`w@f>@Ru7M;W{ zSK+WN(Ck)*^36VJbH8n#7iKr9@``VjV_L*Ju`Ob@UF|NB4_o4w)S1jYNxktc%*sLY6f$}s`z-8W%@gpeNWBM*Sr6tFEcWq ze{PH`nWFZe3^*j z(KgP5+v<99CTl!rUwF;tlgI33+f{WG-t5?+du^?LU&Z78FUgwaEY2nUIh$uq=J!qB zcU?_r^V83|oIhnA%s%h9tIx|fTwwlZtz+z6f7RGNhuJFnoGJ=0bkciy6SfYW&nnnn zpeeG`{{3Ci{-=+4n%ViqwkI59TKT!tym#%qMR#@^aX-D(8gVz7KRQoJ>Pg*%<;ll- zG;hC@IsV;tM(Y-f;JANZmfN5F+019<(RX&1>1h*F)0y}G|NFja{?rWV2M^oj*F|=3 zxb)p&O_F46Kuofpo}PLCv{`37zey|-oHixu?4Ce^OUv3u34Lo+suvQ-ohy?tQcAv`dYp#NvO) zr1MYQaaz}!Tv2cZwD!eDf@7lBhoEP_B1$DE9r!a<=f@NOEei`FBcv0Q)n#h`9B>tn zRq0hd_c3VcMv?jQPbQb$|MQY}2YZRggBKeZ-mSF`>lOj8Bkzcg+)N-!@T+%y`uV#F+qchbTl)Fw9Ol)L38K-8b<)%RME$uMnVy{7UkhDU zKKI$tP3P~Q+qtFjbG!HA$|HeB>&qV;dfaSazvn>LYWY)kgKF2W}UutV!rg^L!>=zQ7>jlJB06;SnE8*zGyIT~wam`g3E;HlCZ#=cb=ee-~N` z8VI*K{ye<%W2E$-Z`=1z-Sz4qyF5?-mgWNs-DS(~mR_Ivd|tJmOHjGA((ZS=R(C8} zVo<9gp5ETA|L$QAei&Ynu#!f2!u}6DzfL<(UY@o+TG4>Asvo^z^*4p?@+k|U0 z#M7HuC8ZWt;4p!wZ4MvKp0OU!27kN9{pCV1QWSz?=4+rHbC`=6NO z48GlMe2`*)YC+7sKPq$NyZ5KREi;#Xu8~>yD7om=)~mY@neY49n|JlI*V{nRgHr5? zN4aNBcb+v>`)ro`!=xX)%WAbmvF;DJpx!_|v z!<+64^BwM#l9qmY@YJQvGU}T3ZG5t~G~azxbhoQxSXlL9Vf!iXsdBk-w`97H-Bf?O z@8@M{1O4t(JkO=fFYb(fZNxP6zM)kU%B|V30yHt3~OJ({iO9#wNqjAOTo#39eQ@51i6&S<<{#`-EwY|UXOvG)_t zJ4MY=j8j+s^6K^N_Di8kQP)*1-FKF!UaG#(zNO^jzS{qPzgu_MvLuEdnSXfs+y~A( zs~dNy_3b&m(-z;#WpM30BoL|7pLaut&(Z2a*Io^deXU_0=eE^ttU4wh^vIlh z?S;3$E{imLsJ#}auGJ=Z=3;Gyy4e?rjWz~quC;$GF5P++xiZXl{S`6rBJb+_n`KMW zn-7WVChTdbJZZ4SluO?mJcz1sfiKR+;(GE~vzJjd$3LGjK0jr;_Tde?PTBot>7D{w zi@%9gF68^Aw6BhFedm;3t(jw2*I~{pAs6!J!s4^1MZ3R%cJT8`&fik5S`QvcJ-*W| zsN`LkNL%;i1Fy0c>vBFzPFKDE#qUSByUU#j387caV&-;=myBLy8^r|2_=JRZE3C<` zR@HIWoUijGOHyY|Ud6iN2)){uXRBwiK3kF|`6&7nKi~gVdN%t(Q-hNBb$cTBRBYU_ z)O&hc`fj#T3GU(q#bgn${DTI!bX;EVQhENNHax6bXVLBUCEpYL4;VbidU%WB!d$b4 zMMn-E>Jl}6^($OQjbD5vq;4#mSRb zT#@kb4xh5+&%%R(u}7LVylCu;vIMQ!E<#$fEfV5rm-#;H-xa2g&+j4@6nkBEsoKAB(heCI0ijM3fkfZ`LGAJ1n<&wCxC z+Fdp!>)Gb~T{S1xSE-uLvAAP=$T8>k-UkWd9#K!)pNluPd<742ma)!@e^wsUZuqK& zZ|}Q^FABMdi!Am`_c+ZCI!Ixq+`jjxbe1gb_H%l5;79d#>mOT$Yc$IBXY4-}kZ|b1 z+-KGIPX(^zU7!(pu*mWhmzU16!1hpMuHx9`v#d6*OGT>b&^8Oe3H<#V2PdT>V0UuP-mlj# zZMH9ab7R||#1)czZ?;5hzTNk8vzfx()6?~*dv(Tbu{g8$Zsqg2s{1}xvqYXU-f&4p zTgNzF+xxKb{ZE~u6DF@|_yu0qygb+Tvdt@r%SI{Tksp@jxhfPyvFBw+vFGYDEhyc4 zH}&e(1E;2LUi4U5(_hy)a?8=Kh~G?^lAF49R)l0FOl&&fpQyT;>-?ri{c-;nwcNIO znMdGg8I-%gAB#(Z$PoY+eyal``XM+@HO#LS!cnIr9zQsstw z^OSxSt*xK_w`TEfeOJl2+eUvBf?t^*Y}=Y#Ap3gxhEC)XY12bb0EJ?Y<}Xtw35Ey)5tN<7MyOA3S7Wd3!>J zTwTW<^I(aL&uta?>F1xQ=KuM;^N;PfHS+2O(>hf5vaiiF~o!#z*$S_YP&TC5!or-PI|ZFF<+;Csm&wPdkdrcmY6Zzf9jXTtl=eOV|~TkX0~T)+EUR1_GiCl zuU+$E&GxVVEq?pW$oYTn_OAMswfu}?SKdEmKW%gEe|S{pw)5sQW-dEulQ+wiVP9C5 z;b-sF))ryh|Jp=1c-~L6y&jj{C%S3%8|{w!q%URG`vC4~Tl(1^OD~wRuW@=pY8{W# z$+eGMQ_uFkyT5-wXyx{k8O?FLe`1SHs;;!%yT?K!qGR5V!@tiMpZDlDY3-bTwoN)u z!?}Csyyj50%E}Lm4)JTV*nPW^Ec?geRI8}^${@=h51Nk_&S6y&@Yu5=qCkm{KNz~6 zc?M_{S8!3!UdVdpB+z>1Jrm6DmIOz}9DxqwrrL!HP1Oqd@bR*=fSG8(qzG0m0~hPe z^dIpy>&~=$YoGsquX?>q@r8(olO4~@R-L~&DB`pD@B0FmjdJ3(tpwH`c3qPcSp1~> z^qPhn5iL3EuIM;>3-(6*Dmv;G>A`vMwpGdb2U1^?T~u8DDtLfaK>t0P6Y;y-VI_C? zowMsJW6yo=J-cjUdRGRci^{`m_4oE=sU1@0$X*{2vH9&*^Gxp3KV2o1yaZ20^!aW) zd8J+ZhFM-o=bE_JV*eFm{vF#WASe>{|7usnZ?A1H3$7m!4YRxJSs=!qlj-`X%|!N(!u5XSZiY?Qr-m`o*`M*dsADV3TgXn%zBs2DjRkwGwg|Ns_Wh3-z=t`lYhoG zTYt@jJsL4TUgZ9kK5{>8S;9XN;rhPbx9FH6oHO>Yui z6~DD^8{gf}VW-?!wUfU4?mpjj6ns?6-89FqA0KO657S@n7&BWp+xGn52XnZt?Q=e7 z#&RWX-J0SA*7Sc&b2&^p^!EKonpyvZ+qP;A2WOsLLAgWBx{XYE7o>mBj=9|aFmUO$ z2i9vMEZFzd<`g{e?l`ml?u+!KnXY>_XKj{#cSgPBM+?8l@zd?H?Mpxhs>mj;&~^@8 zyyor1th=rGYoc_s&Sm{ovY61&KmT5f;^BAN!hBZ0OI{S*KXCfcDverR7cJZT_51(r z`uSwCe@a~TELStmHOdj6B-zdsYN|hi>}&m|rS<>&KdcDKF6b9n6PW#CIEp(;162x+eL>#?I|&J6!Z4=GK&D`9Ge6Om=lu!sc^zs^m9RY1cAu-Js>Af6(C6vcQ`7D>Htbue+WYu^~u$MJsry z_ta%^-8EkK-B?#I`l7UH!=;AIPoA^4gf@wSkBJd+8hLc|NlOH z{6oIxgJZ?E_ZQyJ+H;cEY}t>jiUnOy%r=Ui5DVKA@?%X--73*F?oWK{iq37hx4y|# zd*9C(U4f;g?oWCmXBr=ERek-&Q9D4#p>V zHEQ)`w{y2|`Uo9FHuksu8j>WXJ@vW9oc)iww9l*vTzqB@=v+;G<3n9r{}wIVur~L_ zchI_A(f;#Od`{2Zt9(ab&D#E3AM)1LRg|{hE;)N<=CR9N4=0wq+Mj;(Z1uA1m-gyS zRGq(@`_YbvZ}w>J%klZV{&Y+F>C(e5Ddslew=qsW*0asx@$~x%g+0M~^EtbZ1?=3AH4$y;E&QYvlS|)j=kNcp z!d@wC|1{&Z{*f0el21+%lM23JtqvLtHi^GmtrYvxsbF{@&a6^h*%xH>`RDWbvq7EznDUR6`+x5#2c6HfbomD7@GM&2B96$LH66i+nlrsm%VL-?s11omcrxvht+s!oW|T=l{Q>6Sc)- zo#@fn*Y9?}7xR{XUf5yHe$8>+$4lP&GmXz#I9FA18fTtJ-?`!2z3TkUZ@1m{ikMTJ zXb(Eft?vEK=W>NSnon<>nyP(vUiCZ8hkw7WuNSqS>Tz1W>e1q#pC8NrkLaua|NH** z4FdfgDpi+387|-6#Nh+RDqH#aHEutawSK+e%-^~%s~@!Wspike<3W0p6nvkaDwa8y zyf;5LH}`b1{D!cr^7G8s`bTdp+bp_TUMjd|UkX=nk=pj1q8s^HnfSCb5?9@=H@cDj zFX3?i+JX&7Z}Kvi9)GnjmGy(3<>dQ1>0R$5{;zKStZ;2({f4@I$*dpa9$q-BTfFQ` zo`H%*Rqvl?*Zv#quAg<+{=l*HDPKQN`m-b{BI3_0|Fg6I98uu;V<|3M_vX*e;)^D3 z2dg6NkN?{I@1y&jGhVa5-3SPFsrxG_3qE{BXt{8c$z-$3Nq=wtDKz%#gaotxZ_4(`cRlnKTE@_=M;6VT)#g5x2#OZd@|A9D6;qRC-v#4OHas4<*zGrnYHoV z-tYIS)0%nBCL}+2%)ap%_(T+4fk#V&j<==mtog>dT1@fnndsi-S1(R&lYJ=%S_Avs zz3#C?#+0OkqW5)Y-nrnA@GB@LXwt&HJ1#AnbkcwGqgO}z`t$!LR!)}A{(AUsn8N+k zzd4fgI5KOEw|vsumiT@9p|mK!KZ+|hGAZXQ2#Q#Hp6z;}Q#*WYIKnk&=D%z9iMMtr zTzIuF`7rmQ%WippKOFdwFxkb@epA8(-t}8FIJh}(FWt>sJzMgX*2|6mJnW|xwf{L5 zcRccJxBfJyg&F;h`QVB5W9&s?*@pR7#Sf{h-{ds6cWGahh+=0$%KtOQ=Y4APc5^@C zdUXC{bpGB{F`Wp7Fz*(XMPEN2m!DqMR3(3qBX7m~?Dc!q{{6gr&icKM690=UCC3~0 z&wVTtFkflL-QC9z+BHqFV3@nUBV6Wqhj7vk^$#og@9u7>zC8UNYu6%;Q@a|cC#+@B zx6x@2e7OB_pYrY4>y6&3YlS+JFD_>uX#$I z;`Kv@HWsgr2kPm#=;+_|y0GKXFCPA7(`Q<)iTrSK{)&h_51P1D&T^y_^h(RyAGo6_ z`nJMNUhiie&|kg3Yya`LhQIaA4L?ki3bS}L?{m!Z zEjl|uM;gVNUi*1?siMjhx8t)=d;QyO)5Uef6a$wd4S%0UD3~$dzSC}8Dkhb z@8e6|ifJpS3-(>{zT*GJ{q=FL^VV}~BY%RHmwrvUqx7Qfx|ykIXX%taTbaf22TH4g z!j;@+YIoIdi!j@MBZ=G6|G3I=!6gsc-aN8+Uh)6$_ouV`9Fj|2HQevJ{&@at$Ln>w z{nk0&xszWtc}qFt_k`R%+#;@lQ}pFQhrd=F{HTB7XNUgYFF}z4921}ZQ87)qbZF6c8!HnX-a3Da=ku!9W#;5eIVQ@xYTYE* znXjVSVJ-EnKYlPu3Af8tt>DPk+5P2Gv5wU9qMtqzEu!k0Ywk5EW`LHOmddhZ-rZ<< zxxgO_&7@5TS{MjRJh&hxa4PqE{xQ77Nenpy6k z)urP1ODtn{b{t>6{l}wj{Uz%b{yS>*((2Hnkg9vTvszt$gdXbEax}U0^SPLD(hvPb zU;lhQpI_YJaU@Ob&R4-zd8Y$jteB9tH1X9V#9Gm<-}C}RTm$#jfQIVwG)hwQxUZdf zA)qQ{W@02UNu+i9zR%O2Etk0%m)s(AE>iZUT5R|Gid~A?JWJnd{eH8#KWFi02f?H3 z1dnkY;YdjrEVX@aSJz>#^yOi@yqJANnc$6xCH@uFFY;##E0nSL?JV}QI!yU8j3l2HC23CEZm$p!F;p~TXpoOLj=7V?FZr`<&-`-8~u;-IsjusBY}6OU;+LT|Qg?(t8lQ#SD`9 zr-N66_Mh+8(du}#BvL~#ipRR^5Vy@P34tT+ZmK^ERa&1u+jDM)p)-pt-)fZ&sd+g< zQ(X$9b}d@+l)u;H`fI+HR#mes)^$&gcfR}aNXCR`qkx4(Sh(i=+DF0N3g=d5b{4z@ z4On))XKgYOpB*=Mz5vg|BZsEC=$YyI=;ZzF$=qu!Vb_%`mow$kDuXpA@_+uz3{%m0 zHhCJSw%@d!I|>E9R(?{KVT{-HQ9rWuqRc*C{`G1KB?}EbeI7>~!wn z-osTd+n!s6pIjt+^!dDFo~P6Am;7uf_$H^6^L}Q;iMRQ?n4CJQ#6Na@csw(8UWTdl ztVcV3u83uvXj$yqo^4NLH7oN{= zFWd9yQJuhq80n8DNk=#$EhoLc*!?!_vTM$x{)Z9HZ9Fd@uq%qG>gxR4_pnXc$|6iC ztwU;m;oeg^5ib4~`p@5PyY07T%APg(JD-Y0>KbwtSHF<-_nO}PXJPv+^uruZ+d&U= zNPNf_wgI#-q<8Q3v^O_4=KefvV4Z$dclvofeo)*Pn9n>KFe$99P3Ng(MCYvcAB?8= z{P}u}i!E%1t`C1$=~>=Q_3vkHb}~xu@{ev5+EyI7bE;@ke7=ppcQ$=Zu0P-8wKMRb;h!o0(*C|V@Nt2o=EHYKOyB-2n3~YylgRx#eYJvJ zTBohq9j@6Yvi7_Q=jtwDoyWYtGR#&k^Y5+Px=Fs#H~5J zITN0`FZ*`Z88f+M_l_lZ`Np06we|NILDm1a!VYb{{%psZ9k=i29sjWXuk77=v-~RS z`PxfY2iMqbJ)ZQjP~qIpu$@z9$d>-Toqg-~?W*~_>JOv#UGO|s6S$_#X1(X?z2VGZ zk5W^7YFgu5lx1sk*m)!r4o#^NoG7+5Kx4-Gny1=I8iF0K*YDrA=HBe{&(Cg3eY=wiA+7HM1j==~&bJ;+H&N247h&_)t9+!Ll;CP_k8VeHx z4)Kf6{>asQIQYoooRg=?GJ(}Kd}@69f4mZ9i_aK-TI7F9{*qsF!+DVjdQx^AFEb+S z>NecDdhBiJfdaYQO$Ph72H6RV^%}91MMZ4o=+$wtE=-%a=EvRyzlf;Hec$g@ zKb_Ic#|>Ukxx`kxW|@ll3A>CA&z9E{9M&WSW*@#c>Cdl)3Ylk5UI=38iug5a?T3mR zT%6h_5kK75CAzx4ZVF;|6RqxQdso`-i6C{_^EtYdx!&J&Rf7`-leXhkx0>yi(S3LjdE_>)i_lg}) z^IZ&+rWmYT-+eTxozII!{m`Uc?K?LeIeGBC;MzU?74?Z%m;O`pu@ZkN(A#&e@NoCs z3|0Qkpdq&MaQR=bp5Td_(-Xf&Np}S)C$Od;6oIdCd^blwLUu+pJ7_Q~VMf;7Idd{? z?sLum^8T}Sw&cFUU9Ov7K9_v9cwM%^{%=PT6g7|NuQuEL@La_DpDp|+zPILIy50`z zV{6!UbA_eOWjoCn#&slXr{&ec8Qo_tnCr+#)=g(SY$UyJKL481{r`lz7fQLaW?S>T zJeNDe_~`zrx1L3x{_}v*?OFQrvj@XKomSVCYFZJZOQ%mroKoF>ZKZqi;ijpx9H94k zdgX%F6;@3abPMZvI@v61VGvkL;FM1*62NE9gU6b(CdvKeLtFs5s6-sJgb`FogBD!+ zE^=;~S}GRy>u&k|+NY0yo8PNQes=!Whq>|lrl0uEwt8dG2C$Ff^)kBuyl}VY`pyKp zKINqO@2U45x7+_&xP^1^huD`vo~Z%x4!UbjS#dT^7H3JC%Ky9m-_Pd{CGGA0{Yd_K zH*I!q+PXcTynfo8+vW7SVdb*ajN@L>oE9&aOg;iyLFr{$`D*3zGqvCEs^>jC)cP=R z>Gq13OQ+xZ6yGaQ%dgL^eSf3PqYmXWS5^j}eQ|N|)3kWVslWFYqo4X~eu}hHe@zJ9 zn}Rv?^S0o;%+pUBF4e9N?fAZ@^7E6Y6Q;nnY#-{8GCg%>rm=eQ&sDBc$LA%_a+k|w z+i!LE-POADi>lcmtNYHoBCqZ%jnxe}TeZ)8rJL+Jjjl_flWtA3Jz8GOjO(_Qo13-? z&q2Ly1+l;{V8Wcmi4F^2dMQ8qb~}H1`|X|2=hxfW2sg0u20A4w%N&xnEJ~@k#?NKJ zT1L?sx=dP67rw83pSvPMuJVasC8tW^ox+iI{Ti=y28WUx7QuMALzv^%>p?T)^{-z z<9W+(8`mA`(mcQY=fjwA1^M&#|7$>lqAl*X9!fkfi1^cQ_ba1vVan4ro6i{?m#fZ+ zuH5(SR`yfLJK5{^I?3PE5Kli2+QwUV&i4Bqz2mp17nR21TsrsT+Go2ZM`!*~TW4|n zNT=}AI)V2(A)EQaMO;ygHAHBiAN=lh83)yXh_8=AyqUHjkQ>Wmq;o?m84uytFj^8TJ zkHx92S8H!Ax|*l1v9*1Ag0E0hphUO7zxAWz54lca4vY96oYdAG#m{)L&BJ*OXm>DI zMU=kR&J7Yw+#>J13TmsKRBBYL*c2gr=@a`$iL>%;R(qi5!#?b?aBZ-x`D5_^67Tz? z`!}z#1C7Et%hy11tcP`P*7R!@v7X|UHaRyo6r7iDNq@Yf*jLm3!j<}O*1`MV@GrCY zpq+Mh$NVW~cuA^}dLNU-bp^R>IcH#e^3)>1pQM{rwWWG40_D=QA6MTN1(^eP6x%(Z-lL zi60&ud;}V~IIr{ZS?bN;DXU*^3ebz~xN7_D#$gi^lM{ax{EzoYPQGE`p`2~|-Z^TH zrhfge%k!W70iCmOJnihP)LFA;oq1pXzxw8Ruku#~u7OkLF>UOk{zh_$)fo{px zcKda_<*qT^VV0U{al}j@y?jkrrd;8alcx1aY4&L%+G|tSJb!{J_xz_?SDm{K-dd`?FY8K z>;A2xv*P!o{!RVGb(=ojzW*=m)U9TII|;c=_D1J^4bTo(8^;&f562{;AQr12Ptw^(a zCUE`C(dCPqHy!@cwuXC!WBF@vJSL^BJJ@x_?X$GD-OTJ$-$E}Zm2Evf*Y)f9rD=jS z9ML+{f_>(SZd~nh#!6tzd$(`9PaO;kD7ss(qdR>^OlXW^)8xMz%|(@;Cl}P|{F}G+ z_T8L0i~AK@ z+Xo&zasTJB)@330_1qY_*ZhwC^1W{t&TlX-QcbNiZo(3(GKRto16q_e2 zCR6?6Vf)^y*vlT>#z*FBg3kgCSmEVzI%`t#`I?=()~!CD5Vfn~+Wq?ffBBO59dC$! zeEwnO^IDB^eSzyoChnT`JN8_@<*Hav6%@kVb|R^=HqRLM%mixyFQom+{^{x!4<~->sL?tB-?)Ri^x~+d}HQ&cGpa5s^%K5)%HF8 zf!SrpvFC@su|4@8=q{UjtY1D~Og~O1@8zYX4{xqJXng7r7msP0h$Cbb7$^{bTr0h* z)cxYyLhG+JVxR*%SA~MZN?2!2gyG`6y24QPk2{s7>$ore>>Vj9ar}|@mZlrvOMl*P ziCT63R+hSkt$#m9*tB_W4zAM4g_o+f3r6vj_c}cmN1WMN^w~7h7j|an^_eb9kEK9H zQh2YuP||2=WmSfbq?l%3J8^Ae)z>WJjDX`>8s2i>R0W>j-T3HeVda@UH`XL*=E~YQ zi@A6?|8db-_^0>kRo=U2nXcVzJG$S5`JU}jo*He5sTYh=_-`ItIqj=y=0y2V@`%-1 zpXUFZYqPjVYJu}IYcX4o=ouP(=UFm;K4|7Yq3a_;{Q>+>qzu}H%!zv(IHq|6AP#eA#NM4s*PGc8SuJ$kB3qjU%B z^bJ@3nb^DBG5on;@!Yr5@Lw;K`NhTB5p~7Zha}L5iXp~|EobkaDGa<}e)JQb3wjF7<3%dzff>co_D6Ab6d#=XJrE~lw&fFdj9C$+_C|3Oy?Moa62eO@n+UEA54u0-l-+8!-H;O++eEMb|H~L0@w4X# zBhPtV=k)IRL4VmCYuIwHAMDp(v!Ht^SK+U3xAWWGnIF1Jo_YRxQH#sbRC;e&$VEmTAyG zJ58`*{nV&4e=fb^>$}>tKan-(QhCJrt=DHIx4zN3E%#u1;H+6fp+kQV`$i7$V$L=SSyn}REO>8tGIu1b=Id!-;A96`fJsswas<4vSd79)B7nok?<)b0ljrrfyIuxBZgm(Xel*0v1wSe*?* z`^C>J|Kcm&8*3+dWKZNLOYPRH^`<++exG`|eWhqy{N&b&1+7#4w{wPVTY4ylem-s!5luzoG~^V(`}$a8rHL z;o^4C0-@PYB+h>Vo#eE?v;5msWp7ZgF(_Ay^V;?`8)A}LHN(!9$L)EBdpf* z+bi2@Zt=&N39YZf*Un$-{C&^VO@RlyZq#0Ww>io1d2{RHu$G+yC*L~hqI=Ow@rn+lw z`B(I!xB2XQ`1JSL0Px6*h-=`gcEV@undk5SyA52$Y_6SsNA26e`%39v@@?!>_KHXmJ#i=X)v9&YEq?k5PgW(vz5oi)+9Tc=t+>QG+t(XQ%C zM)CdH?=w&9@3*m;{U`7V+7QW0<hJ%v zDdu*oEN}Mmxn)M6yQpWHWKNQ_C|FQ)fAahE*oud(MfciuejaY`%{(9^mbvrmwP@?7 zv8wiW7H>XpcN?@mCbzKe%SCtVJI3w)a$(BztA!s~=ijpdT`i^hta|AunbyzYF@>#? zrdd;F8mIgDF26l}*Wu!22FB@9{`yjjA8T6`UT|bTxw-hFt9YyXDt@M^&pFf1&(kfv zFt_}k=I_Xly65dmyFsz2;kEXmY5Ug$%=}XxPMlx+EwVyIQisK4+8k$%iw3W}7Qgs* zJ74_a3)p3|O>G)CYro%Bg^z$7(QtO#xNJ$I$H7Z(QXTBP-iK8FtO+?Kzs|EpV0uey z>+>y_{U%pf)%=-Ley=j^SdV0G;W7RF2OmisRp(zl@%-Mig~w&pZ)>mL6SS?6&*A~Y z`cFJ}=FiUG7b*1F*Z{yeug z?-tXYl^)yDc|YqhJ}2PKn5f44Q%C&Tz3TV5pv8oo z-Nkxu)aO+!I{V)C`yJ&z#icUQJByayEIx0mx@Z5tuj?Nz7s~wEtg1fC-u~am{--~_ z@Bd%R$vv^p^VlT{BrB|J2my7ITiTx^wH+t!c+256p_RSJ$6*c31vWpLzc#PCYioj`JMz^H=^G z>iAB~Jfvrt9QEdB`Qgda+KN9d`|x$n$=o!bzxEOJ->h~99utY@vOU02J@;>}g!}E! z?CgmTeOB+i7M&=u{F!f^()>@`es8}0_X*qW?7dp;#*MD;e?0D=UQ~2KvAski`6`?D zlR$S_)$<7@JMu~@bi=%@LN-{u+jv|q?aU0rXIH~-3m-Ff-+KhI3PkeVTf(bAwp>G6 z1u~%sc@>Dw<<8dq;AJ3Rk8R)gbuHi5Hb^4XeUzHG_R55)9R&*`?g^On?frJkdmF#a zhlZTRIa@BeZIU(5o0Bv7K+*vLvzR+v4NDmqyA?n?1v#|aj;aRg>9lQks##Ge6eF*F zG%|f|s$Auhi9TVExBNNzv`F?-`?3AmF_Y8QRD(8}-b`rbeIoJWhvS-^3wQr;_hE3_ z6T)?@;TI%|Jgh&5#YR0Yag~^G{BRpD_xC@JYm`KM>sL$5>(0Ek+*?WF^}fshUWlf# zI+u8NGubN~E-UA0NtHJH@#n^zAC70l_ND#3ao_6Ix1#GC9}0xM=&I*lck@@y$t`y> zz8_9HasOPQ9`_Vhol+Zi4o?=9-|6!z)3WxJiysj^^8PU90*&83m97R&(yxBs%3j}D zU$_19IqU8d%vMY96h6p*ZozI-&5;&fZgInXf)M+HVD^t)k0lD7c)qjPJ-vBV`p)bv zRnFiI^-IN8o=VTnFi5oQ;o1)xeUNfJqulfOS!Z1R->(lRmfiUfBULdwXH%z%nf~rK zMuPEunU|N%G{0Bj{7kG!SLSfoV$g9JPDd_ftY+ygUU&XO!Wxk?iD#Sq|GBvSWEGE5 z$aGU^&Xxh4E_UzYiDz?!MLt#@v8$Y+I=@=#9iuF3=DILJ#-FW*zWX(1O^aS@v1et< zto7Qb_Ax)ytovvA;qsr^33-`yxBHq*(_Ql~?`NsI@krg=#3r+F+T~~WZxwK8mnI;@Z?Wq9F4Fn(nE89triOwgF@gJT^iO;5^}YMttTo^bZbh=&Id(nV>g(&9 zB)c@3?f47Ug1KQ=G&=&Hbv>G|JMFCQwi{08E^jB zc})_RXIZmS4dC=uk8y9Iw5Y_%)2m zd3%TCFBhEoMH72d#kKj5KPvoo^03a&JChAsCib){hZUIsM0Zc10xIt`q;cm-)5sm)#or&K(;sZBi=O`V+MFLFU7sgt;Yi z)dIEdu3s0GC|EbOKv_Vbx8&ZAqdgM;x-)G5|M`4dMoDPnOxE(+mQ}ZnM69%yL}t!- z{$$ByKOy%W54P>){OUGm2|Pu;6g+t9PQZ&(cQn>ayr`IG(v!KwXo)UYuN!!q*P<}? z7MXLA<*@Y+{XCKHAnPCGt6nJHWLk8?^igD^MB@vcMdykhKW?v3{w81dBk^N%s(54X z(l4NHyMjsWrwzM*#^`d){<3_h22ZkEMtE?@<`+TXC%?XzEj<4rUT6E-|A9tJO;v+u zOf=@bf4+O__E{ffE>t#th}m1Uwa4bbr<40$i<~UlUnOi_WASRkv9!i?Cha#ZoWd#f ze|~(FU9)$;FpBDRFnLQM5!zp|!|xp?uh9!c1iEVIcgRIXjRB&w=gpYgPi# zcTAF3-}ShAw}Q?F1J{qBNR813t!y}1R0-*fpAEj^#`4>j zJkzzC)2zLh{d_ekbB;8R^*R5^zUnGx@)`sl?R4Cu^yftJv(9fzzTQ3S{+6rb%)w@M z@8#ZCEW0yh)-1_1(3xS>C_is?`Tg8@#qOE|S*JO;%ylF#M)m#J9GM%l_u)I=pu1pC zb_I1;tQ9&lVSnW2w3(o*CGO~kc`yBV_>TT|iO%L@+VdS2P873$en9B(cHc~!qkk0? zcA6c^IMN}w>66Cw!(5M`s}O3ys}S0M76x8A^ys~G-j0RM$*PHM7N4ZkrzRX!($O?| zx9xVG^~Rt}H+Dar7M-&7ti~DM!<#07uaszQMq7oDxOAp{eO+|K)IS?OaBDBf+xzv} zv3t?RknK$~mTi6oEv;wFK9gkSsqO4M?Gw+M31`YHW_El0OH;MiO@9^f@OsyUKhrEH z&rkY)PeWb%JJ;X0%^811EcPulEWLl~bj{UkzrB}zNqo>M+O+WN$!`m{tod~Mk#}C{ z{awj#w;q1|_|>-!*Co@=-%bka`PO^GTXdh)vE(Ja!vEBtTKzi7AS-c3{AiYY-S;b6 zm)0CPeWL9L*WL~{tE?M*5(W+}nqS$KbiEb^7{vcP748zCByc^xzBY2N`TX;> zc6pt?$2wD7l4UlYT3+zzLc$u6Ylg>VlzESW`kN*iKhLnfT=cMKLSNg{$LyzddEdmA z-`%Rq?|J!Zc>LXM3wr$J(oQ~)YI3t$G}mIYN7$b@gXIQmZSGgU-&=IXv7L23XHucg zCrj;5nNqW#?%cR=#vF+qk6wR^(TKSDDRSnYuy1$L!hFr5606EjZuytK+v2O>n%4DC zQyJC8*$!>_QF3z2os0jZC!Bw|<<^G};>SAAzYy8HR&|<(f8D2!=WL0v!+;o%eC~{3 zeWwbVC|BcJEG1ApC39ZzpFp+^bKH;W)+=`jE^aybIZQ{)y2L=yLU7s?*=MJO)Y< z9MAqWLNMK3i!|=KLMOGsN+;v%dv)t+nzCzudAIxhzGdz*Bx&Oh_VQfi;{>2jl= z=Tdaneuyp)I5)-4XxUfE+9%NN+)?(e8?;PWn?AeS|C-ow6|~c#<{!2R>NUQ)6Xs|6 zB)*@s(%LA!=kIcu4^#K(tf@Kv3F+=xv+sAy=kEj`VAJTzGjZZE)9W$GdAr|kD_C!n zdHvVT^L1(eejK-Nt7g=T>zLeYe(#1%*^R`slao{*M%tgVd@l3((`o(FTVror+#q0s z+|`QQnl-iZ*URN+TgBrvp4Xn3WN-iHAwTFKb5)&7MX%RxFFUo{t8RyT`utkZc{aJX z9{qW-xPRN-&1=4|miqaI`C&};+pUxKXMX&AQeJ_-?qhfSiL!HZENzAEuenmMpYHWu z@^aDgs0c{!S>!0YKKJWJb~%m1I?z*Mc=o%Tv1$)+(oo^-^11`s5g;=cwjywe3_m$c3)P>8?qhgNmU9-F7U?Z>{>rpXL?AiXkl0TQf^XW9%OR=4Y`YbQMpS5SDwb_j%$yF&FoGWkH_b^6cM}`F`FD%mN`jmRqdqbFz2DiAL$Z6?A$2MM%t3LS+<3Qzz63Ks^ z-O(2W^f&}rPJelM*)>AZZZhaRDrcx0bOS+uQn`)hHkwY9_bLI~5sV_!F# z8R^WjoCcacT%oZawz&Gxt>gSLB^O=O4mPnC@g??_+F0qEYTCvBeHE^1cTu!*^OIt! zC$dcTXMaAL{VgjfD&_8>2k)=3doA0sVet!{$lSX{t3?-IGrY6?tG$<+`N4S|5s@Dc zuR1U_jP2Z4^JOpNyNYzT9jiLe%j*x?!veFH$XNs<=zo>YEV+m-}Ok1;CV#bQkpvAs{-Lg)6&)4kEnY^y`>&G+3=S3!-obYtr zrt@~cPkdY0E;mV6p=)kMDr*wUqRkyv+8g@iANAg-|M9T>DF3t&7PD!Wg#9cO12cr= z`_%8QfA`FIzv8`2J+8z3f+sv5Y!A9MIUz2u-{8=UHsduOceT`~h0p2m0}p9|M$X*& zIl}Dfn>#wV&Rb+&vuhD^wp*-_Bw!r)=#Uz;eLDGS$=!nRHIoiZvz+Z2B9xu^vTM>b z`;Oh3!OL2z9U~&_7Kc6Xs+;p7ZgX01j_m62^=8d%yj=S$=(`5cy5s3-zl94IKAeAOe{iD3%Qcak&pbIfIaP2m z=$9X#4lVjcqtt8?4 zCD2`U z*=fgr39>5naTO0+KV&exJoxGLCD(|@$NSBpr?r^gg|u2SVwY+2wWa;){3@p&8NFf(}jZdJ_rgRi!6c(grz z)E=6Em`Z3aorKc9`|@)6{H}<-zu)bCS|h?z3*9&!3EnuJY@B{>N{J{JtKg-J8*2U} zXx=Tk?0a_I?svDQwJ&-3YV~?E?eKLxwX8dSAGNvqV<#xM1kSWHKS(QFy<}6M=3Bla zTJv`&25SFFIq1G&n%%}-B^zoR-t7ESq8-)FdR%bh&W+#7&o!JCd zx9d3J_q?diyz}5-bE(YYAmfC+`+hv?Ub>jk@%;UZQ@gbfW-x>mvzhmYgL~$#fm8N% za)m8bJGiJn!*$KH+1#@2mPdHR>z+;xH~Q-bQ*+B1rTz5fgw{c5?XgIs>ryOA)2ovU zarewpwLp}MY2XfY4V*H|1;tE!Z8DVe4XJLKK=Qx(6A{1vHC|zDV_;xl@O1TaS?83{ F1OS6AJmCNU literal 39790 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�%R`1>fYum72Pkd_p49>W5 zdzIa6ev`39YKd6O!w&1^4! ziSW91GgaPOJ$4uT_cBVwzdYD9b){?!!`&-0FYswTcx`m+O3903J?&EXf4Qb}J^b3yWp+NStQba%VHk##E+Txyje#t*OsD z`zo*9{&eTVQL{VyD&&kVO)5P7=jM+em(TxXc8|$1(F=)p2`=Uinj~b<%~@b{va_%2 zL1yTihpv9JUrulfu+4P29cz2_)g{@WPlp5cY<7#A=iBD&yHw{^GlNRd zruTB)rnx>0+ZWI9To|La@BPIHUk&LSK?hp$1ci?sar(BGV@BnFzX@ml+5LX!ofaRV zbFcfIpw4;sExH#ro;TFl9-lF5W`((OO!Be2I{Q`E%n4h@*tXfq_S`;q%ivo^ttOJQ z)jpM9b1_;nf0_ThhPBq;Jfh#MSjt&7Pfqym3=$6@b(e2;9-+%J*?f(i5*=b|<6Q%fvIBvZu2@vu(+bV1Il+ z+|hmULvU8ma8N#OvgV0&MKLInWFWbtksMk&ON>DzkKxcnS9FM zHrAdqeEE7I_cq6**LrI6<{SM^Tzj;^JfhBj(|OTJJc|>LibuwpMSS@o-z~2c`P}d6 zsm#?fmlnxf;+U#&P#=jfc`u{rJ&)wV8`*klLC|=s-gzpL;6H7WQ9=+7mI)%$o zP3hAKQ$b
{li3%9({`Na0D;P=B>-N_r<_eQ>a` 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 Date: Sat, 16 Sep 2023 18:04:22 -0400 Subject: [PATCH 051/170] indentlog: bugfix for 'simple' function sig style --- img/ex4.png | Bin 40417 -> 43138 bytes include/indentlog/function.hpp | 18 +++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/img/ex4.png b/img/ex4.png index 56e7796dbf38af02ed4e92fd22016d7b7efe6f02..38035dc6daee003f08c9018b68b5339bc304cc5f 100755 GIT binary patch literal 43138 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 F1OS6AJmCNU diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index e6e6600f..57c2c1da 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -37,16 +37,24 @@ namespace xo { std::string_view const & pretty() const { return pretty_; } /* e.g. - * std::vector xo::sometemplateclass::fib(int, char**) + * <------------------------------------- s2 -------------------------------------> + * <--------------------- s3 -----------------> + * <----- s4 -----> + * std::vector xo::sometemplateclass::fib(int, char**) const * ^ ^ * p q + * + * fib <- .print_aux() */ static void print_simple(std::ostream & os, std::string_view const & s) { - std::size_t p = exclude_return_type(s); - std::string_view s2 = s.substr(p); - std::size_t q = find_toplevel_sep(s2, true /*last_flag*/); + std::size_t p = exclude_const_suffix(s); + std::string_view s2 = s.substr(0, p); /* no const suffix */ + std::size_t q = exclude_return_type(s2); + std::string_view s3 = s2.substr(q); /* no return type */ + std::size_t r = find_toplevel_sep(s3, true /*last_flag*/); + std::string_view s4 = s3.substr(r); - print_aux(os, s2.substr(q)); + print_aux(os, s4); } /*print_simple*/ /* e.g. From 2a6b7057b9d11b94f4b5af487ff83adcab43bb2d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 11:36:33 -0400 Subject: [PATCH 052/170] + LICENSE --- LICENSE | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..ed66b81e --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +The MIT License (MIT) +Copyright © 2023 Roland Conybeare + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From c608229981339f2dd71b7df4618e3ef9e487fca5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 11:48:24 -0400 Subject: [PATCH 053/170] + FILES (map out directory layout) --- FILES | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 FILES diff --git a/FILES b/FILES new file mode 100644 index 00000000..68a84654 --- /dev/null +++ b/FILES @@ -0,0 +1,23 @@ +directory layout + ++- README.md markdown README, for github ++- img image files, used in docs +| +- ex1.png +| +- ex2.png +| +- ex3.png +| \- ex4.png ++- LICENSE software license ++- CMakeLists.txt toplevel cmake config ++- cmake +| \- nestlog.cmake cmake support files ++- compile_commands.json symlink to record of compiler commands; for LSP support ++- include to install, copy contents of this directory to permanent location +| \- indentlog +| +- scope.hpp +| ... +\- example + +- CMakeLists.txt cmake config + +- ex1 + | +- CMakeLists.txt ex1 cmake config + | \- ex1.cpp example .cpp exercising indentlog + ... From e324b9d007839de2cc97134272bfe21a35d7a135 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:25:05 -0400 Subject: [PATCH 054/170] indentlog: refactor: + color_spec, streamline color implementation --- include/indentlog/color.hpp | 138 +++++++++++++++++++++++++----------- 1 file changed, 95 insertions(+), 43 deletions(-) diff --git a/include/indentlog/color.hpp b/include/indentlog/color.hpp index 6f1d52f8..5caa1ace 100644 --- a/include/indentlog/color.hpp +++ b/include/indentlog/color.hpp @@ -13,6 +13,93 @@ namespace xo { CE_Xterm, }; + /* specify a color (consistent with ANSI escape sequences - the Select Graphics Rendition subset + * see [[https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences]] + * + * this provides three ways to specify foreground color: + * + * | enum | escape | example | description | foreground codes | + * +-------+-----------+---------------------+---------------+------------------+ + * | ansi | \033[31 | \033[31;42m | 4-bit colors | 30..37, 90..97 | + * | xterm | \033[38;5 | \033[38;5;143m | 8-bit colors | 0..255 | + * | rgb | \033[38;2 | \033[38;2;10;20;30m | 24-bit colors | 3x 0..255 | + * + */ + class color_spec { + public: + color_spec() = default; + color_spec(color_encoding encoding, std::uint32_t code) + : encoding_{encoding}, code_{code} {} + + static color_spec none() { return color_spec(); } + static color_spec ansi(std::uint32_t code) { return color_spec(CE_Ansi, code); } + static color_spec xterm(std::uint32_t code) { return color_spec(CE_Xterm, code); } + static color_spec rgb(std::uint8_t red, std::uint8_t green, std::uint8_t blue) { + return none(); + //return color_spec(CE_Rgb, (red << 16 | green << 8 | blue)); + } + + /* 4-bit foreground colors */ + static color_spec black () { return ansi(30); } + static color_spec red () { return ansi(31); } + static color_spec green () { return ansi(32); } + static color_spec yellow () { return ansi(33); } + static color_spec blue () { return ansi(34); } + static color_spec magenta () { return ansi(35); } + static color_spec cyan () { return ansi(36); } + static color_spec white () { return ansi(37); } + static color_spec bright_black () { return ansi(90); } + static color_spec bright_red () { return ansi(91); } + static color_spec bright_green () { return ansi(92); } + static color_spec bright_yellow () { return ansi(99); } + static color_spec bright_blue () { return ansi(94); } + static color_spec bright_magenta () { return ansi(95); } + static color_spec bright_cyan () { return ansi(96); } + static color_spec bright_white () { return ansi(97); } + + color_encoding encoding() const { return encoding_; } + std::uint32_t code() const { return code_; } + + void print_fg_color_on (std::ostream & os) const { + switch (encoding_) { + case CE_None: + break; + case CE_Ansi: + os << "\033[31;" << code_ << "m"; + break; + case CE_Xterm: + os << "\033[38;5;" << code_ << "m"; + break; + } + } /*print_fg_color_on*/ + + /* escape to reverse effect of .print_on() */ + void print_fg_color_off (std::ostream & os) const { + switch (encoding_) { + case CE_None: + break; + case CE_Ansi: + case CE_Xterm: + os << "\033[0m"; + break; + } + } /*print_fg_color_off*/ + + private: + /* none | ansi | xterm | rgb */ + color_encoding encoding_ = CE_None; + /* ansi : 30..37, 90..97 + * xterm : 0..255 + * see [[https://i.stack.imgur.com/KTSQa.png]] + * 0..7 standard colors (muted: grey, red, green, yellow, blue, pink, cyan, white) + * 8..15 high-intensity colors (grey, red, green, yellow, blue, pink, cyan, white) + * 16..51 chooses hue + * 16..51 + (0..5)x36 increases whiteness + * rgb : r={hi 8 bits}, g={mid 8 bits}, b={lo 8 bits} + */ + std::uint32_t code_ = 0; + }; /*color_spec*/ + enum color_flags { CF_None = 0x0, CF_ColorOn = 0x01, @@ -21,66 +108,31 @@ namespace xo { CF_All = 0x07 }; + /* stream-insertable color control */ template class color_impl { public: color_impl(color_flags flags, color_encoding encoding, std::uint32_t color, Contents && contents) - : flags_{flags}, encoding_{encoding}, color_{color}, contents_{std::forward(contents)} {} + : flags_{flags}, spec_(encoding, color), contents_{std::forward(contents)} {} - std::uint32_t color() const { return color_; } + std::uint32_t color() const { return spec_.code(); } Contents const & contents() const { return contents_; } void print(std::ostream & os) const { - if ((flags_ & CF_ColorOn) && (color_ > 0)) { - switch(encoding_) { - case CE_None: - break; - case CE_Ansi: - os << "\033[" << color_ << "m"; - break; - case CE_Xterm: - os << "\033[38;5;" << color_ << "m"; - break; - } - } + if (flags_ & CF_ColorOn) + spec_.print_fg_color_on(os); if (flags_ & CF_Contents) os << contents_; - if ((flags_ & CF_ColorOff) && (color_ > 0)) { - switch(encoding_) { - case CE_None: - break; - case CE_Ansi: - case CE_Xterm: - os << "\033[0m"; - break; - } - } + if (flags_ & CF_ColorOff) + spec_.print_fg_color_off(os); } /*print*/ private: color_flags flags_ = CF_None; - color_encoding encoding_ = CE_Ansi; - /* .encoding = CE_Ansi: - * 0 = no color - * 30 = black - * 31 = red - * 32 = green - * 33 = yellow - * 34 = blue - * 35 = magenta - * 36 = cyan - * - * .encoding = CE_Xterm: - * see [[https://i.stack.imgur.com/KTSQa.png]] - * 0..7 standard colors (muted: grey, red, green, yellow, blue, pink, cyan, white) - * 8..15 high-intensity colors (grey, red, green, yellow, blue, pink, cyan, white) - * 16..51 chooses hue - * 16..51 + (0..5)x36 increases whiteness - */ - std::uint32_t color_ = 0; + color_spec spec_; Contents contents_; }; /*color_impl*/ From 1be7001966c27e4d91d3b7592c3f2e17fd0e636a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:31:14 -0400 Subject: [PATCH 055/170] indentlog: refactor: promote use of color_spec --- include/indentlog/color.hpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/include/indentlog/color.hpp b/include/indentlog/color.hpp index 5caa1ace..508507ed 100644 --- a/include/indentlog/color.hpp +++ b/include/indentlog/color.hpp @@ -112,9 +112,10 @@ namespace xo { template class color_impl { public: - color_impl(color_flags flags, color_encoding encoding, std::uint32_t color, Contents && contents) - : flags_{flags}, spec_(encoding, color), contents_{std::forward(contents)} {} + color_impl(color_flags flags, color_spec spec, Contents && contents) + : flags_{flags}, spec_{spec}, contents_{std::forward(contents)} {} + color_spec const & spec() const { return spec_; } std::uint32_t color() const { return spec_.code(); } Contents const & contents() const { return contents_; } @@ -130,6 +131,11 @@ namespace xo { } /*print*/ private: + /* controls independently what to print + * \033[38;5;117m hello, world! \033[0m + * <------------> <-----------> <-----> + * CF_ColorOn CF_Contents CF_ColorOff + */ color_flags flags_ = CF_None; color_spec spec_; @@ -139,38 +145,38 @@ namespace xo { template color_impl with_ansi_color(std::uint32_t color, Contents && contents) { - return color_impl(CF_All, CE_Ansi, color, std::forward(contents)); + return color_impl(CF_All, color_spec::ansi(color), std::forward(contents)); } /*with_ansi_color*/ template color_impl with_xterm_color(std::uint32_t color, Contents && contents) { - return color_impl(CF_All, CE_Xterm, color, std::forward(contents)); + return color_impl(CF_All, color_spec::xterm(color), std::forward(contents)); } /*with_ansi_color*/ template color_impl with_color(color_encoding encoding, std::uint32_t color, Contents && contents) { - return color_impl(CF_All, encoding, color, std::forward(contents)); + return color_impl(CF_All, color_spec(encoding, color), std::forward(contents)); } /*with_color*/ inline color_impl color_on_ansi(std::uint32_t color) { - return color_impl(CF_ColorOn, CE_Ansi, color, 0); + return color_impl(CF_ColorOn, color_spec::ansi(color), 0); } /*color_on_ansi*/ inline color_impl color_on_xterm(std::uint32_t color) { - return color_impl(CF_ColorOn, CE_Xterm, color, 0); + return color_impl(CF_ColorOn, color_spec::xterm(color), 0); } /*color_on_xterm*/ inline color_impl color_on(color_encoding encoding, std::uint32_t color) { - return color_impl(CF_ColorOn, encoding, color, 0); + return color_impl(CF_ColorOn, color_spec(encoding, color), 0); } /*color_on*/ inline color_impl color_off() { - /* any non-zero value works here for color */ - return color_impl(CF_ColorOff, CE_Ansi, 1 /*color*/, 0); + /* any spec other than color_spec::none() works here */ + return color_impl(CF_ColorOff, color_spec::white(), 0); } /*color_off*/ template From a9777a7ddf32810dfd9aca86b42cd2bab8b3f783 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:34:17 -0400 Subject: [PATCH 056/170] indentlog: refactor: with_color() uses color_spec --- include/indentlog/code_location.hpp | 2 +- include/indentlog/color.hpp | 4 ++-- include/indentlog/function.hpp | 4 ++-- include/indentlog/log_state.hpp | 4 ++-- include/indentlog/tag.hpp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/indentlog/code_location.hpp b/include/indentlog/code_location.hpp index e343fb58..e0460225 100644 --- a/include/indentlog/code_location.hpp +++ b/include/indentlog/code_location.hpp @@ -25,7 +25,7 @@ namespace xo { void print_code_location(std::ostream & os) const { os << "[" - << with_color(encoding_, color_, basename(file_)) + << with_color(color_spec(encoding_, color_), basename(file_)) << ":" << line_ << "]"; diff --git a/include/indentlog/color.hpp b/include/indentlog/color.hpp index 508507ed..37e0b072 100644 --- a/include/indentlog/color.hpp +++ b/include/indentlog/color.hpp @@ -154,8 +154,8 @@ namespace xo { } /*with_ansi_color*/ template - color_impl with_color(color_encoding encoding, std::uint32_t color, Contents && contents) { - return color_impl(CF_All, color_spec(encoding, color), std::forward(contents)); + color_impl with_color(color_spec spec, Contents && contents) { + return color_impl(CF_All, spec, std::forward(contents)); } /*with_color*/ inline color_impl diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index 57c2c1da..4b44c2a8 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -250,10 +250,10 @@ namespace xo { switch(fn.style()) { case FS_Literal: - os << with_color(fn.encoding(), fn.color(), fn.pretty()); + os << with_color(color_spec(fn.encoding(), fn.color()), fn.pretty()); break; case FS_Pretty: - os << "[" << with_color(fn.encoding(), fn.color(), fn.pretty()) << "]"; + os << "[" << with_color(color_spec(fn.encoding(), fn.color()), fn.pretty()) << "]"; break; case FS_Simple: os << color_on(fn.encoding(), fn.color()); diff --git a/include/indentlog/log_state.hpp b/include/indentlog/log_state.hpp index 01566380..814bf070 100644 --- a/include/indentlog/log_state.hpp +++ b/include/indentlog/log_state.hpp @@ -223,8 +223,8 @@ namespace xo { */ this->ss_ << "(" - << with_color(log_config::encoding, - log_config::nesting_level_color, + << with_color(color_spec(log_config::encoding, + log_config::nesting_level_color), this->nesting_level_) << ")"; } diff --git a/include/indentlog/tag.hpp b/include/indentlog/tag.hpp index 258b432f..a6825bee 100644 --- a/include/indentlog/tag.hpp +++ b/include/indentlog/tag.hpp @@ -96,7 +96,7 @@ namespace xo { if(PrefixSpace) s << " "; - s << with_color(tag_config::encoding, tag_config::tag_color, concat((char const *)":", tag.name())) + s << with_color(color_spec(tag_config::encoding, tag_config::tag_color), concat((char const *)":", tag.name())) << " " << unq(tag.value()); return s; From dfc84d5fdedcf10bf77762edf2e8497d9eaf5162 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:35:29 -0400 Subject: [PATCH 057/170] indentlog: refactor: color_on() uses color_spec --- include/indentlog/color.hpp | 4 ++-- include/indentlog/function.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/indentlog/color.hpp b/include/indentlog/color.hpp index 37e0b072..7e600fa4 100644 --- a/include/indentlog/color.hpp +++ b/include/indentlog/color.hpp @@ -169,8 +169,8 @@ namespace xo { } /*color_on_xterm*/ inline color_impl - color_on(color_encoding encoding, std::uint32_t color) { - return color_impl(CF_ColorOn, color_spec(encoding, color), 0); + color_on(color_spec spec) { + return color_impl(CF_ColorOn, spec, 0); } /*color_on*/ inline color_impl diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index 4b44c2a8..85727eb9 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -256,13 +256,13 @@ namespace xo { os << "[" << with_color(color_spec(fn.encoding(), fn.color()), fn.pretty()) << "]"; break; case FS_Simple: - os << color_on(fn.encoding(), fn.color()); + os << color_on(color_spec(fn.encoding(), fn.color())); function_name::print_simple(os, fn.pretty()); os << color_off(); break; case FS_Streamlined: /* omit namespace qualifiers and template arguments */ - os << color_on(fn.encoding(), fn.color()); + os << color_on(color_spec(fn.encoding(), fn.color())); function_name::print_streamlined(os, fn.pretty()); os << color_off(); break; From 3fa1ed052fb15998912a939785b2afe69861a69e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:37:36 -0400 Subject: [PATCH 058/170] indentlog: refactor: function_name_impl<> rep uses color_spec --- include/indentlog/function.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index 85727eb9..65ee5ae5 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -29,11 +29,11 @@ namespace xo { color_encoding encoding, std::uint32_t color, std::string_view pretty) - : style_{style}, encoding_{encoding}, color_{color}, pretty_{pretty} {} + : style_{style}, color_spec_(encoding, color), pretty_{pretty} {} function_style style() const { return style_; } - color_encoding encoding() const { return encoding_; } - std::uint32_t color() const { return color_; } + color_encoding encoding() const { return color_spec_.encoding(); } + std::uint32_t color() const { return color_spec_.code(); } std::string_view const & pretty() const { return pretty_; } /* e.g. @@ -232,10 +232,8 @@ namespace xo { private: /* FS_Simple | FS_Pretty (= FS_Literal) | FS_Streamlined */ function_style style_; - /* CE_Ansi | CE_Xterm */ - color_encoding encoding_; - /* color, if non-zero */ - std::uint32_t color_; + /* terminal color (controls vt100 escape) */ + color_spec color_spec_; /* e.g. __PRETTY_FUNCTION__ */ std::string_view pretty_; }; /*function_name_impl*/ From 921da6aac62baf1944c8c6b3c758688080b32125 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:39:55 -0400 Subject: [PATCH 059/170] indentlog: refactor: color_spec arg to function_name_impl<> --- include/indentlog/function.hpp | 6 +++--- include/indentlog/log_state.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index 65ee5ae5..d79417e0 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -26,12 +26,12 @@ namespace xo { * 31 = red */ function_name_impl(function_style style, - color_encoding encoding, - std::uint32_t color, + color_spec spec, std::string_view pretty) - : style_{style}, color_spec_(encoding, color), pretty_{pretty} {} + : style_{style}, color_spec_{spec}, pretty_{pretty} {} function_style style() const { return style_; } + color_spec const & spec() const { return color_spec_; } color_encoding encoding() const { return color_spec_.encoding(); } std::uint32_t color() const { return color_spec_.code(); } std::string_view const & pretty() const { return pretty_; } diff --git a/include/indentlog/log_state.hpp b/include/indentlog/log_state.hpp index 814bf070..ad92c08e 100644 --- a/include/indentlog/log_state.hpp +++ b/include/indentlog/log_state.hpp @@ -233,7 +233,7 @@ namespace xo { this->ss_ << ' '; /* scope name - note no trailing newline; expect .preamble()/.postamble() caller to supply */ - this->ss_ << function_name(style, encoding, fn_color, name1) << name2; + this->ss_ << function_name(style, color_spec(encoding, fn_color), name1) << name2; } /*entryexit_aux*/ template From 92c74b90a00d6a5b1d5ac53ded7d8ec03d1933c3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:42:18 -0400 Subject: [PATCH 060/170] indentlog: refactor: more function_name_impl<> use of color_spec --- include/indentlog/function.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index d79417e0..1de2301f 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -26,14 +26,14 @@ namespace xo { * 31 = red */ function_name_impl(function_style style, - color_spec spec, + color_spec const & spec, std::string_view pretty) : style_{style}, color_spec_{spec}, pretty_{pretty} {} function_style style() const { return style_; } - color_spec const & spec() const { return color_spec_; } - color_encoding encoding() const { return color_spec_.encoding(); } - std::uint32_t color() const { return color_spec_.code(); } + color_spec const & colorspec() const { return color_spec_; } + //color_encoding encoding() const { return color_spec_.encoding(); } + //std::uint32_t color() const { return color_spec_.code(); } std::string_view const & pretty() const { return pretty_; } /* e.g. @@ -248,19 +248,19 @@ namespace xo { switch(fn.style()) { case FS_Literal: - os << with_color(color_spec(fn.encoding(), fn.color()), fn.pretty()); + os << with_color(fn.colorspec(), fn.pretty()); break; case FS_Pretty: - os << "[" << with_color(color_spec(fn.encoding(), fn.color()), fn.pretty()) << "]"; + os << "[" << with_color(fn.colorspec(), fn.pretty()) << "]"; break; case FS_Simple: - os << color_on(color_spec(fn.encoding(), fn.color())); + os << color_on(fn.colorspec()); function_name::print_simple(os, fn.pretty()); os << color_off(); break; case FS_Streamlined: /* omit namespace qualifiers and template arguments */ - os << color_on(color_spec(fn.encoding(), fn.color())); + os << color_on(fn.colorspec()); function_name::print_streamlined(os, fn.pretty()); os << color_off(); break; From a51355417a69dca172bec7e9a07136dd1c790294 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:45:57 -0400 Subject: [PATCH 061/170] indentlog: refactor: use color_spec in code_location_impl<> inserter --- include/indentlog/code_location.hpp | 13 +++++-------- include/indentlog/function.hpp | 2 -- include/indentlog/log_state.hpp | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/indentlog/code_location.hpp b/include/indentlog/code_location.hpp index e0460225..4e4bab21 100644 --- a/include/indentlog/code_location.hpp +++ b/include/indentlog/code_location.hpp @@ -19,13 +19,12 @@ namespace xo { public: code_location_impl(std::string_view file, std::uint32_t line, - color_encoding encoding = CE_Ansi, - std::uint32_t color = 31 /*red*/) - : file_{file}, line_{line}, encoding_{encoding}, color_{color} {} + color_spec colorspec) + : file_{file}, line_{line}, color_spec_{colorspec} {} void print_code_location(std::ostream & os) const { os << "[" - << with_color(color_spec(encoding_, color_), basename(file_)) + << with_color(color_spec_, basename(file_)) << ":" << line_ << "]"; @@ -36,10 +35,8 @@ namespace xo { std::string_view file_; /* __LINE__ */ std::uint32_t line_ = 0; - /* color encoding for file,line */ - color_encoding encoding_ = CE_Ansi; - /* color for file,line */ - std::uint32_t color_ = 0; + /* color encoding for [file:line] */ + color_spec color_spec_; }; /*code_location_impl*/ using code_location = code_location_impl; diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index 1de2301f..bfb107e8 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -32,8 +32,6 @@ namespace xo { function_style style() const { return style_; } color_spec const & colorspec() const { return color_spec_; } - //color_encoding encoding() const { return color_spec_.encoding(); } - //std::uint32_t color() const { return color_spec_.code(); } std::string_view const & pretty() const { return pretty_; } /* e.g. diff --git a/include/indentlog/log_state.hpp b/include/indentlog/log_state.hpp index ad92c08e..e99ef44a 100644 --- a/include/indentlog/log_state.hpp +++ b/include/indentlog/log_state.hpp @@ -348,7 +348,7 @@ namespace xo { std::stringstream ss; ss << code_location(this->file_, this->line_, - log_config::encoding, log_config::code_location_color); + color_spec(log_config::encoding, log_config::code_location_color)); std::string ss_str = std::move(ss.str()); /*c++20*/ sbuf2->sputn(ss_str.c_str(), ss_str.size()); From 62d2ac27663552fce615445bb3e7648dd6c3db83 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:49:45 -0400 Subject: [PATCH 062/170] indentlog: refactor: log_config.code_location_color uses color_spec --- example/ex3/ex3.cpp | 2 +- include/indentlog/log_config.hpp | 6 +++--- include/indentlog/log_state.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 281a6e33..cc77ca6e 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -34,7 +34,7 @@ main(int argc, char ** argv) { log_config::encoding = CE_Xterm; log_config::function_entry_color = 69; log_config::function_exit_color = 70; - log_config::code_location_color = 166; + log_config::code_location_color = color_spec::xterm(166); int n = 3; diff --git a/include/indentlog/log_config.hpp b/include/indentlog/log_config.hpp index 76ecf63f..4f48b0f6 100644 --- a/include/indentlog/log_config.hpp +++ b/include/indentlog/log_config.hpp @@ -41,7 +41,7 @@ namespace xo { /* when .location_enabled, write [file:line] starting this many chars from left margin */ static std::uint32_t location_tab; /* color to use for code location */ - static std::uint32_t code_location_color; + static color_spec code_location_color; }; /*log_config_impl*/ template @@ -101,8 +101,8 @@ namespace xo { log_config_impl::location_tab = 80; template - std::uint32_t - log_config_impl::code_location_color = 31; + color_spec + log_config_impl::code_location_color = color_spec::red(); using log_config = log_config_impl; } /*namespace xo*/ diff --git a/include/indentlog/log_state.hpp b/include/indentlog/log_state.hpp index e99ef44a..834aa119 100644 --- a/include/indentlog/log_state.hpp +++ b/include/indentlog/log_state.hpp @@ -348,7 +348,7 @@ namespace xo { std::stringstream ss; ss << code_location(this->file_, this->line_, - color_spec(log_config::encoding, log_config::code_location_color)); + log_config::code_location_color); std::string ss_str = std::move(ss.str()); /*c++20*/ sbuf2->sputn(ss_str.c_str(), ss_str.size()); From 9a12eba62f79d8636deb94e1facac8b86f5fb2b5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:51:36 -0400 Subject: [PATCH 063/170] indentlog: refactor: log_config.nesting_level_color color_spec --- include/indentlog/log_config.hpp | 6 +++--- include/indentlog/log_state.hpp | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/indentlog/log_config.hpp b/include/indentlog/log_config.hpp index 4f48b0f6..d3e8c91d 100644 --- a/include/indentlog/log_config.hpp +++ b/include/indentlog/log_config.hpp @@ -26,7 +26,7 @@ namespace xo { /* if true enable explicit nesting level display [nnn] */ static bool nesting_level_enabled; /* color to use for explicit nesting level */ - static std::uint32_t nesting_level_color; + static color_spec nesting_level_color; /* display style for function names. FS_Simple|FS_Pretty|FS_Streamlined */ static function_style style; /* color encoding */ @@ -73,8 +73,8 @@ namespace xo { log_config_impl::nesting_level_enabled = true; template - std::uint32_t - log_config_impl::nesting_level_color = 195; + color_spec + log_config_impl::nesting_level_color = color_spec::xterm(195); template function_style diff --git a/include/indentlog/log_state.hpp b/include/indentlog/log_state.hpp index 834aa119..6895fb25 100644 --- a/include/indentlog/log_state.hpp +++ b/include/indentlog/log_state.hpp @@ -223,8 +223,7 @@ namespace xo { */ this->ss_ << "(" - << with_color(color_spec(log_config::encoding, - log_config::nesting_level_color), + << with_color(log_config::nesting_level_color, this->nesting_level_) << ")"; } From 0c9eb6e2dad7a7ff8b9fc8b295569e2cf07d2634 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:56:21 -0400 Subject: [PATCH 064/170] indentlog: refactor: log_config function_name uses color_spec --- example/ex3/ex3.cpp | 4 ++-- include/indentlog/color.hpp | 20 -------------------- include/indentlog/log_config.hpp | 12 ++++++------ include/indentlog/log_state.hpp | 6 ++---- 4 files changed, 10 insertions(+), 32 deletions(-) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index cc77ca6e..69ad095d 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -32,8 +32,8 @@ main(int argc, char ** argv) { log_config::max_indent_width = 30; log_config::location_tab = 80; log_config::encoding = CE_Xterm; - log_config::function_entry_color = 69; - log_config::function_exit_color = 70; + log_config::function_entry_color = color_spec::xterm(69); + log_config::function_exit_color = color_spec::xterm(70); log_config::code_location_color = color_spec::xterm(166); int n = 3; diff --git a/include/indentlog/color.hpp b/include/indentlog/color.hpp index 7e600fa4..6d0ee749 100644 --- a/include/indentlog/color.hpp +++ b/include/indentlog/color.hpp @@ -143,31 +143,11 @@ namespace xo { Contents contents_; }; /*color_impl*/ - template - color_impl with_ansi_color(std::uint32_t color, Contents && contents) { - return color_impl(CF_All, color_spec::ansi(color), std::forward(contents)); - } /*with_ansi_color*/ - - template - color_impl with_xterm_color(std::uint32_t color, Contents && contents) { - return color_impl(CF_All, color_spec::xterm(color), std::forward(contents)); - } /*with_ansi_color*/ - template color_impl with_color(color_spec spec, Contents && contents) { return color_impl(CF_All, spec, std::forward(contents)); } /*with_color*/ - inline color_impl - color_on_ansi(std::uint32_t color) { - return color_impl(CF_ColorOn, color_spec::ansi(color), 0); - } /*color_on_ansi*/ - - inline color_impl - color_on_xterm(std::uint32_t color) { - return color_impl(CF_ColorOn, color_spec::xterm(color), 0); - } /*color_on_xterm*/ - inline color_impl color_on(color_spec spec) { return color_impl(CF_ColorOn, spec, 0); diff --git a/include/indentlog/log_config.hpp b/include/indentlog/log_config.hpp index d3e8c91d..b239aa60 100644 --- a/include/indentlog/log_config.hpp +++ b/include/indentlog/log_config.hpp @@ -34,8 +34,8 @@ namespace xo { /* color to use for function name, on entry/exit (xo::scope creation/destruction) * (ansi color codes, see Select Graphics Rendition subset) */ - static std::uint32_t function_entry_color; - static std::uint32_t function_exit_color; + static color_spec function_entry_color; + static color_spec function_exit_color; /* if true, append [file:line] to output */ static bool location_enabled; /* when .location_enabled, write [file:line] starting this many chars from left margin */ @@ -85,12 +85,12 @@ namespace xo { log_config_impl::encoding = CE_Ansi; template - std::uint32_t - log_config_impl::function_entry_color = 34; + color_spec + log_config_impl::function_entry_color = color_spec::ansi(34); template - std::uint32_t - log_config_impl::function_exit_color = 32; + color_spec + log_config_impl::function_exit_color = color_spec::ansi(32); template bool diff --git a/include/indentlog/log_state.hpp b/include/indentlog/log_state.hpp index 6895fb25..c1450779 100644 --- a/include/indentlog/log_state.hpp +++ b/include/indentlog/log_state.hpp @@ -194,9 +194,7 @@ namespace xo { this->indent(' '); char ee_label = '\0'; - std::uint32_t fn_color = 0; - - color_encoding encoding = log_config::encoding; + color_spec fn_color; /* mnemonic for scope entry/exit */ switch(entryexit) { @@ -232,7 +230,7 @@ namespace xo { this->ss_ << ' '; /* scope name - note no trailing newline; expect .preamble()/.postamble() caller to supply */ - this->ss_ << function_name(style, color_spec(encoding, fn_color), name1) << name2; + this->ss_ << function_name(style, fn_color, name1) << name2; } /*entryexit_aux*/ template From e674fe65b13f7f907e15beed8e432a6ce54aca91 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 12:57:10 -0400 Subject: [PATCH 065/170] indentlog: refactor: retire log_config.encoding --- example/ex3/ex3.cpp | 1 - include/indentlog/log_config.hpp | 6 ------ 2 files changed, 7 deletions(-) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 69ad095d..ab343dd4 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -31,7 +31,6 @@ main(int argc, char ** argv) { log_config::indent_width = 4; log_config::max_indent_width = 30; log_config::location_tab = 80; - log_config::encoding = CE_Xterm; log_config::function_entry_color = color_spec::xterm(69); log_config::function_exit_color = color_spec::xterm(70); log_config::code_location_color = color_spec::xterm(166); diff --git a/include/indentlog/log_config.hpp b/include/indentlog/log_config.hpp index b239aa60..ff63ade1 100644 --- a/include/indentlog/log_config.hpp +++ b/include/indentlog/log_config.hpp @@ -29,8 +29,6 @@ namespace xo { static color_spec nesting_level_color; /* display style for function names. FS_Simple|FS_Pretty|FS_Streamlined */ static function_style style; - /* color encoding */ - static color_encoding encoding; /* color to use for function name, on entry/exit (xo::scope creation/destruction) * (ansi color codes, see Select Graphics Rendition subset) */ @@ -80,10 +78,6 @@ namespace xo { function_style log_config_impl::style = FS_Streamlined; - template - color_encoding - log_config_impl::encoding = CE_Ansi; - template color_spec log_config_impl::function_entry_color = color_spec::ansi(34); From 30753c76af479e3a5aaeb7719756e5fb194c880c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 13:01:44 -0400 Subject: [PATCH 066/170] indentlog: refactor: color_encoding -> strongly-typed --- include/indentlog/color.hpp | 26 +++++++++++++------------- include/indentlog/log_level.hpp | 2 +- include/indentlog/tag_config.hpp | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/indentlog/color.hpp b/include/indentlog/color.hpp index 6d0ee749..32661d9b 100644 --- a/include/indentlog/color.hpp +++ b/include/indentlog/color.hpp @@ -7,10 +7,10 @@ #include namespace xo { - enum color_encoding { - CE_None, - CE_Ansi, - CE_Xterm, + enum class color_encoding : std::uint8_t { + none, + ansi, + xterm, }; /* specify a color (consistent with ANSI escape sequences - the Select Graphics Rendition subset @@ -32,8 +32,8 @@ namespace xo { : encoding_{encoding}, code_{code} {} static color_spec none() { return color_spec(); } - static color_spec ansi(std::uint32_t code) { return color_spec(CE_Ansi, code); } - static color_spec xterm(std::uint32_t code) { return color_spec(CE_Xterm, code); } + static color_spec ansi(std::uint32_t code) { return color_spec(color_encoding::ansi, code); } + static color_spec xterm(std::uint32_t code) { return color_spec(color_encoding::xterm, code); } static color_spec rgb(std::uint8_t red, std::uint8_t green, std::uint8_t blue) { return none(); //return color_spec(CE_Rgb, (red << 16 | green << 8 | blue)); @@ -62,12 +62,12 @@ namespace xo { void print_fg_color_on (std::ostream & os) const { switch (encoding_) { - case CE_None: + case color_encoding::none: break; - case CE_Ansi: + case color_encoding::ansi: os << "\033[31;" << code_ << "m"; break; - case CE_Xterm: + case color_encoding::xterm: os << "\033[38;5;" << code_ << "m"; break; } @@ -76,10 +76,10 @@ namespace xo { /* escape to reverse effect of .print_on() */ void print_fg_color_off (std::ostream & os) const { switch (encoding_) { - case CE_None: + case color_encoding::none: break; - case CE_Ansi: - case CE_Xterm: + case color_encoding::ansi: + case color_encoding::xterm: os << "\033[0m"; break; } @@ -87,7 +87,7 @@ namespace xo { private: /* none | ansi | xterm | rgb */ - color_encoding encoding_ = CE_None; + color_encoding encoding_ = color_encoding::none; /* ansi : 30..37, 90..97 * xterm : 0..255 * see [[https://i.stack.imgur.com/KTSQa.png]] diff --git a/include/indentlog/log_level.hpp b/include/indentlog/log_level.hpp index 55c4f2a4..8b470891 100644 --- a/include/indentlog/log_level.hpp +++ b/include/indentlog/log_level.hpp @@ -3,7 +3,7 @@ #include namespace xo { - enum class log_level : std::uint32_t { + enum class log_level : std::uint8_t { /* control log message severity * silent > always > severe > error > warning > info > chatty > never * diff --git a/include/indentlog/tag_config.hpp b/include/indentlog/tag_config.hpp index d4a67cb7..8b9643e6 100644 --- a/include/indentlog/tag_config.hpp +++ b/include/indentlog/tag_config.hpp @@ -22,7 +22,7 @@ namespace xo { template color_encoding - tag_config_impl::encoding = CE_Xterm; + tag_config_impl::encoding = color_encoding::xterm; template std::uint32_t From 346eef69a42cdbc17cf9c991a230ef64f1db9d8a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 13:06:28 -0400 Subject: [PATCH 067/170] indentlog: refactor: color_spec -> color_spec_type --- example/ex3/ex3.cpp | 6 +-- include/indentlog/code_location.hpp | 4 +- include/indentlog/color.hpp | 62 ++++++++++++++--------------- include/indentlog/function.hpp | 6 +-- include/indentlog/log_config.hpp | 24 +++++------ include/indentlog/log_state.hpp | 2 +- include/indentlog/tag.hpp | 2 +- 7 files changed, 53 insertions(+), 53 deletions(-) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index ab343dd4..cc592a5b 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -31,9 +31,9 @@ main(int argc, char ** argv) { log_config::indent_width = 4; log_config::max_indent_width = 30; log_config::location_tab = 80; - log_config::function_entry_color = color_spec::xterm(69); - log_config::function_exit_color = color_spec::xterm(70); - log_config::code_location_color = color_spec::xterm(166); + log_config::function_entry_color = color_spec_type::xterm(69); + log_config::function_exit_color = color_spec_type::xterm(70); + log_config::code_location_color = color_spec_type::xterm(166); int n = 3; diff --git a/include/indentlog/code_location.hpp b/include/indentlog/code_location.hpp index 4e4bab21..cd6c9308 100644 --- a/include/indentlog/code_location.hpp +++ b/include/indentlog/code_location.hpp @@ -19,7 +19,7 @@ namespace xo { public: code_location_impl(std::string_view file, std::uint32_t line, - color_spec colorspec) + color_spec_type colorspec) : file_{file}, line_{line}, color_spec_{colorspec} {} void print_code_location(std::ostream & os) const { @@ -36,7 +36,7 @@ namespace xo { /* __LINE__ */ std::uint32_t line_ = 0; /* color encoding for [file:line] */ - color_spec color_spec_; + color_spec_type color_spec_; }; /*code_location_impl*/ using code_location = code_location_impl; diff --git a/include/indentlog/color.hpp b/include/indentlog/color.hpp index 32661d9b..52548b5a 100644 --- a/include/indentlog/color.hpp +++ b/include/indentlog/color.hpp @@ -25,37 +25,37 @@ namespace xo { * | rgb | \033[38;2 | \033[38;2;10;20;30m | 24-bit colors | 3x 0..255 | * */ - class color_spec { + class color_spec_type { public: - color_spec() = default; - color_spec(color_encoding encoding, std::uint32_t code) + color_spec_type() = default; + color_spec_type(color_encoding encoding, std::uint32_t code) : encoding_{encoding}, code_{code} {} - static color_spec none() { return color_spec(); } - static color_spec ansi(std::uint32_t code) { return color_spec(color_encoding::ansi, code); } - static color_spec xterm(std::uint32_t code) { return color_spec(color_encoding::xterm, code); } - static color_spec rgb(std::uint8_t red, std::uint8_t green, std::uint8_t blue) { + static color_spec_type none() { return color_spec_type(); } + static color_spec_type ansi(std::uint32_t code) { return color_spec_type(color_encoding::ansi, code); } + static color_spec_type xterm(std::uint32_t code) { return color_spec_type(color_encoding::xterm, code); } + static color_spec_type rgb(std::uint8_t red, std::uint8_t green, std::uint8_t blue) { return none(); //return color_spec(CE_Rgb, (red << 16 | green << 8 | blue)); } /* 4-bit foreground colors */ - static color_spec black () { return ansi(30); } - static color_spec red () { return ansi(31); } - static color_spec green () { return ansi(32); } - static color_spec yellow () { return ansi(33); } - static color_spec blue () { return ansi(34); } - static color_spec magenta () { return ansi(35); } - static color_spec cyan () { return ansi(36); } - static color_spec white () { return ansi(37); } - static color_spec bright_black () { return ansi(90); } - static color_spec bright_red () { return ansi(91); } - static color_spec bright_green () { return ansi(92); } - static color_spec bright_yellow () { return ansi(99); } - static color_spec bright_blue () { return ansi(94); } - static color_spec bright_magenta () { return ansi(95); } - static color_spec bright_cyan () { return ansi(96); } - static color_spec bright_white () { return ansi(97); } + static color_spec_type black () { return ansi(30); } + static color_spec_type red () { return ansi(31); } + static color_spec_type green () { return ansi(32); } + static color_spec_type yellow () { return ansi(33); } + static color_spec_type blue () { return ansi(34); } + static color_spec_type magenta () { return ansi(35); } + static color_spec_type cyan () { return ansi(36); } + static color_spec_type white () { return ansi(37); } + static color_spec_type bright_black () { return ansi(90); } + static color_spec_type bright_red () { return ansi(91); } + static color_spec_type bright_green () { return ansi(92); } + static color_spec_type bright_yellow () { return ansi(99); } + static color_spec_type bright_blue () { return ansi(94); } + static color_spec_type bright_magenta () { return ansi(95); } + static color_spec_type bright_cyan () { return ansi(96); } + static color_spec_type bright_white () { return ansi(97); } color_encoding encoding() const { return encoding_; } std::uint32_t code() const { return code_; } @@ -98,7 +98,7 @@ namespace xo { * rgb : r={hi 8 bits}, g={mid 8 bits}, b={lo 8 bits} */ std::uint32_t code_ = 0; - }; /*color_spec*/ + }; /*color_spec_type*/ enum color_flags { CF_None = 0x0, @@ -112,10 +112,10 @@ namespace xo { template class color_impl { public: - color_impl(color_flags flags, color_spec spec, Contents && contents) + color_impl(color_flags flags, color_spec_type spec, Contents && contents) : flags_{flags}, spec_{spec}, contents_{std::forward(contents)} {} - color_spec const & spec() const { return spec_; } + color_spec_type const & spec() const { return spec_; } std::uint32_t color() const { return spec_.code(); } Contents const & contents() const { return contents_; } @@ -138,25 +138,25 @@ namespace xo { */ color_flags flags_ = CF_None; - color_spec spec_; + color_spec_type spec_; Contents contents_; }; /*color_impl*/ template - color_impl with_color(color_spec spec, Contents && contents) { + color_impl with_color(color_spec_type spec, Contents && contents) { return color_impl(CF_All, spec, std::forward(contents)); } /*with_color*/ inline color_impl - color_on(color_spec spec) { + color_on(color_spec_type spec) { return color_impl(CF_ColorOn, spec, 0); } /*color_on*/ inline color_impl color_off() { - /* any spec other than color_spec::none() works here */ - return color_impl(CF_ColorOff, color_spec::white(), 0); + /* any spec other than color_spec_type::none() works here */ + return color_impl(CF_ColorOff, color_spec_type::white(), 0); } /*color_off*/ template diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index bfb107e8..d68c75b9 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -26,12 +26,12 @@ namespace xo { * 31 = red */ function_name_impl(function_style style, - color_spec const & spec, + color_spec_type const & spec, std::string_view pretty) : style_{style}, color_spec_{spec}, pretty_{pretty} {} function_style style() const { return style_; } - color_spec const & colorspec() const { return color_spec_; } + color_spec_type const & colorspec() const { return color_spec_; } std::string_view const & pretty() const { return pretty_; } /* e.g. @@ -231,7 +231,7 @@ namespace xo { /* FS_Simple | FS_Pretty (= FS_Literal) | FS_Streamlined */ function_style style_; /* terminal color (controls vt100 escape) */ - color_spec color_spec_; + color_spec_type color_spec_; /* e.g. __PRETTY_FUNCTION__ */ std::string_view pretty_; }; /*function_name_impl*/ diff --git a/include/indentlog/log_config.hpp b/include/indentlog/log_config.hpp index ff63ade1..22371bb7 100644 --- a/include/indentlog/log_config.hpp +++ b/include/indentlog/log_config.hpp @@ -26,20 +26,20 @@ namespace xo { /* if true enable explicit nesting level display [nnn] */ static bool nesting_level_enabled; /* color to use for explicit nesting level */ - static color_spec nesting_level_color; + static color_spec_type nesting_level_color; /* display style for function names. FS_Simple|FS_Pretty|FS_Streamlined */ static function_style style; /* color to use for function name, on entry/exit (xo::scope creation/destruction) * (ansi color codes, see Select Graphics Rendition subset) */ - static color_spec function_entry_color; - static color_spec function_exit_color; + static color_spec_type function_entry_color; + static color_spec_type function_exit_color; /* if true, append [file:line] to output */ static bool location_enabled; /* when .location_enabled, write [file:line] starting this many chars from left margin */ static std::uint32_t location_tab; /* color to use for code location */ - static color_spec code_location_color; + static color_spec_type code_location_color; }; /*log_config_impl*/ template @@ -71,20 +71,20 @@ namespace xo { log_config_impl::nesting_level_enabled = true; template - color_spec - log_config_impl::nesting_level_color = color_spec::xterm(195); + color_spec_type + log_config_impl::nesting_level_color = color_spec_type::xterm(195); template function_style log_config_impl::style = FS_Streamlined; template - color_spec - log_config_impl::function_entry_color = color_spec::ansi(34); + color_spec_type + log_config_impl::function_entry_color = color_spec_type::ansi(34); template - color_spec - log_config_impl::function_exit_color = color_spec::ansi(32); + color_spec_type + log_config_impl::function_exit_color = color_spec_type::ansi(32); template bool @@ -95,8 +95,8 @@ namespace xo { log_config_impl::location_tab = 80; template - color_spec - log_config_impl::code_location_color = color_spec::red(); + color_spec_type + log_config_impl::code_location_color = color_spec_type::red(); using log_config = log_config_impl; } /*namespace xo*/ diff --git a/include/indentlog/log_state.hpp b/include/indentlog/log_state.hpp index c1450779..66f1e15d 100644 --- a/include/indentlog/log_state.hpp +++ b/include/indentlog/log_state.hpp @@ -194,7 +194,7 @@ namespace xo { this->indent(' '); char ee_label = '\0'; - color_spec fn_color; + color_spec_type fn_color; /* mnemonic for scope entry/exit */ switch(entryexit) { diff --git a/include/indentlog/tag.hpp b/include/indentlog/tag.hpp index a6825bee..7b22e67b 100644 --- a/include/indentlog/tag.hpp +++ b/include/indentlog/tag.hpp @@ -96,7 +96,7 @@ namespace xo { if(PrefixSpace) s << " "; - s << with_color(color_spec(tag_config::encoding, tag_config::tag_color), concat((char const *)":", tag.name())) + s << with_color(color_spec_type(tag_config::encoding, tag_config::tag_color), concat((char const *)":", tag.name())) << " " << unq(tag.value()); return s; From 6a06c769c8324a5f106ef1147d51bd470ab0454a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 13:09:15 -0400 Subject: [PATCH 068/170] indentlog: refactor: tag_config.tag_color uses color_spec --- include/indentlog/tag.hpp | 2 +- include/indentlog/tag_config.hpp | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/include/indentlog/tag.hpp b/include/indentlog/tag.hpp index 7b22e67b..6c7eafbb 100644 --- a/include/indentlog/tag.hpp +++ b/include/indentlog/tag.hpp @@ -96,7 +96,7 @@ namespace xo { if(PrefixSpace) s << " "; - s << with_color(color_spec_type(tag_config::encoding, tag_config::tag_color), concat((char const *)":", tag.name())) + s << with_color(tag_config::tag_color, concat((char const *)":", tag.name())) << " " << unq(tag.value()); return s; diff --git a/include/indentlog/tag_config.hpp b/include/indentlog/tag_config.hpp index 8b9643e6..f86b2c8f 100644 --- a/include/indentlog/tag_config.hpp +++ b/include/indentlog/tag_config.hpp @@ -9,24 +9,18 @@ namespace xo { /* Tag here b/c we want header-only library */ template struct tag_config_impl { - /* color encoding */ - static color_encoding encoding; /* color to use for tags * os << tag("foo", foovalue) * to produces output like * :foo foovalue * with :foo using .tag_color */ - static std::uint32_t tag_color; + static color_spec_type tag_color; }; /*tag_config_impl*/ template - color_encoding - tag_config_impl::encoding = color_encoding::xterm; - - template - std::uint32_t - tag_config_impl::tag_color = 245; + color_spec_type + tag_config_impl::tag_color = color_spec_type::xterm(245); using tag_config = tag_config_impl; } /*namespace xo*/ From fbe0de6cba9f71d73f2e8a57dd01ac9ee9c7cad3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 13:12:19 -0400 Subject: [PATCH 069/170] indentlog: + support rgb color --- include/indentlog/color.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/indentlog/color.hpp b/include/indentlog/color.hpp index 52548b5a..688a152a 100644 --- a/include/indentlog/color.hpp +++ b/include/indentlog/color.hpp @@ -11,6 +11,7 @@ namespace xo { none, ansi, xterm, + rgb }; /* specify a color (consistent with ANSI escape sequences - the Select Graphics Rendition subset @@ -35,8 +36,7 @@ namespace xo { static color_spec_type ansi(std::uint32_t code) { return color_spec_type(color_encoding::ansi, code); } static color_spec_type xterm(std::uint32_t code) { return color_spec_type(color_encoding::xterm, code); } static color_spec_type rgb(std::uint8_t red, std::uint8_t green, std::uint8_t blue) { - return none(); - //return color_spec(CE_Rgb, (red << 16 | green << 8 | blue)); + return color_spec_type(color_encoding::rgb, (red << 16 | green << 8 | blue)); } /* 4-bit foreground colors */ @@ -70,6 +70,11 @@ namespace xo { case color_encoding::xterm: os << "\033[38;5;" << code_ << "m"; break; + case color_encoding::rgb: + os << "\033[38;2;" + << (0xff & (code_ >> 16)) << ";" + << (0xff & (code_ >> 8)) << ";" + << (0xff & (code_ >> 0)) << "m"; } } /*print_fg_color_on*/ @@ -80,6 +85,7 @@ namespace xo { break; case color_encoding::ansi: case color_encoding::xterm: + case color_encoding::rgb: os << "\033[0m"; break; } From 21c1a8e1aec94011c46f5c80257723c53f29546c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 13:18:07 -0400 Subject: [PATCH 070/170] indentlog: refactor: strongly-typed coloring_control_flags --- include/indentlog/color.hpp | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/include/indentlog/color.hpp b/include/indentlog/color.hpp index 688a152a..49eb0bcf 100644 --- a/include/indentlog/color.hpp +++ b/include/indentlog/color.hpp @@ -106,19 +106,26 @@ namespace xo { std::uint32_t code_ = 0; }; /*color_spec_type*/ - enum color_flags { - CF_None = 0x0, - CF_ColorOn = 0x01, - CF_Contents = 0x02, - CF_ColorOff = 0x04, - CF_All = 0x07 + enum class coloring_control_flags : std::uint8_t { + none = 0x0, + color_on = 0x01, + contents = 0x02, + color_off = 0x04, + all = 0x07 }; + inline std::uint8_t operator& (coloring_control_flags x, coloring_control_flags y) { + return static_cast(x) & static_cast(y); + } + inline std::uint8_t operator| (coloring_control_flags x, coloring_control_flags y) { + return static_cast(x) | static_cast(y); + } + /* stream-insertable color control */ template class color_impl { public: - color_impl(color_flags flags, color_spec_type spec, Contents && contents) + color_impl(coloring_control_flags flags, color_spec_type spec, Contents && contents) : flags_{flags}, spec_{spec}, contents_{std::forward(contents)} {} color_spec_type const & spec() const { return spec_; } @@ -126,13 +133,13 @@ namespace xo { Contents const & contents() const { return contents_; } void print(std::ostream & os) const { - if (flags_ & CF_ColorOn) + if (flags_ & coloring_control_flags::color_on) spec_.print_fg_color_on(os); - if (flags_ & CF_Contents) + if (flags_ & coloring_control_flags::contents) os << contents_; - if (flags_ & CF_ColorOff) + if (flags_ & coloring_control_flags::color_off) spec_.print_fg_color_off(os); } /*print*/ @@ -140,9 +147,9 @@ namespace xo { /* controls independently what to print * \033[38;5;117m hello, world! \033[0m * <------------> <-----------> <-----> - * CF_ColorOn CF_Contents CF_ColorOff + * color_on contents color_off */ - color_flags flags_ = CF_None; + coloring_control_flags flags_ = coloring_control_flags::none; color_spec_type spec_; @@ -151,18 +158,18 @@ namespace xo { template color_impl with_color(color_spec_type spec, Contents && contents) { - return color_impl(CF_All, spec, std::forward(contents)); + return color_impl(coloring_control_flags::all, spec, std::forward(contents)); } /*with_color*/ inline color_impl color_on(color_spec_type spec) { - return color_impl(CF_ColorOn, spec, 0); + return color_impl(coloring_control_flags::color_on, spec, 0); } /*color_on*/ inline color_impl color_off() { /* any spec other than color_spec_type::none() works here */ - return color_impl(CF_ColorOff, color_spec_type::white(), 0); + return color_impl(coloring_control_flags::color_off, color_spec_type::white(), 0); } /*color_off*/ template From 5c60277610beda7d818df2761d597ead1b914789 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 13:24:41 -0400 Subject: [PATCH 071/170] indentlog: strongly-typed fucntion_style enum --- example/ex3/ex3.cpp | 2 +- example/ex4/ex4.cpp | 9 ++++--- include/indentlog/function.hpp | 41 +++++++++++++++++++------------- include/indentlog/log_config.hpp | 2 +- include/indentlog/scope.hpp | 4 ++-- 5 files changed, 32 insertions(+), 26 deletions(-) diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index cc592a5b..2a09d2d7 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -27,7 +27,7 @@ main(int argc, char ** argv) { log_config::min_log_level = log_level::info; log_config::time_enabled = true; log_config::time_local_flag = true; - log_config::style = FS_Streamlined; + log_config::style = function_style::streamlined; log_config::indent_width = 4; log_config::max_indent_width = 30; log_config::location_tab = 80; diff --git a/example/ex4/ex4.cpp b/example/ex4/ex4.cpp index 05ca39e0..d59e83c1 100644 --- a/example/ex4/ex4.cpp +++ b/example/ex4/ex4.cpp @@ -26,8 +26,7 @@ private: int main(int argc, char ** argv) { - //log_config::style = FS_Pretty; - log_config::style = FS_Streamlined; + log_config::style = function_style::streamlined; log_config::min_log_level = log_level::info; scope log(XO_ENTER0(info)); @@ -37,15 +36,15 @@ main(int argc, char ** argv) { double x = 3.0; double r = 0.0; - log_config::style = FS_Pretty; + log_config::style = function_style::pretty; r = quadratic(x); - log_config::style = FS_Streamlined; + log_config::style = function_style::streamlined; r = quadratic(x); - log_config::style = FS_Simple; + log_config::style = function_style::simple; r = quadratic(x); } diff --git a/include/indentlog/function.hpp b/include/indentlog/function.hpp index d68c75b9..5bbfbd05 100644 --- a/include/indentlog/function.hpp +++ b/include/indentlog/function.hpp @@ -6,15 +6,22 @@ #include namespace xo { - enum function_style { - /* literal: print given name, no alterations */ - FS_Literal, - /* pretty: print name, surrounded by [] */ - FS_Pretty, - /* streamlined: remove extraneous detail, try to print something like class::method */ - FS_Streamlined, - /* simple: remove everything except function/method name */ - FS_Simple + enum class function_style : std::uint8_t { + /* literal: print supplied text, no alterations */ + literal, + /* pretty: print name, surrounded by [] + * [double Quadratic::operator()(double) const] + */ + pretty, + /* streamlined: remove extraneous detail, + * try to print something like class::method + * Quadratic::operator() + */ + streamlined, + /* simple: remove everything except function/method name + * operator() + */ + simple }; /* Tag to drive header-only expression */ @@ -245,23 +252,23 @@ namespace xo { /* set text color */ switch(fn.style()) { - case FS_Literal: + case function_style::literal: os << with_color(fn.colorspec(), fn.pretty()); break; - case FS_Pretty: + case function_style::pretty: os << "[" << with_color(fn.colorspec(), fn.pretty()) << "]"; break; - case FS_Simple: - os << color_on(fn.colorspec()); - function_name::print_simple(os, fn.pretty()); - os << color_off(); - break; - case FS_Streamlined: + case function_style::streamlined: /* omit namespace qualifiers and template arguments */ os << color_on(fn.colorspec()); function_name::print_streamlined(os, fn.pretty()); os << color_off(); break; + case function_style::simple: + os << color_on(fn.colorspec()); + function_name::print_simple(os, fn.pretty()); + os << color_off(); + break; } return os; diff --git a/include/indentlog/log_config.hpp b/include/indentlog/log_config.hpp index 22371bb7..1630b5c2 100644 --- a/include/indentlog/log_config.hpp +++ b/include/indentlog/log_config.hpp @@ -76,7 +76,7 @@ namespace xo { template function_style - log_config_impl::style = FS_Streamlined; + log_config_impl::style = function_style::streamlined; template color_spec_type diff --git a/include/indentlog/scope.hpp b/include/indentlog/scope.hpp index fac759c2..fd0da297 100644 --- a/include/indentlog/scope.hpp +++ b/include/indentlog/scope.hpp @@ -56,7 +56,7 @@ namespace xo { /* threshold level for logging -- write messages with severity >= this level */ log_level log_level_ = log_level::error; /* FS_Pretty | FS_Streamlined | FS_Simple */ - function_style style_ = FS_Pretty; + function_style style_ = function_style::pretty; std::string_view name1_ = "<.name1>"; std::string_view name2_ = "<.name2>"; /* __FILE__ */ @@ -168,7 +168,7 @@ namespace xo { /* send indented output to this streambuf (e.g. std::clog.rdbuf()) */ std::streambuf * dest_sbuf_ = std::clog.rdbuf(); /* style for displaying .name1 */ - function_style style_ = FS_Pretty; + function_style style_ = function_style::pretty; /* name of this scope (part 1) */ std::string_view name1_ = ""; /* name of this scope (part 2) */ From efe207a4deb0038b6791dc843bbc705c9b8cb6e0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 13:29:04 -0400 Subject: [PATCH 072/170] indentlog: refactor: move stream-inserters to print/ subdir --- include/indentlog/log_config.hpp | 4 ++-- include/indentlog/log_state.hpp | 8 ++++---- include/indentlog/{ => print}/array.hpp | 0 include/indentlog/{ => print}/code_location.hpp | 0 include/indentlog/{ => print}/color.hpp | 0 include/indentlog/{ => print}/concat.hpp | 0 include/indentlog/{ => print}/filename.hpp | 0 include/indentlog/{ => print}/fixed.hpp | 0 include/indentlog/{ => print}/function.hpp | 0 include/indentlog/{ => print}/pad.hpp | 0 include/indentlog/{ => print}/printer.hpp | 0 include/indentlog/{ => print}/quoted.hpp | 0 include/indentlog/{ => print}/quoted_char.hpp | 0 include/indentlog/{ => print}/tag.hpp | 0 include/indentlog/{ => print}/tag_config.hpp | 0 include/indentlog/{ => print}/time.hpp | 0 include/indentlog/{ => print}/tostr.hpp | 0 include/indentlog/{ => print}/vector.hpp | 0 include/indentlog/scope.hpp | 6 +++--- 19 files changed, 9 insertions(+), 9 deletions(-) rename include/indentlog/{ => print}/array.hpp (100%) rename include/indentlog/{ => print}/code_location.hpp (100%) rename include/indentlog/{ => print}/color.hpp (100%) rename include/indentlog/{ => print}/concat.hpp (100%) rename include/indentlog/{ => print}/filename.hpp (100%) rename include/indentlog/{ => print}/fixed.hpp (100%) rename include/indentlog/{ => print}/function.hpp (100%) rename include/indentlog/{ => print}/pad.hpp (100%) rename include/indentlog/{ => print}/printer.hpp (100%) rename include/indentlog/{ => print}/quoted.hpp (100%) rename include/indentlog/{ => print}/quoted_char.hpp (100%) rename include/indentlog/{ => print}/tag.hpp (100%) rename include/indentlog/{ => print}/tag_config.hpp (100%) rename include/indentlog/{ => print}/time.hpp (100%) rename include/indentlog/{ => print}/tostr.hpp (100%) rename include/indentlog/{ => print}/vector.hpp (100%) diff --git a/include/indentlog/log_config.hpp b/include/indentlog/log_config.hpp index 1630b5c2..9e2099cf 100644 --- a/include/indentlog/log_config.hpp +++ b/include/indentlog/log_config.hpp @@ -3,8 +3,8 @@ #pragma once #include "log_level.hpp" -#include "function.hpp" -#include "color.hpp" +#include "print/function.hpp" +#include "print/color.hpp" #include namespace xo { diff --git a/include/indentlog/log_state.hpp b/include/indentlog/log_state.hpp index 66f1e15d..42e23d1f 100644 --- a/include/indentlog/log_state.hpp +++ b/include/indentlog/log_state.hpp @@ -4,10 +4,10 @@ #include "log_config.hpp" #include "log_streambuf.hpp" -#include "pad.hpp" -#include "filename.hpp" -#include "code_location.hpp" -#include "time.hpp" +#include "print/pad.hpp" +#include "print/filename.hpp" +#include "print/code_location.hpp" +#include "print/time.hpp" #include #include #include // for std::unique_ptr diff --git a/include/indentlog/array.hpp b/include/indentlog/print/array.hpp similarity index 100% rename from include/indentlog/array.hpp rename to include/indentlog/print/array.hpp diff --git a/include/indentlog/code_location.hpp b/include/indentlog/print/code_location.hpp similarity index 100% rename from include/indentlog/code_location.hpp rename to include/indentlog/print/code_location.hpp diff --git a/include/indentlog/color.hpp b/include/indentlog/print/color.hpp similarity index 100% rename from include/indentlog/color.hpp rename to include/indentlog/print/color.hpp diff --git a/include/indentlog/concat.hpp b/include/indentlog/print/concat.hpp similarity index 100% rename from include/indentlog/concat.hpp rename to include/indentlog/print/concat.hpp diff --git a/include/indentlog/filename.hpp b/include/indentlog/print/filename.hpp similarity index 100% rename from include/indentlog/filename.hpp rename to include/indentlog/print/filename.hpp diff --git a/include/indentlog/fixed.hpp b/include/indentlog/print/fixed.hpp similarity index 100% rename from include/indentlog/fixed.hpp rename to include/indentlog/print/fixed.hpp diff --git a/include/indentlog/function.hpp b/include/indentlog/print/function.hpp similarity index 100% rename from include/indentlog/function.hpp rename to include/indentlog/print/function.hpp diff --git a/include/indentlog/pad.hpp b/include/indentlog/print/pad.hpp similarity index 100% rename from include/indentlog/pad.hpp rename to include/indentlog/print/pad.hpp diff --git a/include/indentlog/printer.hpp b/include/indentlog/print/printer.hpp similarity index 100% rename from include/indentlog/printer.hpp rename to include/indentlog/print/printer.hpp diff --git a/include/indentlog/quoted.hpp b/include/indentlog/print/quoted.hpp similarity index 100% rename from include/indentlog/quoted.hpp rename to include/indentlog/print/quoted.hpp diff --git a/include/indentlog/quoted_char.hpp b/include/indentlog/print/quoted_char.hpp similarity index 100% rename from include/indentlog/quoted_char.hpp rename to include/indentlog/print/quoted_char.hpp diff --git a/include/indentlog/tag.hpp b/include/indentlog/print/tag.hpp similarity index 100% rename from include/indentlog/tag.hpp rename to include/indentlog/print/tag.hpp diff --git a/include/indentlog/tag_config.hpp b/include/indentlog/print/tag_config.hpp similarity index 100% rename from include/indentlog/tag_config.hpp rename to include/indentlog/print/tag_config.hpp diff --git a/include/indentlog/time.hpp b/include/indentlog/print/time.hpp similarity index 100% rename from include/indentlog/time.hpp rename to include/indentlog/print/time.hpp diff --git a/include/indentlog/tostr.hpp b/include/indentlog/print/tostr.hpp similarity index 100% rename from include/indentlog/tostr.hpp rename to include/indentlog/print/tostr.hpp diff --git a/include/indentlog/vector.hpp b/include/indentlog/print/vector.hpp similarity index 100% rename from include/indentlog/vector.hpp rename to include/indentlog/print/vector.hpp diff --git a/include/indentlog/scope.hpp b/include/indentlog/scope.hpp index fd0da297..b86923c1 100644 --- a/include/indentlog/scope.hpp +++ b/include/indentlog/scope.hpp @@ -3,9 +3,9 @@ #pragma once #include "log_state.hpp" -#include "filename.hpp" -#include "tostr.hpp" -#include "tag.hpp" +#include "print/filename.hpp" +#include "print/tostr.hpp" +#include "print/tag.hpp" #include #include From 38101cce90ed38a7562af913689d1f9dd725b618 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 13:33:07 -0400 Subject: [PATCH 073/170] indentlog: ++ FILES --- FILES | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/FILES b/FILES index 68a84654..7838f779 100644 --- a/FILES +++ b/FILES @@ -1,23 +1,29 @@ directory layout -+- README.md markdown README, for github -+- img image files, used in docs ++- README.md markdown README, for github ++- img image files, used in docs | +- ex1.png | +- ex2.png | +- ex3.png | \- ex4.png -+- LICENSE software license -+- CMakeLists.txt toplevel cmake config ++- LICENSE software license ++- CMakeLists.txt toplevel cmake config +- cmake -| \- nestlog.cmake cmake support files -+- compile_commands.json symlink to record of compiler commands; for LSP support -+- include to install, copy contents of this directory to permanent location +| \- nestlog.cmake cmake support files ++- compile_commands.json symlink to record of compiler commands; for LSP support ++- include to install, copy contents of this directory to permanent location | \- indentlog -| +- scope.hpp -| ... +| +- scope.hpp logger api -- appl code will #include this +| +- log_config.hpp logger api -- control logger format, verbosity, colors etc. +| +- log_level.hpp encode logger verbosity +| +- log_state.hpp per-thread state tracking (e.g. recognize nesting) +| +- log_streambuf.hpp custom streambuf +| \- print +| +- tag.hpp stream inserters +| ... \- example - +- CMakeLists.txt cmake config + +- CMakeLists.txt cmake config +- ex1 - | +- CMakeLists.txt ex1 cmake config - | \- ex1.cpp example .cpp exercising indentlog + | +- CMakeLists.txt ex1 cmake config + | \- ex1.cpp example .cpp exercising indentlog ... From eaa5f3ada3e31f5e01bade9e66f1d277792f6196 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 16:15:41 -0400 Subject: [PATCH 074/170] refactor: + indentlog/timeutil/, for clarity --- include/indentlog/log_state.hpp | 4 +- include/indentlog/print/time.hpp | 300 ++---------------------- include/indentlog/scope.hpp | 2 +- include/indentlog/timeutil/timeutil.hpp | 287 +++++++++++++++++++++++ 4 files changed, 304 insertions(+), 289 deletions(-) create mode 100644 include/indentlog/timeutil/timeutil.hpp diff --git a/include/indentlog/log_state.hpp b/include/indentlog/log_state.hpp index 42e23d1f..d7bec9ae 100644 --- a/include/indentlog/log_state.hpp +++ b/include/indentlog/log_state.hpp @@ -37,7 +37,7 @@ namespace xo { std::ostream & ss() { return ss_; } void check_print_time(utc_nanos now_tm) { - using xo::time::time; + using xo::time::timeutil; using xo::time::utc_nanos; using xo::time::hms_msec; using xo::time::hms_usec; @@ -190,7 +190,7 @@ namespace xo { sbuf->reset_stream(); - this->check_print_time(xo::time::time::now()); + this->check_print_time(xo::time::timeutil::now()); this->indent(' '); char ee_label = '\0'; diff --git a/include/indentlog/print/time.hpp b/include/indentlog/print/time.hpp index 1d93dd26..275f43da 100644 --- a/include/indentlog/print/time.hpp +++ b/include/indentlog/print/time.hpp @@ -2,284 +2,11 @@ #pragma once -#include -#include -#ifdef NOT_YET -# include -#endif -#include -#include -#include +#include "indentlog/timeutil/timeutil.hpp" namespace xo { namespace time { - - using utc_nanos = std::chrono::time_point; - - using nanos = std::chrono::nanoseconds; - using microseconds = std::chrono::microseconds; - using milliseconds = std::chrono::milliseconds; - using seconds = std::chrono::seconds; - using hours = std::chrono::hours; - using days = std::chrono::days; - - struct time { - static utc_nanos now() { - return utc_nanos(std::chrono::system_clock::now()); - } - - static utc_nanos epoch() { - return utc_nanos(std::chrono::system_clock::from_time_t(0)); - } /*epoch*/ - - static utc_nanos ymd_hms(uint32_t ymd, uint32_t hms) { - /* e.g. ymd=20220610 -> n_yr=2022, n_mon=06, n_dy=10 */ - - uint32_t n_yr = ymd / 10000; - uint32_t n_mon = (ymd % 10000) / 100; - uint32_t n_dy = ymd % 100; - - uint32_t n_hr = hms / 10000; - uint32_t n_min = (hms % 10000) / 100; - uint32_t n_sec = hms % 100; - - struct tm t; - - t.tm_year = n_yr - 1900; /* 0 means 1900 */ - t.tm_mon = n_mon - 1; /* 0 means january */ - t.tm_mday = n_dy; - - t.tm_hour = n_hr; /* 24 hour clock */ - t.tm_min = n_min; - t.tm_sec = n_sec; - - /* time since epoch */ - time_t epoch_time = timegm(&t); - - return std::chrono::system_clock::from_time_t(epoch_time); - } /*ymd_hms*/ - - /* midnight UTC on date ymd. - * e.g. ymd_midnight(20220707) -> midnight UTC on 7jul22 - */ - static utc_nanos ymd_midnight(uint32_t ymd) { - return ymd_hms(ymd, 0); - } /*ymd_midnight*/ - - static utc_nanos ymd_hms_usec(uint32_t ymd, uint32_t hms, uint32_t usec) { - utc_nanos s = ymd_hms(ymd, hms); - - return s + microseconds(usec); - } /*ymd_hms_usec*/ - - /* .first: UTC midnight on same calendar day as t0 - * .second: elapsed time from .first to t0 (i.e. UTC time-of-day for t0) - */ - static std::pair utc_split_vs_midnight(utc_nanos t0) { - using xo::time::microseconds; - using xo::time::utc_nanos; - - /* use yyyymmdd.hh:mm:ss.nnnnnn */ - - time_t t0_time_t = (std::chrono::system_clock::to_time_t - (std::chrono::time_point_cast(t0))); - - /* convert to std::tm, - * only provides 1-second precision - */ - std::tm t0_tm; - ::gmtime_r(&t0_time_t, &t0_tm); - - /* midnight on the same calendar day as t0_tm */ - std::tm midnight_tm = t0_tm; - { - midnight_tm.tm_hour = 0; - midnight_tm.tm_min = 0; - midnight_tm.tm_sec = 0; - } - - /* convert to UTC epoch seconds */ - time_t midnight_time_t = ::timegm(&midnight_tm); - - utc_nanos t0_midnight = - (std::chrono::time_point_cast( - std::chrono::system_clock::from_time_t(midnight_time_t))); - - nanos t0_tdy = t0 - t0_midnight; - - return std::pair(t0_midnight, t0_tdy); - } /*utc_split_vs_midnight*/ - - /* .first: LOCAL midnight on same calendar day as t0 (but in UTC coords) - * .second: elapsed time from .first to t0 (i.e. LOCAL time-of-day for t0) - */ - static std::pair local_split_vs_midnight(utc_nanos t0) { - using xo::time::microseconds; - using xo::time::utc_nanos; - - /* use yyyymmdd.hh:mm:ss.nnnnnn */ - - time_t t0_time_t = (std::chrono::system_clock::to_time_t - (std::chrono::time_point_cast(t0))); - - /* convert to std::tm, - * only provides 1-second precision - */ - std::tm t0_tm; - ::localtime_r(&t0_time_t, &t0_tm); - - /* midnight on the same calendar day as t0_tm */ - std::tm midnight_tm = t0_tm; - { - midnight_tm.tm_hour = 0; - midnight_tm.tm_min = 0; - midnight_tm.tm_sec = 0; - } - - /* convert local midnight to UTC epoch seconds */ - time_t midnight_time_t = ::timelocal(&midnight_tm); - - utc_nanos t0_midnight = - (std::chrono::time_point_cast( - std::chrono::system_clock::from_time_t(midnight_time_t))); - - nanos t0_tdy = t0 - t0_midnight; - - return std::pair(t0_midnight, t0_tdy); - } /*local_split_vs_midnight*/ - - /* split utc_nanos into - * std::tm - * .tm_year - * .tm_mon (1-12) - * .tm_mday (1-31) - * .tm_hour (0-23) - * .tm_min (0-59) - * .tm_sec (0-59) - * .tm_wday (0=sunday .. 6=saturday) - * .tm_yday (0=1jan .. 365) - * .tm_isdst (daylight savings time flag) - * usec (0-999999) - */ - static std::pair split_tm(utc_nanos t0) { - using xo::time::microseconds; - using xo::time::utc_nanos; - - /* use yyyymmdd.hh:mm:ss.nnnnnn */ - - time_t t0_time_t = (std::chrono::system_clock::to_time_t - (std::chrono::time_point_cast(t0))); - - /* convert to std::tm, un UTC coords, - * only provides 1-second precision - */ - std::tm t0_tm; - ::gmtime_r(&t0_time_t, &t0_tm); - - /* midnight on the same calendar day as t0_tm */ - std::tm midnight_tm = t0_tm; - - midnight_tm.tm_isdst = 0; - midnight_tm.tm_hour = 0; - midnight_tm.tm_min = 0; - midnight_tm.tm_sec = 0; - - /* convert back to epoch seconds */ - time_t midnight_time_t = ::mktime(&midnight_tm); - - utc_nanos t0_midnight = - (std::chrono::time_point_cast( - std::chrono::system_clock::from_time_t(midnight_time_t))); - - uint32_t usec = - (std::chrono::duration_cast( - std::chrono::hh_mm_ss(t0 - t0_midnight).subseconds())) - .count(); - - return std::make_pair(t0_tm, usec); - } /*split_tm*/ - - static void print_hms_msec(nanos dt, std::ostream & os) { - /* use hhmmss.nnn */ - using std::int32_t; - - auto hms = std::chrono::hh_mm_ss(dt); - int32_t h = hms.hours().count(); - int32_t m = hms.minutes().count(); - int32_t s = hms.seconds().count(); - int32_t msec = std::chrono::duration_cast(hms.subseconds()).count(); - - char buf[32]; - snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%03d", h, m, s, msec); - - os << buf; - } /*print_hms_msec*/ - - static void print_utc_hms_msec(utc_nanos t0, std::ostream & os) { - print_hms_msec(utc_split_vs_midnight(t0).second, os); - } /*print_utc_hms_usec*/ - - static void print_hms_usec(nanos dt, std::ostream & os) { - /* use hhmmss.uuuuuu */ - using std::int32_t; - - auto hms = std::chrono::hh_mm_ss(dt); - int32_t h = hms.hours().count(); - int32_t m = hms.minutes().count(); - int32_t s = hms.seconds().count(); - int32_t usec = std::chrono::duration_cast(hms.subseconds()).count(); - - char buf[32]; - snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06d", h, m, s, usec); - - os << buf; - } /*print_hms_usec*/ - - static void print_utc_ymd_hms_usec(utc_nanos t0, std::ostream & os) { - using xo::time::microseconds; - using xo::time::utc_nanos; - - /* use yyyymmdd.hh:mm:ss.nnnnnn */ - - //std::tm t0_tm; - //uint32_t t0_usec; - - /* (structured binding ftw!) */ - auto [t0_tm, t0_usec] = split_tm(t0); - - /* no std::format in clang11 afaict */ - char usec_buf[7]; - snprintf(usec_buf, sizeof(usec_buf), "%06d", t0_usec); - - - /* control string | example - * ----------------------------+-------------------------- - * %c - locale-specific string | Fri Jun 10 16:29:05 2022 - * %Y - year | 2022 - * %m - month | 06 - * %d - day of month | 10 - * %H - hour | 16 - * %M - minute | 29 - * %S - second | 05 - * %Z - timezone | UTC - */ - os << std::put_time(&t0_tm, "%Y%m%d:%H:%M:%S.") << usec_buf; - } /*print_utc_ymd_hms_usec*/ - - /* print datetime in format compatible with ISO 8601. - * copying the format javascript uses, e.g: - * 2012-04-23T18:25:43.511Z - */ - static void print_iso8601(utc_nanos t0, std::ostream & os) { - auto [t0_tm, t0_usec] = split_tm(t0); - - char msec_buf[8]; - snprintf(msec_buf, sizeof(msec_buf), "%03d", t0_usec / 1000); - - os << std::put_time(&t0_tm, "%Y-%m-%dT%H:%M:%S.") << msec_buf << "Z"; - } /*print_iso8601*/ - }; /*time*/ + // ----- iso8601 ----- /* stream inserter that displays time in ISO 8601 format: * 2012-04-23T18:25:43.511Z @@ -294,18 +21,20 @@ namespace xo { operator<<(std::ostream & os, iso8601 x) { - time::print_iso8601(x.t0_, os); + timeutil::print_iso8601(x.t0_, os); return os; } /*operator<<*/ + // ----- hms_msec ----- + /* stream inserter that display time like: * hh:mm:ss.nnn */ struct hms_msec { hms_msec(nanos dt) : dt_{dt} {} - static hms_msec utc(utc_nanos t0) { return hms_msec(time::utc_split_vs_midnight(t0).second); } - static hms_msec local(utc_nanos t0) { return hms_msec(time::local_split_vs_midnight(t0).second); } + static hms_msec utc(utc_nanos t0) { return hms_msec(timeutil::utc_split_vs_midnight(t0).second); } + static hms_msec local(utc_nanos t0) { return hms_msec(timeutil::local_split_vs_midnight(t0).second); } nanos dt_; }; /*hms_msec*/ @@ -313,10 +42,11 @@ namespace xo { inline std::ostream & operator<<(std::ostream & os, hms_msec x) { - time::print_hms_msec(x.dt_, os); + timeutil::print_hms_msec(x.dt_, os); return os; } /*operator<<*/ + // ----- hms_usec ----- /* stream inserter that display time like: * hh:mm:ss.nnnnnn @@ -324,8 +54,8 @@ namespace xo { struct hms_usec { hms_usec(nanos dt) : dt_{dt} {} - static hms_usec utc(utc_nanos t0) { return hms_usec(time::utc_split_vs_midnight(t0).second); } - static hms_usec local(utc_nanos t0) { return hms_usec(time::local_split_vs_midnight(t0).second); } + static hms_usec utc(utc_nanos t0) { return hms_usec(timeutil::utc_split_vs_midnight(t0).second); } + static hms_usec local(utc_nanos t0) { return hms_usec(timeutil::local_split_vs_midnight(t0).second); } nanos dt_; }; /*hms_msec*/ @@ -333,11 +63,9 @@ namespace xo { inline std::ostream & operator<<(std::ostream & os, hms_usec x) { - time::print_hms_usec(x.dt_, os); + timeutil::print_hms_usec(x.dt_, os); return os; } /*operator<<*/ - - } /*namespace time*/ } /*namespace xo*/ @@ -346,14 +74,14 @@ namespace std { inline std::ostream & operator<<(std::ostream & os, xo::time::utc_nanos t0) { - xo::time::time::print_utc_ymd_hms_usec(t0, os); + xo::time::timeutil::print_utc_ymd_hms_usec(t0, os); return os; } /*operator<<*/ inline std::ostream & operator<<(std::ostream & os, xo::time::nanos dt) { - xo::time::time::print_hms_usec(dt, os); + xo::time::timeutil::print_hms_usec(dt, os); return os; } /*operator<<*/ } /*namespace chrono*/ diff --git a/include/indentlog/scope.hpp b/include/indentlog/scope.hpp index b86923c1..551589e9 100644 --- a/include/indentlog/scope.hpp +++ b/include/indentlog/scope.hpp @@ -23,7 +23,7 @@ namespace xo { # define XO_DEBUG(debug_flag) XO_ENTER1(always, debug_flag) # define XO_DEBUG2(debug_flag, name1) XO_ENTER2(always, debug_flag, name1) -# define XO_LITERAL(lvl, name1, name2) xo::scope_setup(xo::log_level::lvl, FS_Literal, name1, name2, __FILE__, __LINE__) +# define XO_LITERAL(lvl, name1, name2) xo::scope_setup(xo::log_level::lvl, function_style::literal, name1, name2, __FILE__, __LINE__) //# define XO_SSETUP0() xo::scope_setup(__FUNCTION__) //# define XO_SSETUP0(lvl) xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) diff --git a/include/indentlog/timeutil/timeutil.hpp b/include/indentlog/timeutil/timeutil.hpp new file mode 100644 index 00000000..6e24d3ce --- /dev/null +++ b/include/indentlog/timeutil/timeutil.hpp @@ -0,0 +1,287 @@ +/* @file time.hpp */ + +#pragma once + +#include +#include +#ifdef NOT_YET +# include +#endif +#include +#include +#include + +namespace xo { + namespace time { + + using utc_nanos = std::chrono::time_point; + + using nanos = std::chrono::nanoseconds; + using microseconds = std::chrono::microseconds; + using milliseconds = std::chrono::milliseconds; + using seconds = std::chrono::seconds; + using hours = std::chrono::hours; + using days = std::chrono::days; + + struct timeutil { + static utc_nanos now() { + return utc_nanos(std::chrono::system_clock::now()); + } + + static utc_nanos epoch() { + return utc_nanos(std::chrono::system_clock::from_time_t(0)); + } /*epoch*/ + + static utc_nanos ymd_hms(uint32_t ymd, uint32_t hms) { + /* e.g. ymd=20220610 -> n_yr=2022, n_mon=06, n_dy=10 */ + + uint32_t n_yr = ymd / 10000; + uint32_t n_mon = (ymd % 10000) / 100; + uint32_t n_dy = ymd % 100; + + uint32_t n_hr = hms / 10000; + uint32_t n_min = (hms % 10000) / 100; + uint32_t n_sec = hms % 100; + + struct tm t; + + t.tm_year = n_yr - 1900; /* 0 means 1900 */ + t.tm_mon = n_mon - 1; /* 0 means january */ + t.tm_mday = n_dy; + + t.tm_hour = n_hr; /* 24 hour clock */ + t.tm_min = n_min; + t.tm_sec = n_sec; + + /* time since epoch */ + time_t epoch_time = timegm(&t); + + return std::chrono::system_clock::from_time_t(epoch_time); + } /*ymd_hms*/ + + /* midnight UTC on date ymd. + * e.g. ymd_midnight(20220707) -> midnight UTC on 7jul22 + */ + static utc_nanos ymd_midnight(uint32_t ymd) { + return ymd_hms(ymd, 0); + } /*ymd_midnight*/ + + static utc_nanos ymd_hms_usec(uint32_t ymd, uint32_t hms, uint32_t usec) { + utc_nanos s = ymd_hms(ymd, hms); + + return s + microseconds(usec); + } /*ymd_hms_usec*/ + + /* .first: UTC midnight on same calendar day as t0 + * .second: elapsed time from .first to t0 (i.e. UTC time-of-day for t0) + */ + static std::pair utc_split_vs_midnight(utc_nanos t0) { + //using xo::timeutil::microseconds; + //using xo::timeutil::utc_nanos; + + /* use yyyymmdd.hh:mm:ss.nnnnnn */ + + time_t t0_time_t = (std::chrono::system_clock::to_time_t + (std::chrono::time_point_cast(t0))); + + /* convert to std::tm, + * only provides 1-second precision + */ + std::tm t0_tm; + ::gmtime_r(&t0_time_t, &t0_tm); + + /* midnight on the same calendar day as t0_tm */ + std::tm midnight_tm = t0_tm; + { + midnight_tm.tm_hour = 0; + midnight_tm.tm_min = 0; + midnight_tm.tm_sec = 0; + } + + /* convert to UTC epoch seconds */ + time_t midnight_time_t = ::timegm(&midnight_tm); + + utc_nanos t0_midnight = + (std::chrono::time_point_cast( + std::chrono::system_clock::from_time_t(midnight_time_t))); + + nanos t0_tdy = t0 - t0_midnight; + + return std::pair(t0_midnight, t0_tdy); + } /*utc_split_vs_midnight*/ + + /* .first: LOCAL midnight on same calendar day as t0 (but in UTC coords) + * .second: elapsed time from .first to t0 (i.e. LOCAL time-of-day for t0) + */ + static std::pair local_split_vs_midnight(utc_nanos t0) { + using xo::time::microseconds; + using xo::time::utc_nanos; + + /* use yyyymmdd.hh:mm:ss.nnnnnn */ + + time_t t0_time_t = (std::chrono::system_clock::to_time_t + (std::chrono::time_point_cast(t0))); + + /* convert to std::tm, + * only provides 1-second precision + */ + std::tm t0_tm; + ::localtime_r(&t0_time_t, &t0_tm); + + /* midnight on the same calendar day as t0_tm */ + std::tm midnight_tm = t0_tm; + { + midnight_tm.tm_hour = 0; + midnight_tm.tm_min = 0; + midnight_tm.tm_sec = 0; + } + + /* convert local midnight to UTC epoch seconds */ + time_t midnight_time_t = ::timelocal(&midnight_tm); + + utc_nanos t0_midnight = + (std::chrono::time_point_cast( + std::chrono::system_clock::from_time_t(midnight_time_t))); + + nanos t0_tdy = t0 - t0_midnight; + + return std::pair(t0_midnight, t0_tdy); + } /*local_split_vs_midnight*/ + + /* split utc_nanos into + * std::tm + * .tm_year + * .tm_mon (1-12) + * .tm_mday (1-31) + * .tm_hour (0-23) + * .tm_min (0-59) + * .tm_sec (0-59) + * .tm_wday (0=sunday .. 6=saturday) + * .tm_yday (0=1jan .. 365) + * .tm_isdst (daylight savings time flag) + * usec (0-999999) + */ + static std::pair split_tm(utc_nanos t0) { + using xo::time::microseconds; + using xo::time::utc_nanos; + + /* use yyyymmdd.hh:mm:ss.nnnnnn */ + + time_t t0_time_t = (std::chrono::system_clock::to_time_t + (std::chrono::time_point_cast(t0))); + + /* convert to std::tm, un UTC coords, + * only provides 1-second precision + */ + std::tm t0_tm; + ::gmtime_r(&t0_time_t, &t0_tm); + + /* midnight on the same calendar day as t0_tm */ + std::tm midnight_tm = t0_tm; + + midnight_tm.tm_isdst = 0; + midnight_tm.tm_hour = 0; + midnight_tm.tm_min = 0; + midnight_tm.tm_sec = 0; + + /* convert back to epoch seconds */ + time_t midnight_time_t = ::mktime(&midnight_tm); + + utc_nanos t0_midnight = + (std::chrono::time_point_cast( + std::chrono::system_clock::from_time_t(midnight_time_t))); + + uint32_t usec = + (std::chrono::duration_cast( + std::chrono::hh_mm_ss(t0 - t0_midnight).subseconds())) + .count(); + + return std::make_pair(t0_tm, usec); + } /*split_tm*/ + + static void print_hms_msec(nanos dt, std::ostream & os) { + /* use hhmmss.nnn */ + using std::int32_t; + + auto hms = std::chrono::hh_mm_ss(dt); + int32_t h = hms.hours().count(); + int32_t m = hms.minutes().count(); + int32_t s = hms.seconds().count(); + int32_t msec = std::chrono::duration_cast(hms.subseconds()).count(); + + char buf[32]; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%03d", h, m, s, msec); + + os << buf; + } /*print_hms_msec*/ + + static void print_utc_hms_msec(utc_nanos t0, std::ostream & os) { + print_hms_msec(utc_split_vs_midnight(t0).second, os); + } /*print_utc_hms_usec*/ + + static void print_hms_usec(nanos dt, std::ostream & os) { + /* use hhmmss.uuuuuu */ + using std::int32_t; + + auto hms = std::chrono::hh_mm_ss(dt); + int32_t h = hms.hours().count(); + int32_t m = hms.minutes().count(); + int32_t s = hms.seconds().count(); + int32_t usec = std::chrono::duration_cast(hms.subseconds()).count(); + + char buf[32]; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06d", h, m, s, usec); + + os << buf; + } /*print_hms_usec*/ + + static void print_utc_ymd_hms_usec(utc_nanos t0, std::ostream & os) { + using xo::time::microseconds; + using xo::time::utc_nanos; + + /* use yyyymmdd.hh:mm:ss.nnnnnn */ + + //std::tm t0_tm; + //uint32_t t0_usec; + + /* (structured binding ftw!) */ + auto [t0_tm, t0_usec] = split_tm(t0); + + /* no std::format in clang11 afaict */ + char usec_buf[7]; + snprintf(usec_buf, sizeof(usec_buf), "%06d", t0_usec); + + + /* control string | example + * ----------------------------+-------------------------- + * %c - locale-specific string | Fri Jun 10 16:29:05 2022 + * %Y - year | 2022 + * %m - month | 06 + * %d - day of month | 10 + * %H - hour | 16 + * %M - minute | 29 + * %S - second | 05 + * %Z - timezone | UTC + */ + os << std::put_time(&t0_tm, "%Y%m%d:%H:%M:%S.") << usec_buf; + } /*print_utc_ymd_hms_usec*/ + + /* print datetime in format compatible with ISO 8601. + * copying the format javascript uses, e.g: + * 2012-04-23T18:25:43.511Z + */ + static void print_iso8601(utc_nanos t0, std::ostream & os) { + auto [t0_tm, t0_usec] = split_tm(t0); + + char msec_buf[8]; + snprintf(msec_buf, sizeof(msec_buf), "%03d", t0_usec / 1000); + + os << std::put_time(&t0_tm, "%Y-%m-%dT%H:%M:%S.") << msec_buf << "Z"; + } /*print_iso8601*/ + }; /*timeutil*/ + + } /*namespace time*/ +} /*namespace xo*/ + +/* end timeutil.hpp */ From 6f74ce1cf42f7d23a5450a9f94808ef13b82d43d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 18 Sep 2023 17:51:28 -0400 Subject: [PATCH 075/170] build: cmake install targets --- CMakeLists.txt | 7 +++++++ include/CMakeLists.txt | 6 ++++++ 2 files changed, 13 insertions(+) create mode 100644 include/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 38939895..aeeda3ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,4 +6,11 @@ enable_testing() include(cmake/nestlog.cmake) +add_subdirectory(include) add_subdirectory(example) + +# this doesn't work in include/CMakeLists.txt +install(TARGETS indentlog DESTINATION include) + +set(CMAKE_INSTALL_PREFIX /home/roland/local) +set(CMAKE_INSTALL_RPATH /home/roland/local/lib) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt new file mode 100644 index 00000000..72fcb50d --- /dev/null +++ b/include/CMakeLists.txt @@ -0,0 +1,6 @@ +# header-only library +add_library(indentlog INTERFACE) +target_include_directories(indentlog INTERFACE + $ + $ + ) From 468c525470ccf66cd841ddb810c7835d638fec50 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 19 Sep 2023 14:34:41 -0400 Subject: [PATCH 076/170] indentlog: + hello example + cmake install attempt --- CMakeLists.txt | 24 +++++++++++++++++------- cmake/nestlog.cmake | 3 +-- example/CMakeLists.txt | 1 + example/hello/CMakeLists.txt | 2 ++ example/hello/hello.cpp | 5 +++++ include/CMakeLists.txt | 6 ------ 6 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 example/hello/CMakeLists.txt create mode 100644 example/hello/hello.cpp delete mode 100644 include/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index aeeda3ed..d819b716 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,13 +4,23 @@ project(nestlog VERSION 0.1) enable_language(CXX) enable_testing() -include(cmake/nestlog.cmake) - -add_subdirectory(include) -add_subdirectory(example) - -# this doesn't work in include/CMakeLists.txt -install(TARGETS indentlog DESTINATION include) +# always write compile_commands.json +set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") set(CMAKE_INSTALL_PREFIX /home/roland/local) set(CMAKE_INSTALL_RPATH /home/roland/local/lib) + +include(cmake/nestlog.cmake) +add_subdirectory(example) + +# header-only library +#add_library(indentlog INTERFACE) +#target_include_directories(indentlog INTERFACE +# $ +# $ +# ) +# +#install(TARGETS indentlog +# PUBLIC_HEADER DESTINATION include) # COMPONENT Development + +install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION include) diff --git a/cmake/nestlog.cmake b/cmake/nestlog.cmake index 30736007..4a1a26ae 100644 --- a/cmake/nestlog.cmake +++ b/cmake/nestlog.cmake @@ -25,7 +25,6 @@ macro(xo_include_options target) # (2) clangd (run from emacs lsp-mode) can find them # if(CMAKE_EXPORT_COMPILE_COMMANDS) - set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES - ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) endif() endmacro() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 7f8eb99d..0f629f7a 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -7,6 +7,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") #include(cmake/FindSphinx.cmake) +add_subdirectory(hello) add_subdirectory(ex1) add_subdirectory(ex2) add_subdirectory(ex3) diff --git a/example/hello/CMakeLists.txt b/example/hello/CMakeLists.txt new file mode 100644 index 00000000..d6f694e6 --- /dev/null +++ b/example/hello/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(hello hello.cpp) +xo_include_options(hello) diff --git a/example/hello/hello.cpp b/example/hello/hello.cpp new file mode 100644 index 00000000..5147511e --- /dev/null +++ b/example/hello/hello.cpp @@ -0,0 +1,5 @@ +#include + +int main(int argc, char ** argv) { + std::cout << "Hello, world!" << std::endl; +} diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt deleted file mode 100644 index 72fcb50d..00000000 --- a/include/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# header-only library -add_library(indentlog INTERFACE) -target_include_directories(indentlog INTERFACE - $ - $ - ) From 3aa23ef8940f2d7cbe9675cf7e966c34fc3aff62 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 19 Sep 2023 14:52:11 -0400 Subject: [PATCH 077/170] indentlog: build: install fixes --- CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d819b716..bb0649be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,12 @@ enable_testing() # always write compile_commands.json set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") -set(CMAKE_INSTALL_PREFIX /home/roland/local) -set(CMAKE_INSTALL_RPATH /home/roland/local/lib) +if(NOT CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX /home/roland/local CACHE STRING "install directory") +endif() +if(NOT CMAKE_INSTALL_RPATH) + set(CMAKE_INSTALL_RPATH /home/roland/local/lib CACHE STRING "runpath in installed libraries/executables") +endif() include(cmake/nestlog.cmake) add_subdirectory(example) @@ -24,3 +28,9 @@ add_subdirectory(example) # PUBLIC_HEADER DESTINATION include) # COMPONENT Development install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION include) + +install(TARGETS hello DESTINATION bin/indentlog/example) +install(TARGETS ex1 DESTINATION bin/indentlog/example) +install(TARGETS ex2 DESTINATION bin/indentlog/example) +install(TARGETS ex3 DESTINATION bin/indentlog/example) +install(TARGETS ex4 DESTINATION bin/indentlog/example) From 0977ff960601b501e36d60d42a7b916c6bebe0c8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 19 Sep 2023 14:59:09 -0400 Subject: [PATCH 078/170] + FAQ --- FAQ | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 FAQ diff --git a/FAQ b/FAQ new file mode 100644 index 00000000..6e85b042 --- /dev/null +++ b/FAQ @@ -0,0 +1,25 @@ +development environment that works + +1. + 1. nix stdenv = gcc12Stdenv (see mkderivation.nix) + 2. baseInputs has gcc (but probably doesn't need it) + 3. devInputs has llvmPackages_16.clang-unwrapped + + This leads to env with + CC=gcc + CXX=g++ + NIX_CC=/nix/store/$hash-gcc-wrapper-12.3.0 + +2. + + 1. nix stdenv = clang16Stdenv (see mkderivation.nix) + 2. baseInputs has gcc + 3. devInputs has llvmPackages_16.clang-unwrapped + + This leads to env with: + CC=clang + CXX=clang++ + NIX_CC=/nix/store/$hash-clang-wrapper-16.0.1 + + To build, need to tell cmake to use gcc: + cmake -DCMAKE_CXX_COMPILER=$(which g++) -DCMAKE_C_COMPILER=$(which gcc) path/to/src From 414630a09a3d2be8a6483649a8746a6bc712cc08 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 19 Sep 2023 15:22:20 -0400 Subject: [PATCH 079/170] doc: expand build instructions --- CMakeLists.txt | 8 ++++++-- README.md | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb0649be..b5a8caaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,15 @@ enable_testing() # always write compile_commands.json set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") +if(NOT USER) + set(USER $ENV{USER}) +endif() + if(NOT CMAKE_INSTALL_PREFIX) - set(CMAKE_INSTALL_PREFIX /home/roland/local CACHE STRING "install directory") + set(CMAKE_INSTALL_PREFIX /home/${USER}/local CACHE STRING "install directory") endif() if(NOT CMAKE_INSTALL_RPATH) - set(CMAKE_INSTALL_RPATH /home/roland/local/lib CACHE STRING "runpath in installed libraries/executables") + set(CMAKE_INSTALL_RPATH /home/${USER}/local/lib CACHE STRING "runpath in installed libraries/executables") endif() include(cmake/nestlog.cmake) diff --git a/README.md b/README.md index 1db16b19..22e8bf63 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,27 @@ Indentlog is a lightweight header-only library for console logging. - logger is 'truthy' -> only pay for formatting when entry points is enabled. - also provides family of convenience stream-inserters +## Getting Started + +### copy repository locally + +``` +$ git clone git@github.com:rconybea/indentlog.git +$ ls -d indentlog +indentlog +``` + +### build & install + +``` +$ cd indentlog +$ mkdir build +$ cd build +$ cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. +$ make +$ make install +``` + ## Examples ### 1 From 6775e8243ae9c6f56788421c71c20eb9a00a6a7a Mon Sep 17 00:00:00 2001 From: Roland Date: Tue, 19 Sep 2023 15:36:01 -0400 Subject: [PATCH 080/170] Create cmake-single-platform.yml --- .github/workflows/cmake-single-platform.yml | 39 +++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/cmake-single-platform.yml diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml new file mode 100644 index 00000000..28c6f783 --- /dev/null +++ b/.github/workflows/cmake-single-platform.yml @@ -0,0 +1,39 @@ +# This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml +name: CMake on a single platform + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. + # You can convert this to a matrix build if you need cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + From 6364779191fdff7f89457399a671e1bdd430d3f5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 19 Sep 2023 15:56:22 -0400 Subject: [PATCH 081/170] doc: + nix instructions --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 22e8bf63..fb8b2deb 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,15 @@ $ make $ make install ``` +alternatively, if you're a nix user: +``` +$ git clone git@github.com:rconybea/indentlog-nix.git +$ ls -d indentlog-nix +indentlog-nix +$ cd indentlog-nix +$ nix-build +``` + ## Examples ### 1 From 7676b7a6761be8f77b4706aa8670706c13fd468b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 19 Sep 2023 17:12:13 -0400 Subject: [PATCH 082/170] + unit test for xo::fixed --- CMakeLists.txt | 1 + utest/CMakeLists.txt | 25 ++++++++++ utest/fixed.test.cpp | 84 ++++++++++++++++++++++++++++++++++ utest/indentlog_utest_main.cpp | 6 +++ 4 files changed, 116 insertions(+) create mode 100644 utest/CMakeLists.txt create mode 100644 utest/fixed.test.cpp create mode 100644 utest/indentlog_utest_main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b5a8caaa..9318caa2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ endif() include(cmake/nestlog.cmake) add_subdirectory(example) +add_subdirectory(utest) # header-only library #add_library(indentlog INTERFACE) diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt new file mode 100644 index 00000000..187a92c3 --- /dev/null +++ b/utest/CMakeLists.txt @@ -0,0 +1,25 @@ +# indentlog unit test + +set(SELF_EXECUTABLE_NAME utest.indentlog) +set(SELF_SOURCE_FILES fixed.test.cpp indentlog_utest_main.cpp) + +add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) +xo_include_options(${SELF_EXECUTABLE_NAME}) + +add_test(NAME ${SELF_EXECUTABLE_NAME} COMMAND ${SELF_EXECUTABLE_NAME}) + +# ---------------------------------------------------------------- +# 3rd party dependency: catch2 + +find_package(Catch2 2 REQUIRED) + +# ---------------------------------------------------------------- +# make standard directories for std:: includes explicit +# so that +# (1) they appear in compile_commands.json. +# (2) clangd (run from emacs lsp-mode) can find them +# +if(CMAKE_EXPORT_COMPILE_COMMANDS) + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES + ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) +endif() diff --git a/utest/fixed.test.cpp b/utest/fixed.test.cpp new file mode 100644 index 00000000..d882e542 --- /dev/null +++ b/utest/fixed.test.cpp @@ -0,0 +1,84 @@ +/* @file fixed.test.cpp */ + +#include "indentlog/print/fixed.hpp" +#include "indentlog/print/tag.hpp" +#include +#include + +using namespace xo; + +namespace ut { + struct fixed_tcase { + fixed_tcase() = default; + fixed_tcase(double x, std::uint32_t prec, std::string s) + : x_{x}, prec_{prec}, s_{std::move(s)} {} + + /* floating-point value to format */ + double x_ = 0.0; + /* precision */ + std::uint32_t prec_ = 0; + /* expected result */ + std::string s_; + }; /*fixed_tcase*/ + + std::vector s_fixed_tcase_v( + {fixed_tcase(0.0, 0, "0"), + fixed_tcase(0.0, 1, "0.0"), + fixed_tcase(0.0, 2, "0.00"), + + //fixed_tcase(0.5, 0, "1"), // failing --> 0 + fixed_tcase(0.5, 1, "0.5"), + + fixed_tcase(0.049, 0, "0"), + fixed_tcase(0.049, 1, "0.0"), + fixed_tcase(0.049, 2, "0.05"), + + fixed_tcase(0.05, 0, "0"), + fixed_tcase(0.05, 1, "0.1"), + fixed_tcase(0.05, 2, "0.05"), + + fixed_tcase(1e-6, 0, "0"), + fixed_tcase(1e-6, 1, "0.0"), + fixed_tcase(1e-6, 2, "0.00"), + fixed_tcase(1e-6, 3, "0.000"), + fixed_tcase(1e-6, 4, "0.0000"), + fixed_tcase(1e-6, 5, "0.00000"), + fixed_tcase(1e-6, 6, "0.000001"), + + fixed_tcase(-1e-6, 0, "-0"), + fixed_tcase(-1e-6, 1, "-0.0"), + fixed_tcase(-1e-6, 2, "-0.00"), + fixed_tcase(-1e-6, 3, "-0.000"), + fixed_tcase(-1e-6, 4, "-0.0000"), + fixed_tcase(-1e-6, 5, "-0.00000"), + fixed_tcase(-1e-6, 6, "-0.000001"), + + fixed_tcase(666.66, 1, "666.7"), + fixed_tcase(666.66, 2, "666.66"), + + fixed_tcase(-666.66, 1, "-666.7"), + fixed_tcase(-666.66, 2, "-666.66"), + + }); + + TEST_CASE("fixed", "[fixed]") { + tag_config::tag_color = color_spec_type::none(); + + for (std::uint32_t i_tc = 0, z_tc = s_fixed_tcase_v.size(); i_tc < z_tc; ++i_tc) { + fixed_tcase const & tc = s_fixed_tcase_v[i_tc]; + + INFO(tostr(xtag("i_tc", i_tc), xtag("x", tc.x_), xtag("prec", tc.prec_))); + + std::stringstream ss; + ss << fixed(tc.x_, tc.prec_); + + INFO(xtag("ss.str", ss.str())); + + REQUIRE(ss.str() == tc.s_); + } + + REQUIRE(s_fixed_tcase_v.size() > 1); + } +} /*namespace ut*/ + +/* end fixed.test.cpp */ diff --git a/utest/indentlog_utest_main.cpp b/utest/indentlog_utest_main.cpp new file mode 100644 index 00000000..6337b638 --- /dev/null +++ b/utest/indentlog_utest_main.cpp @@ -0,0 +1,6 @@ +/* @file indentlog_utest_main.cpp */ + +#define CATCH_CONFIG_MAIN +#include "catch2/catch.hpp" + +/* end indentlog_utest_main.cpp */ From 9678b6fdea5098916b4352fa5e27b937a17ac2e3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 19 Sep 2023 17:33:02 -0400 Subject: [PATCH 083/170] github: + catch2 install for build --- .github/workflows/cmake-single-platform.yml | 5 ++++- FAQ | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 28c6f783..059cf017 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -22,6 +22,10 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Install catch2 + # install catch2. see [[https://stackoverflow.com/questions/57982945/how-to-apt-get-install-in-a-github-actions-workflow]] + run: sudo apt-get install -y catch2 + - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type @@ -36,4 +40,3 @@ jobs: # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} - diff --git a/FAQ b/FAQ index 6e85b042..27d04f3b 100644 --- a/FAQ +++ b/FAQ @@ -1,4 +1,4 @@ -development environment that works +Q1. how to get a nix development environment that works 1. 1. nix stdenv = gcc12Stdenv (see mkderivation.nix) @@ -23,3 +23,18 @@ development environment that works To build, need to tell cmake to use gcc: cmake -DCMAKE_CXX_COMPILER=$(which g++) -DCMAKE_C_COMPILER=$(which gcc) path/to/src + +Q2. how to add a dependency to github workflow + + comments. + 1. workflow configured in ./.github/cmake-single-platform.yml + 2. workflow runs on ubuntu vm. see + runs-on: ubuntu-latest + in cmake-single-platform.yml + 3. find a desired dependency + $ apt-cache search ${keyword} + e.g. + $ apt-cache search catch2 + 4. add/edit install step to ./.github/cmake-single-platform.yml + - name: Install catch2 + run: sudo apt-get install -y catch2 From dd75bcfedff534eb67908126ba65b2293e603815 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 20 Sep 2023 16:59:46 -0400 Subject: [PATCH 084/170] + test code coverage + writeup --- CMakeLists.txt | 8 +- README.md | 2 + cmake/code-coverage.cmake | 678 ++++++++++++++++++++++++++++++++++++++ img/lcov1.png | Bin 0 -> 125426 bytes utest/CMakeLists.txt | 1 + 5 files changed, 688 insertions(+), 1 deletion(-) create mode 100644 cmake/code-coverage.cmake create mode 100755 img/lcov1.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 9318caa2..7656fc0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,14 @@ cmake_minimum_required(VERSION 3.10) project(nestlog VERSION 0.1) enable_language(CXX) + +include(cmake/nestlog.cmake) +include(cmake/code-coverage.cmake) + enable_testing() +# activate code coverage for all executables + libraries (when -DCODE_COVERAGE=ON ??) +add_code_coverage() +add_code_coverage_all_targets() # always write compile_commands.json set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") @@ -18,7 +25,6 @@ if(NOT CMAKE_INSTALL_RPATH) set(CMAKE_INSTALL_RPATH /home/${USER}/local/lib CACHE STRING "runpath in installed libraries/executables") endif() -include(cmake/nestlog.cmake) add_subdirectory(example) add_subdirectory(utest) diff --git a/README.md b/README.md index fb8b2deb..bd376bd9 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ $ cd indentlog-nix $ nix-build ``` +For some more detail see [BUILD.md](BUILD.md) + ## Examples ### 1 diff --git a/cmake/code-coverage.cmake b/cmake/code-coverage.cmake new file mode 100644 index 00000000..b6b36064 --- /dev/null +++ b/cmake/code-coverage.cmake @@ -0,0 +1,678 @@ +# +# Copyright (C) 2018-2020 by George Cave - gcave@stablecoder.ca +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +# USAGE: To enable any code coverage instrumentation/targets, the single CMake +# option of `CODE_COVERAGE` needs to be set to 'ON', either by GUI, ccmake, or +# on the command line. +# +# From this point, there are two primary methods for adding instrumentation to +# targets: +# +# 1 - A blanket instrumentation by calling `add_code_coverage()`, where +# all targets in that directory and all subdirectories are automatically +# instrumented. +# +# 2 - Per-target instrumentation by calling +# `target_code_coverage()`, where the target is given and thus only +# that target is instrumented. This applies to both libraries and executables. +# +# To add coverage targets, such as calling `make ccov` to generate the actual +# coverage information for perusal or consumption, call +# `target_code_coverage()` on an *executable* target. +# +# Example 1: All targets instrumented +# +# In this case, the coverage information reported will will be that of the +# `theLib` library target and `theExe` executable. +# +# 1a: Via global command +# +# ~~~ +# add_code_coverage() # Adds instrumentation to all targets +# +# add_library(theLib lib.cpp) +# +# add_executable(theExe main.cpp) +# target_link_libraries(theExe PRIVATE theLib) +# target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target +# # (instrumentation already added via global anyways) +# # for generating code coverage reports. +# ~~~ +# +# 1b: Via target commands +# +# ~~~ +# add_library(theLib lib.cpp) +# target_code_coverage(theLib) # As a library target, adds coverage instrumentation but no targets. +# +# add_executable(theExe main.cpp) +# target_link_libraries(theExe PRIVATE theLib) +# target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target and instrumentation for generating code coverage reports. +# ~~~ +# +# Example 2: Target instrumented, but with regex pattern of files to be excluded +# from report +# +# ~~~ +# add_executable(theExe main.cpp non_covered.cpp) +# target_code_coverage(theExe EXCLUDE non_covered.cpp test/*) # As an executable target, the reports will exclude the non-covered.cpp file, and any files in a test/ folder. +# ~~~ +# +# Example 3: Target added to the 'ccov' and 'ccov-all' targets +# +# ~~~ +# add_code_coverage_all_targets(EXCLUDE test/*) # Adds the 'ccov-all' target set and sets it to exclude all files in test/ folders. +# +# add_executable(theExe main.cpp non_covered.cpp) +# target_code_coverage(theExe AUTO ALL EXCLUDE non_covered.cpp test/*) # As an executable target, adds to the 'ccov' and ccov-all' targets, and the reports will exclude the non-covered.cpp file, and any files in a test/ folder. +# ~~~ + +# Options +option( + CODE_COVERAGE + "Builds targets with code coverage instrumentation. (Requires GCC or Clang)" + OFF) + +# Programs +find_program(LLVM_COV_PATH llvm-cov) +find_program(LLVM_PROFDATA_PATH llvm-profdata) +find_program(LCOV_PATH lcov) +find_program(GENHTML_PATH genhtml) +# Hide behind the 'advanced' mode flag for GUI/ccmake +mark_as_advanced(FORCE LLVM_COV_PATH LLVM_PROFDATA_PATH LCOV_PATH GENHTML_PATH) + +# Variables +set(CMAKE_COVERAGE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/ccov) +set_property(GLOBAL PROPERTY JOB_POOLS ccov_serial_pool=1) + +# Common initialization/checks +if(CODE_COVERAGE AND NOT CODE_COVERAGE_ADDED) + set(CODE_COVERAGE_ADDED ON) + + # Common Targets + add_custom_target( + ccov-preprocessing + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY} + DEPENDS ccov-clean) + + if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" + OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") + # Messages + message(STATUS "Building with llvm Code Coverage Tools") + + if(NOT LLVM_COV_PATH) + message(FATAL_ERROR "llvm-cov not found! Aborting.") + else() + # Version number checking for 'EXCLUDE' compatibility + execute_process(COMMAND ${LLVM_COV_PATH} --version + OUTPUT_VARIABLE LLVM_COV_VERSION_CALL_OUTPUT) + string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" LLVM_COV_VERSION + ${LLVM_COV_VERSION_CALL_OUTPUT}) + + if(LLVM_COV_VERSION VERSION_LESS "7.0.0") + message( + WARNING + "target_code_coverage()/add_code_coverage_all_targets() 'EXCLUDE' option only available on llvm-cov >= 7.0.0" + ) + endif() + endif() + + # Targets + if(${CMAKE_VERSION} VERSION_LESS "3.17.0") + add_custom_target( + ccov-clean + COMMAND ${CMAKE_COMMAND} -E remove -f + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list + COMMAND ${CMAKE_COMMAND} -E remove -f + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list) + else() + add_custom_target( + ccov-clean + COMMAND ${CMAKE_COMMAND} -E rm -f + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list + COMMAND ${CMAKE_COMMAND} -E rm -f + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list) + endif() + + # Used to get the shared object file list before doing the main all- + # processing + add_custom_target( + ccov-libs + COMMAND ; + COMMENT "libs ready for coverage report.") + + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES + "GNU") + # Messages + message(STATUS "Building with lcov Code Coverage Tools") + + if(CMAKE_BUILD_TYPE) + string(TOUPPER ${CMAKE_BUILD_TYPE} upper_build_type) + if(NOT ${upper_build_type} STREQUAL "DEBUG") + message( + WARNING + "Code coverage results with an optimized (non-Debug) build may be misleading" + ) + endif() + else() + message( + WARNING + "Code coverage results with an optimized (non-Debug) build may be misleading" + ) + endif() + if(NOT LCOV_PATH) + message(FATAL_ERROR "lcov not found! Aborting...") + endif() + if(NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Aborting...") + endif() + + # Targets + add_custom_target(ccov-clean COMMAND ${LCOV_PATH} --directory + ${CMAKE_BINARY_DIR} --zerocounters) + + else() + message(FATAL_ERROR "Code coverage requires Clang or GCC. Aborting.") + endif() +endif() + +# Adds code coverage instrumentation to a library, or instrumentation/targets +# for an executable target. +# ~~~ +# EXECUTABLE ADDED TARGETS: +# GCOV/LCOV: +# ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter. +# ccov-${TARGET_NAME} : Generates HTML code coverage report for the associated named target. +# ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report. +# +# LLVM-COV: +# ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter. +# ccov-report : Generates HTML code coverage report for every target added with 'AUTO' parameter. +# ccov-${TARGET_NAME} : Generates HTML code coverage report. +# ccov-report-${TARGET_NAME} : Prints to command line summary per-file coverage information. +# ccov-export-${TARGET_NAME} : Exports the coverage report to a JSON file. +# ccov-show-${TARGET_NAME} : Prints to command line detailed per-line coverage information. +# ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report. +# ccov-all-report : Prints summary per-file coverage information for every target added with ALL' parameter to the command line. +# ccov-all-export : Exports the coverage report to a JSON file. +# +# Required: +# TARGET_NAME - Name of the target to generate code coverage for. +# Optional: +# PUBLIC - Sets the visibility for added compile options to targets to PUBLIC instead of the default of PRIVATE. +# INTERFACE - Sets the visibility for added compile options to targets to INTERFACE instead of the default of PRIVATE. +# PLAIN - Do not set any target visibility (backward compatibility with old cmake projects) +# AUTO - Adds the target to the 'ccov' target so that it can be run in a batch with others easily. Effective on executable targets. +# ALL - Adds the target to the 'ccov-all' and 'ccov-all-report' targets, which merge several executable targets coverage data to a single report. Effective on executable targets. +# EXTERNAL - For GCC's lcov, allows the profiling of 'external' files from the processing directory +# COVERAGE_TARGET_NAME - For executables ONLY, changes the outgoing target name so instead of `ccov-${TARGET_NAME}` it becomes `ccov-${COVERAGE_TARGET_NAME}`. +# EXCLUDE - Excludes files of the patterns provided from coverage. Note that GCC/lcov excludes by glob pattern, and clang/LLVM excludes via regex! **These do not copy to the 'all' targets.** +# OBJECTS - For executables ONLY, if the provided targets are shared libraries, adds coverage information to the output +# ARGS - For executables ONLY, appends the given arguments to the associated ccov-* executable call +# ~~~ +function(target_code_coverage TARGET_NAME) + # Argument parsing + set(options AUTO ALL EXTERNAL PUBLIC INTERFACE PLAIN) + set(single_value_keywords COVERAGE_TARGET_NAME) + set(multi_value_keywords EXCLUDE OBJECTS ARGS) + cmake_parse_arguments( + target_code_coverage "${options}" "${single_value_keywords}" + "${multi_value_keywords}" ${ARGN}) + + # Set the visibility of target functions to PUBLIC, INTERFACE or default to + # PRIVATE. + if(target_code_coverage_PUBLIC) + set(TARGET_VISIBILITY PUBLIC) + set(TARGET_LINK_VISIBILITY PUBLIC) + elseif(target_code_coverage_INTERFACE) + set(TARGET_VISIBILITY INTERFACE) + set(TARGET_LINK_VISIBILITY INTERFACE) + elseif(target_code_coverage_PLAIN) + set(TARGET_VISIBILITY PUBLIC) + set(TARGET_LINK_VISIBILITY) + else() + set(TARGET_VISIBILITY PRIVATE) + set(TARGET_LINK_VISIBILITY PRIVATE) + endif() + + if(NOT target_code_coverage_COVERAGE_TARGET_NAME) + # If a specific name was given, use that instead. + set(target_code_coverage_COVERAGE_TARGET_NAME ${TARGET_NAME}) + endif() + + if(CODE_COVERAGE) + + # Add code coverage instrumentation to the target's linker command + if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" + OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") + target_compile_options(${TARGET_NAME} ${TARGET_VISIBILITY} + -fprofile-instr-generate -fcoverage-mapping) + target_link_options(${TARGET_NAME} ${TARGET_VISIBILITY} + -fprofile-instr-generate -fcoverage-mapping) + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES + "GNU") + target_compile_options(${TARGET_NAME} ${TARGET_VISIBILITY} -fprofile-arcs + -ftest-coverage) + target_link_libraries(${TARGET_NAME} ${TARGET_LINK_VISIBILITY} gcov) + endif() + + # Targets + get_target_property(target_type ${TARGET_NAME} TYPE) + + # Add shared library to processing for 'all' targets + if(target_type STREQUAL "SHARED_LIBRARY" AND target_code_coverage_ALL) + if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" + OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") + add_custom_target( + ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND + ${CMAKE_COMMAND} -E echo "-object=$" >> + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list + DEPENDS ccov-preprocessing ${TARGET_NAME}) + + if(NOT TARGET ccov-libs) + message( + FATAL_ERROR + "Calling target_code_coverage with 'ALL' must be after a call to 'add_code_coverage_all_targets'." + ) + endif() + + add_dependencies(ccov-libs + ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME}) + endif() + endif() + + # For executables add targets to run and produce output + if(target_type STREQUAL "EXECUTABLE") + if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" + OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") + + # If there are shared objects to also work with, generate the string to + # add them here + foreach(SO_TARGET ${target_code_coverage_OBJECTS}) + # Check to see if the target is a shared object + if(TARGET ${SO_TARGET}) + get_target_property(SO_TARGET_TYPE ${SO_TARGET} TYPE) + if(${SO_TARGET_TYPE} STREQUAL "SHARED_LIBRARY") + set(SO_OBJECTS ${SO_OBJECTS} -object=$) + endif() + endif() + endforeach() + + # Run the executable, generating raw profile data Make the run data + # available for further processing. Separated to allow Windows to run + # this target serially. + add_custom_target( + ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND + ${CMAKE_COMMAND} -E env + LLVM_PROFILE_FILE=${target_code_coverage_COVERAGE_TARGET_NAME}.profraw + $ ${target_code_coverage_ARGS} + COMMAND + ${CMAKE_COMMAND} -E echo "-object=$" + ${SO_OBJECTS} >> ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list + COMMAND + ${CMAKE_COMMAND} -E echo + "${CMAKE_CURRENT_BINARY_DIR}/${target_code_coverage_COVERAGE_TARGET_NAME}.profraw" + >> ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list + JOB_POOL ccov_serial_pool + DEPENDS ccov-preprocessing ccov-libs ${TARGET_NAME}) + + # Merge the generated profile data so llvm-cov can process it + add_custom_target( + ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND + ${LLVM_PROFDATA_PATH} merge -sparse + ${target_code_coverage_COVERAGE_TARGET_NAME}.profraw -o + ${target_code_coverage_COVERAGE_TARGET_NAME}.profdata + DEPENDS ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME}) + + # Ignore regex only works on LLVM >= 7 + if(LLVM_COV_VERSION VERSION_GREATER_EQUAL "7.0.0") + foreach(EXCLUDE_ITEM ${target_code_coverage_EXCLUDE}) + set(EXCLUDE_REGEX ${EXCLUDE_REGEX} + -ignore-filename-regex='${EXCLUDE_ITEM}') + endforeach() + endif() + + # Print out details of the coverage information to the command line + add_custom_target( + ccov-show-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND + ${LLVM_COV_PATH} show $ ${SO_OBJECTS} + -instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata + -show-line-counts-or-regions ${EXCLUDE_REGEX} + DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME}) + + # Print out a summary of the coverage information to the command line + add_custom_target( + ccov-report-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND + ${LLVM_COV_PATH} report $ ${SO_OBJECTS} + -instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata + ${EXCLUDE_REGEX} + DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME}) + + # Export coverage information so continuous integration tools (e.g. + # Jenkins) can consume it + add_custom_target( + ccov-export-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND + ${LLVM_COV_PATH} export $ ${SO_OBJECTS} + -instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata + -format="text" ${EXCLUDE_REGEX} > + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}.json + DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME}) + + # Generates HTML output of the coverage information for perusal + add_custom_target( + ccov-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND + ${LLVM_COV_PATH} show $ ${SO_OBJECTS} + -instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata + -show-line-counts-or-regions + -output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME} + -format="html" ${EXCLUDE_REGEX} + DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME}) + + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES + "GNU") + set(COVERAGE_INFO + "${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}.info" + ) + + # Run the executable, generating coverage information + add_custom_target( + ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND $ ${target_code_coverage_ARGS} + DEPENDS ccov-preprocessing ${TARGET_NAME}) + + # Generate exclusion string for use + foreach(EXCLUDE_ITEM ${target_code_coverage_EXCLUDE}) + set(EXCLUDE_REGEX ${EXCLUDE_REGEX} --remove ${COVERAGE_INFO} + '${EXCLUDE_ITEM}') + endforeach() + + if(EXCLUDE_REGEX) + set(EXCLUDE_COMMAND ${LCOV_PATH} ${EXCLUDE_REGEX} --output-file + ${COVERAGE_INFO}) + else() + set(EXCLUDE_COMMAND ;) + endif() + + if(NOT ${target_code_coverage_EXTERNAL}) + set(EXTERNAL_OPTION --no-external) + endif() + + # Capture coverage data + if(${CMAKE_VERSION} VERSION_LESS "3.17.0") + add_custom_target( + ccov-capture-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND ${CMAKE_COMMAND} -E remove -f ${COVERAGE_INFO} + COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters + COMMAND $ ${target_code_coverage_ARGS} + COMMAND + ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --base-directory + ${CMAKE_SOURCE_DIR} --capture ${EXTERNAL_OPTION} --output-file + ${COVERAGE_INFO} + COMMAND ${EXCLUDE_COMMAND} + DEPENDS ccov-preprocessing ${TARGET_NAME}) + else() + add_custom_target( + ccov-capture-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND ${CMAKE_COMMAND} -E rm -f ${COVERAGE_INFO} + COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters + COMMAND $ ${target_code_coverage_ARGS} + COMMAND + ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --base-directory + ${CMAKE_SOURCE_DIR} --capture ${EXTERNAL_OPTION} --output-file + ${COVERAGE_INFO} + COMMAND ${EXCLUDE_COMMAND} + DEPENDS ccov-preprocessing ${TARGET_NAME}) + endif() + + # Generates HTML output of the coverage information for perusal + add_custom_target( + ccov-${target_code_coverage_COVERAGE_TARGET_NAME} + COMMAND + ${GENHTML_PATH} -o + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME} + ${COVERAGE_INFO} + DEPENDS ccov-capture-${target_code_coverage_COVERAGE_TARGET_NAME}) + endif() + + add_custom_command( + TARGET ccov-${target_code_coverage_COVERAGE_TARGET_NAME} + POST_BUILD + COMMAND ; + COMMENT + "Open ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}/index.html in your browser to view the coverage report." + ) + + # AUTO + if(target_code_coverage_AUTO) + if(NOT TARGET ccov) + add_custom_target(ccov) + endif() + add_dependencies(ccov ccov-${target_code_coverage_COVERAGE_TARGET_NAME}) + + if(NOT CMAKE_C_COMPILER_ID MATCHES "GNU" AND NOT CMAKE_CXX_COMPILER_ID + MATCHES "GNU") + if(NOT TARGET ccov-report) + add_custom_target(ccov-report) + endif() + add_dependencies( + ccov-report + ccov-report-${target_code_coverage_COVERAGE_TARGET_NAME}) + endif() + endif() + + # ALL + if(target_code_coverage_ALL) + if(NOT TARGET ccov-all-processing) + message( + FATAL_ERROR + "Calling target_code_coverage with 'ALL' must be after a call to 'add_code_coverage_all_targets'." + ) + endif() + + add_dependencies(ccov-all-processing + ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME}) + endif() + endif() + endif() +endfunction() + +# Adds code coverage instrumentation to all targets in the current directory and +# any subdirectories. To add coverage instrumentation to only specific targets, +# use `target_code_coverage`. +function(add_code_coverage) + if(CODE_COVERAGE) + if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" + OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") + add_compile_options(-fprofile-instr-generate -fcoverage-mapping) + add_link_options(-fprofile-instr-generate -fcoverage-mapping) + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES + "GNU") + add_compile_options(-fprofile-arcs -ftest-coverage) + link_libraries(gcov) + endif() + endif() +endfunction() + +# Adds the 'ccov-all' type targets that calls all targets added via +# `target_code_coverage` with the `ALL` parameter, but merges all the coverage +# data from them into a single large report instead of the numerous smaller +# reports. Also adds the ccov-all-capture Generates an all-merged.info file, for +# use with coverage dashboards (e.g. codecov.io, coveralls). +# ~~~ +# Optional: +# EXCLUDE - Excludes files of the patterns provided from coverage. Note that GCC/lcov excludes by glob pattern, and clang/LLVM excludes via regex! +# ~~~ +function(add_code_coverage_all_targets) + # Argument parsing + set(multi_value_keywords EXCLUDE) + cmake_parse_arguments(add_code_coverage_all_targets "" "" + "${multi_value_keywords}" ${ARGN}) + + if(CODE_COVERAGE) + if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" + OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") + + # Merge the profile data for all of the run executables + if(WIN32) + add_custom_target( + ccov-all-processing + COMMAND + powershell -Command $$FILELIST = Get-Content + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list\; llvm-profdata.exe + merge -o ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata + -sparse $$FILELIST) + else() + add_custom_target( + ccov-all-processing + COMMAND + ${LLVM_PROFDATA_PATH} merge -o + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata -sparse `cat + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list`) + endif() + + # Regex exclude only available for LLVM >= 7 + if(LLVM_COV_VERSION VERSION_GREATER_EQUAL "7.0.0") + foreach(EXCLUDE_ITEM ${add_code_coverage_all_targets_EXCLUDE}) + set(EXCLUDE_REGEX ${EXCLUDE_REGEX} + -ignore-filename-regex='${EXCLUDE_ITEM}') + endforeach() + endif() + + # Print summary of the code coverage information to the command line + if(WIN32) + add_custom_target( + ccov-all-report + COMMAND + powershell -Command $$FILELIST = Get-Content + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list\; llvm-cov.exe + report $$FILELIST + -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata + ${EXCLUDE_REGEX} + DEPENDS ccov-all-processing) + else() + add_custom_target( + ccov-all-report + COMMAND + ${LLVM_COV_PATH} report `cat + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list` + -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata + ${EXCLUDE_REGEX} + DEPENDS ccov-all-processing) + endif() + + # Export coverage information so continuous integration tools (e.g. + # Jenkins) can consume it + add_custom_target( + ccov-all-export + COMMAND + ${LLVM_COV_PATH} export `cat + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list` + -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata + -format="text" ${EXCLUDE_REGEX} > + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/coverage.json + DEPENDS ccov-all-processing) + + # Generate HTML output of all added targets for perusal + if(WIN32) + add_custom_target( + ccov-all + COMMAND + powershell -Command $$FILELIST = Get-Content + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list\; llvm-cov.exe show + $$FILELIST + -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata + -show-line-counts-or-regions + -output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged + -format="html" ${EXCLUDE_REGEX} + DEPENDS ccov-all-processing) + else() + add_custom_target( + ccov-all + COMMAND + ${LLVM_COV_PATH} show `cat + ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list` + -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata + -show-line-counts-or-regions + -output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged + -format="html" ${EXCLUDE_REGEX} + DEPENDS ccov-all-processing) + endif() + + elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES + "GNU") + set(COVERAGE_INFO "${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.info") + + # Nothing required for gcov + add_custom_target(ccov-all-processing COMMAND ;) + + # Exclusion regex string creation + set(EXCLUDE_REGEX) + foreach(EXCLUDE_ITEM ${add_code_coverage_all_targets_EXCLUDE}) + set(EXCLUDE_REGEX ${EXCLUDE_REGEX} --remove ${COVERAGE_INFO} + '${EXCLUDE_ITEM}') + endforeach() + + if(EXCLUDE_REGEX) + set(EXCLUDE_COMMAND ${LCOV_PATH} ${EXCLUDE_REGEX} --output-file + ${COVERAGE_INFO}) + else() + set(EXCLUDE_COMMAND ;) + endif() + + # Capture coverage data + if(${CMAKE_VERSION} VERSION_LESS "3.17.0") + add_custom_target( + ccov-all-capture + COMMAND ${CMAKE_COMMAND} -E remove -f ${COVERAGE_INFO} + COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --capture + --output-file ${COVERAGE_INFO} + COMMAND ${EXCLUDE_COMMAND} + DEPENDS ccov-preprocessing ccov-all-processing) + else() + add_custom_target( + ccov-all-capture + COMMAND ${CMAKE_COMMAND} -E rm -f ${COVERAGE_INFO} + COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --capture + --output-file ${COVERAGE_INFO} + COMMAND ${EXCLUDE_COMMAND} + DEPENDS ccov-preprocessing ccov-all-processing) + endif() + + # Generates HTML output of all targets for perusal + add_custom_target( + ccov-all + COMMAND ${GENHTML_PATH} -o ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged + ${COVERAGE_INFO} -p ${CMAKE_SOURCE_DIR} + DEPENDS ccov-all-capture) + + endif() + + add_custom_command( + TARGET ccov-all + POST_BUILD + COMMAND ; + COMMENT + "Open ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged/index.html in your browser to view the coverage report." + ) + endif() +endfunction() diff --git a/img/lcov1.png b/img/lcov1.png new file mode 100755 index 0000000000000000000000000000000000000000..c8e66e119fda63dfdb8c6f453584fb017be09ab3 GIT binary patch literal 125426 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 z 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 literal 0 HcmV?d00001 diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 187a92c3..707b7fd1 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -7,6 +7,7 @@ add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) xo_include_options(${SELF_EXECUTABLE_NAME}) add_test(NAME ${SELF_EXECUTABLE_NAME} COMMAND ${SELF_EXECUTABLE_NAME}) +target_code_coverage(${SELF_EXECUTABLE_NAME} AUTO ALL) # ---------------------------------------------------------------- # 3rd party dependency: catch2 From d259cee0097785a0e679f669abcb5ad854e97fb9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 20 Sep 2023 17:00:04 -0400 Subject: [PATCH 085/170] BUILD.mk: missed in prior commit --- BUILD.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 BUILD.md diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 00000000..29023957 --- /dev/null +++ b/BUILD.md @@ -0,0 +1,43 @@ +# indentlog build details + +## Test Coverage + +### enable coverage build +``` +$ cd indentlog +$ mkdir ccov +$ cd ccov +$ cmake -DCODE_COVERAGE=ON .. # prepares coverage build +``` + +### build + generate test coverage +``` +$ make ccov # builds + runs unit tests +$ make ccov-all # generates .html report +``` + +### view coverage report +``` +$ firefox +[navigate to coverage report; path something like file://home/roland/proj/indentlog/ccov/ccov/all-merged/index.html] +``` + +![lcov_output](img/lcov1.png) + +## Implementation Notes + +- coverage builds creates `.gcno` files alongside `.o` object files +- running coverage-enabled executables creates/appends to `.gcda` files +- e.g. see `ccov/utest/CMakeFiles/utest.indentlog.dir` +- coverage feature enabled globally in top-level `CMakeLists.txt` by: +``` +include(cmake/code-coverage.cmake) +add_code_coverage() +add_code_coverage_all_targets() +``` +- looks like these need to appear before executable targets are introduced +- also need to opt-in individual executables, e.g. in `utest/CMakeLists.txt`: +``` +target_code_coverage(${SELF_EXECUTABLE_NAME} AUTO ALL) +``` +- here `AUTO` opts in to the `ccov` target; `ALL` opts in to the `ccov-all` target From 78eceaab4243b6db694740205e8b75701d1d0b29 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 20 Sep 2023 17:13:02 -0400 Subject: [PATCH 086/170] coverage: exclude system files (gcc, catch, ..) --- CMakeLists.txt | 8 +++++++- img/lcov1.png | Bin 125426 -> 59982 bytes 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7656fc0b..cbfe6953 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,13 @@ include(cmake/code-coverage.cmake) enable_testing() # activate code coverage for all executables + libraries (when -DCODE_COVERAGE=ON ??) add_code_coverage() -add_code_coverage_all_targets() + +# 1. assuming that /nix/store/ prefixes .hpp files belonging to gcc, catch2 etc. +# we're not interested in code coverage for these sources. +# 2. exclude the utest/ subdir, we don't need coverage on the unit tests themselves; +# rather, want coverage on the code that the unit tests exercise. +# +add_code_coverage_all_targets(EXCLUDE /nix/store/* utest/*) # always write compile_commands.json set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") diff --git a/img/lcov1.png b/img/lcov1.png index c8e66e119fda63dfdb8c6f453584fb017be09ab3..4fb14106bb882a87b76ef1b28f1ad1705e596603 100755 GIT binary patch literal 59982 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 literal 125426 zcmeAS@N?(olHy`uVBq!ia0y~yVC!RGU_8sg#=yX!@VV2Lfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9R^{>lFzsfc@Xmvx3{s5JYB z>F+>*ja8FXMTf`7frU9o;An%th-*m5Aq5skLB^L;rc8SG?%kgIKj+WfT>kFOox8hF zFWUX)|M6nEw6y2@~rQK#wpv6F<|`A^LZUj9bY1qKTJckxK71Yeso$;OqdnoIDg**m*F z2@9pJQ~{G)J5!sVoQ(G{N&zvlee{7~pw3f1 z8N*Q7K%M4kZX8mnC+AIeguAM1bHMgiE4?eF3(s|TJYr+(>qwGZvfSAlu3(WhhR8_cSbgr1U^LGE6WNb=K{PX^E=zw6L%+{2XLM!9;?s{@&=H<;_-rNj6H^(yh zyf4ftBDVj3-~a#Q?e_cAw%@Dr<`=%Z@)!RPhja6+)#G_2b?oN*v+@7D^UwQ_(BnpB zmj?nq`k}yNHSBt8_w$LcX6&w#8+K{mcK&!UJAdEAL#^EI z6*WhvCKp^>Qir1&&B^gRynJqqod=+{)TC8`ulz?(#t7zxwtj!Yu3*1 z|N0WYKAtFgX7{J}``?EDw-(chQ}Va_w<2U!faCxD2^W)o>wom_Ve1q4QSs!X`qS_B z%WelJ@#_dr<30T&|M%bi%%b?;enzRUOm;qhx4RS^R&D!xW$hhzeS4w#SzK>ZysOB@ zzrVk~J`iwrmg!;9$Mfs|UHm-9uJ+bEA=CYTzs>&h>9qc)ijPT_rLU%htceJG7xp{% z=BCtA1?6S7pU)WYS~?}TQ%Lp6_4xX&$6fejtyDZGtMvv?E&jnbS>1oz@kh%Z9qqpV z?fnG9WVe@hc5YVjpLb_olB9LnnvekdYb#dd-Po{@PwZab-}hm>QYId!rt9bT|Fxc1 z`|W1I@iX`7yb2=P>Uy2l>I-3%GvhTggll*h@dC|K+ zmA^w>4A~DVZxQI~dwYAkcOw()l9ZE^c3pK@9jq{m8NJhO*2@n+Uw1;ud+Nf&tG3(e>-_&xXXP-k%e{V z_f&p9)gh>?;ycUan+P{k``YO3*AAbz|Gy_s)b(HTu{E=AD46L_{(MI$Ja%{4S-D^3 zA0<>kB~#b@Z*Om_*Z=)G{hVI|`{c_@y_a)0xzA|ZpD4E|K-R9vCGN$)n25g>DNB#q z`hLyMTmJBVFAvAD1#*g|tFHXYe^&qezTyA3Uye@jKg4>WY3joHeEV|w%Z_4=z3%z3odv{g)nWE`=j%qB$uc-(S;u&|uw{Oj z5XA9Wdc~TYJ3BTm@tJvP-lO#gO6H|cc()?qVAHQhtfzag1s=P)I{fSR6BCu&RlKM9 ztO{AFv^o9!w*RmE(@pa4+1!m%aqSWbS|4X?S@B`Pys&jKmVZ@_*nYnwtk-%=zW&d` z`~2%q&bQyc=hG?ehnJKr_cPmZpYFXfKd#IKB(+TB%k9{>izoaiV zz3_ZK`?F}*3G6RMUSFLT zUcrd?NvYYEa z`GvN3eagJNtTnf|e3s6d==JYk{*l{V{{GtO{%Jm~T%wmwziay|_Wt3W{EPiF5-%y$ z{d&2)Dq6W#`Pi)0x_sduY<^SKBef`x_7fG|68UJQW-`gIxHma&}!LQK$Nsq8V>LJ!s~CCDL^6{ZqTN57n2pW{2NBE_qM-_fdcQzf1nJMQ_iW z`up8(fA+?W|321k*z;g3|GAmQ?*DnMN?)nu-rmOhqvnmbhq+nBhlFacE7LjsS0q|) zkXM$tv!}9nZ@sh2>6Y{7=2~yB`F1nC>dt}kBfH}FR&BLaEtu(KS+}y(+d< zUoQM++a^8j?Ww8SzkVmrO^!{pFZ^`t{ha6CoA2-a|L^y&uNKob@Rq%~u`v4Ij9RJZ z73HtCpZJ#P5M`G$J7i_h%jCBy1hn$*h z_VGU1ulM(CQ~xHM<6l$0*;ep{8YoBYy8OV7cV=(_Z(nxC9qw5@W^8SSy!D4|W{9sp zxR*I_#j&2>mTS1h)qR}H*41HH!gDha{q(px;r zvn*WT?CKd$_sHg17NkT;U0oL%%$}BHEo|eo;C0z{8>!!)U1BALbuw7w`G49ZSO%^B z*_n5Be*M3d+Ajlr=DP>BUSGIrQ_xbcUnv<}T6>h65)Pc3YhAj5v5_H!WznI6^Yd(f zz0Ww;^RzJhn=aqssx9}<3;sEj&A_O!Mp=jZl1q|ob*}gxK1N>| z;|kqts{8(Lzh9>M~n+yhP?FlyiB^P}%abu$}p$ti=J*KWO1t*qu}3m?X*<*2hr zeB5dO??>{DDrT0Y0vAf&>7PsGDtn`FqH^^ISwWGb`+AeP9oc2fcQhWVWObagd|s7S z!u&(`Ki1xP?mZ`;=Z*Rd_TO_kLzEag9vA-n^z>Iu*JHy~zfJ6fe@mU4&T;5L8h@kK z_JF>F{PuqWetmzx{(FDj-(N2u+-YQH|8jprt&%lcVa%1a(cxVpnv0$v+}HZH^?gIF zNTW1M=7t)MHHsIy-u5>!{<&WYDNP4W{_uWIh}*-qc0z~K z*W*3*Pj|}MGB>$P9NSX)YTxVoEjA z?mRl$U29qVY|HUQ&;EYD|2=e7$Vs`)E4W$j-_GCvc6a6HWpe)0_2#~RKEM9j;m^;{ ze^>RMcBcH<8A;o`E9>L$nA~1ey*43KL>F2LKb~`yqwN_Z&Z_DwTeTUom ze@{~Jd}Lkpq{H^;b7}j!J?njD8hx8_{`&s<`uJB@R@N@}pTBMSj~e;&;_{c`L&=Jyu6_sdn)JUrC8kA+j{$FsAummg2OvLbLr=QrKhU03Ek`phe9 zbtQa7fMWHT=h+t)G`_zY9?u)i-|*dIp3Tnp$9ko!WbP{#K01oZrYN2`IvD%ex9yhRX8kStyIsVtlFYsQ zNfM_UY7blbPuGjBDZg7f-8SuDq0B3zt81gf-)}zmK4r$^N3YlK-?qFZUadIB;`>S^ z*RGaa}zXg+NSB&Ut1GdyV$+| z+T$DVH{84Xd+z6&%yWe|^m`&Vr@c(hyuYvZo5=k9$H#gD?=63Qb@lV=FBjdvZn(H9 z)w_0Hab5q3KF2q^Z+xG-DfRR-Y3s5za(quE-dtZlf4y6;RMm|gH9t4S*?UjZ*|_}2 zmu>n13mW3`be8X0xZ%IhJj?BmKlkqc|1bKzaXX*vrN`P~Yc71AV^!+aFP&Cx^{{xO z?b+|g{{NVlRz2%;xXbfQP-VAh2gCQo9oJ=z(|T-Gi+21wo;~M#L0rJ|r=jAkglWT4Fz`E$khI#21CmsD|dhUD2%O(lOo2Noc zU*6k1{e4Fi-};{c8*FC0FFWRxbuC+9o6ST~ooXN5)2F6tGoRAkYT@Lq{N?oL<6k6$ z_U1J=#MB?;vdY;NyXaD($TZ2*eeV~Xi~eSPWKHhv?cNs`wZ1i6WGx@Wq&Ss-o}d4O z1M_e3Y2LpO#C%+8o=p6%l9hg&Qx@o}Zpk@tS(7a);sIyHnfwLy$~GV0wy0nE7_y`B zOK3%v?1y;~a$DRCH`r8ov8|P#qZPI$gTJ$Gk<1+b8_BmWE_Q!w_ z>x6^%gi}+sZzoSnxX-AY&9jBa!OQCVC#(JH|Jt_X+=yd~N>Vtg5LL(Wc`3ay2y}S~+)W;KnN8vMX3&v)B5#y(K^I|Nocn&&&6D!BYEY$FnYckJ)+E#Cim`6BD;cXPhTe`x$W{r@r9i^nf= z-`)M{|6EH3W$hnE+r2}=w5CaZkj=Y(s#j~tn(QKf@9G|ncRMRTFI#7DkkZmVn>}G2$IH8SL}#pUDLM4#M~(XW^QHd9Y%FK)-?=>JeRtxL z_M&=!kzmW0|M=R%pVn%e&Zzl*w|v*9>Jt+bcQJ{~?+o$bu&_||nsP$!Q}KG~@4t%s zcVA|e^7#4m$-kU}`tu3*)o+w6(RZF@{l!vr;)#9Be_J;e-%g5qv;E!Mjz>9Z@~3|B zxVpS%oG;1sCYod4tYo!K*IPgBi#z>vPMb))$L&^;6p!fk+`cK9ZNDx4ZJ)-;$a3I6 zN6mu&N{9FQER?f8m@s#7zs!>5E{^r~ZN>AMbe3N?*?hib*ZrOS%75;57gw!#FMIRj z|9rV-kM!qT_ndp667*x?edRUoEG*6s|Kx0bZ!ukW#)>?DZ~$>gx3{?K3MOVN*S z-QoUcR`a94R=?Rzq^s-c>61;a+;0uFD_R@`%M3+$tmS*=>@QdtvL@i3+-}>VXD0-w zb-g=zTz+b6H}h}yf7|a0*2-+%v3%y9pIP~LtDZktcz7Q7d%f+SPq*v};$NA1)F}Dp zN7=mTO0C?dudTiPcH;@%h%FK2NxmZC4>@zcL_d7jU~5#d=x!uqH{Y9!`d!8ehV}ny zVt>BQ6BHKQBH%eqXXd;8#}6Fk`_=1cud$u!zUXP$H;+!%us{F)Noa2BkzcOvUtVw@ zwP|d$^I3GLX5C8-xeq&6@R%$8;yahy)0O&VVpACZ!3Vn+EV_5Iia~dCz)$HnrRVHw z7IDw-c4*&xxqgeDqkWiL$@ggUkbuQc16(%PWE4K1!+%>&^!xQo39zOH7(1S z`?#gF`E8Qcp^vf`J{{cocg~0MH^CVPABw%Q>zEdlVcH~S$8qVwkCJUaI?fp-{{Ljv z<`k>O(syAM$7_+=xruj9?)BMT_2$9vMWwx(8L^VFKmMuv&FT15*Z!FGx5=+=;|p2* z#}_t!@5`Bgtg1xrf5YP&FYnv1752IBPd}&-(fhW$uK$9(>@NZCtxF>e)K-YxEc6Bs zpU6MF$EmvLb;+NzXWT`)_}<<=xka-6)IsO=H=1D|UbG9|fANS%DpBsr!}1;b*V;b) zcHsG+y=lFA_j@E%pPrt&^}o>myFm{)d_KIm``v!Z{r@x4{CoFq==pnf)4syl&29nP z%XB5p6~FLp-ZaTxEe*VDx^-5bYH4( zm1mxIX2wG8K5p@E%d1>imle+oc;NY0&bI1B-&w&Yj$P_K`FD4P{;${m5W>4J`1`xN zrN{qP_%C_q#Qy5RSJ^!->5_qoy%vG3xN|DEddCiu)Wdif=`!t3?b@c5~g#m`P`%f0<%=ks}&#UHEvNbHk* zUUm4Ba&PqRvR6zww@miRY)(6S>9}G-baLf{yu6>Eo?11uJ8*AnE|z!6a@x%QX!Az< z+2>hvjBN_r{+^Xw^3keKIa;kot}VX)Z|U4~JWntC+h3JUoRxa${+-h;|IZpdJv%#m zzW;~60v$X4|NH&5KdM`gi)a1lki@(vw75cb)luv9gc<8iuPsF+7a@9II4_b=#f}HuJ z&3xW7do29<;V^$YYwZTP3AY3qj|4nDIoX{(xBma%^1b^ltW#7$Wr))2ht@VOFZSq{ z9J)WDY?eky#+AT@HI^^`{+cbwrdn9vR%xIgS8Q$j>BrH$SIW=8GY~B0>P3!``6w(dAx^vO~=Qk$`4x# z+RJj^Xu1^g>!}2s>^@~5Vj->_<`XWZ%+bUZ=dfQo!?dBR^uV7C*C#o-=|Oue6;}w& zR@s+W!Ba;P5+(<_pxYf0^3!&x1j9U7Y5< zJuan^f@_>uHMNpA#;NuXp2Cq5{RTPqn**z@;U*!-wNcAe+%Zcguim%P$vrjgZK zv0rM2bAIb;E!q3+c7RFtHJ|nRZ=_$`PCwEi_$~g=hWW}JO$wa9ybqQg&$j#dWby{? z!Zp!**q1$4l6il1N8#fQQ&JF2JzX8LWyf7Dg*?i25` z-`t-t@5HyvKW}@@?_GG!TdTJB_q*MUuOHpFVcXbS;N0~<^IP?nAg2Q&_cflzv*XVMHL00= zKKECgP;30nB{F$018AgXx<-in-s|xKuPdH(E>C&2<>j{!`zsIa|NNL-HLsER-qr67 z+b{p*7EgJxT>kW?*3T&qe!qWtrS$*O8<&m;HhE9iI~L(_iY3jiV*7rR70=&auriym zJz?UP%D=t!OP5ZZ9I0-*yL@ur+uJvTnH4j>oP6$_U;WCaOWJH*q^9U<_qsn1PF9A5 zEM|3dIo2<~UixNVriw{2{%aq17NpmUZWP_e ztfd%uGIyVIO!7A7ea>66uD)3r7G)Z;Cw^Cn=9)=X%NDq@FsZKi@%Pp0^(79Bj9YHk zHVWKUbZ9Us7#LS{taQHy#uY3iKW(E0kQ#m#rZ8_M?{uw$_e0-Vz{B_a) z7Ta<17cG3i=-}|JM?AhJQ2dJIm)FVq*(77-s!bG1@4gM%o5%d~&*cA}PrF3lY93r0^!@I6+xx-O z^k!5azpI@Oo?ttY@qj~Mf#+nktGW43Vxc!yJUE1nOs+dJ8{=v(S696<`BU7a{a_!rmsOKP6X{L$^5&$!=S(= zZ-w~${RI0rzeggo-}Rl}S*c^7S;FIpNx!?9pgGIEcN&#fvuAe-?FxAA>Qcze z?C!GBXW1Id)cfybi{5;2wCi;Qt8j5~DHMCPE#P?TF1;(2f`NA?Jh-&9d(BL>u2jAF zT`KB*a#M_#``ru%mjxi=k=zy&rwbaDT_WE^l)7@wa&BbsN1{5rYx$i<C8ze$9t1JPaXVQZsO`6Fkn>H|3lhE3Q| zxE{$5U@~BOAf>mk*d3Jv4}B|fZAd*Wc5{3FeA~2@vAef{Chg=PzFxE==jy7^ZxdR< zA+^XN=l{RIMu~@5s?SWaF3-!nzHY9qnCuyDJZxIx zJ3FjPL{rH$>&gT%-6)S;B`@EEvy?wQB^tRUW1>#P1_!hJdu#5$zO>YPl3}vj-Zi{Z zCKGnQ-*@}--h!1@DJKN}?hoFccUPtG(UETv1)wQc8T-0Ba+^!u+z8y1em<{1Fh$BV zOQrbPnT^L?E-mp?R`;LBllfN|Jgpu029mZf%08LwZ#OY+Zxt&`*sij-TJ!7w?X(p$ z-Cg!}QosGb2)AA-)#vBtZeCvH+&%gE{Q5Y%KOdZ{y%rd!pF8p3U~}q?4T(ixUIbRJ z+Rh_sgsUS+FxI+E~J~}-U?afJ3FmkFtDcl@2}F#tE;Bk#YwR!#W$>lN?);T6mrj49S@-kP)6MOFE?m-5T5-UI;Vh?aiolVi3mPS- zr|a``NICAU`uavuNon<@#9v=t8dZOLvtg2wE7$M!pbRJ?Zdd@O-4zpBN{aFV*WPf~ z+WGta{&@CWy|_IY{$HJ06aM}Asp{S*^YGH-%Gzrm9v*%=uln6bo_7mU1@CD`{I}qU zTX^ZBrd6Zz9{x*@EElGR%`{4VW5{*%&(F_q75BejQR{qhPBfU`KtNDXF!0Sma6uF( zv$gDP)ZObn!6zrFg67)3MLfy7vtwZ}&)-j{^}mVi=aaR1Vb^!z7l-B>J~&etbr8#S-)SLWY+elLnM&(1Qfs{9z2k=SBV9ryRip6~an8K+JN)?L8{d~9U6ZsnO^Fio~oVR4~~hLBX;2Y`)Gx~ z{ojzdiifP#XFlC2K7aDULg%*|Pwf46EBn*G-|ufHPn)6{d}@Yaa*2bclKtN=legsF z4x6Ovz3lkKL+p;M<*S!AGP74LTfn@9$;sZsufm>Xh0ki0_3v+PPWQjN>V&pH$@{(E zPp#koFRMRN;7t~2(DvJX=d1&u`Imi76W+bQu+X{a-=E5pGYl6$IWsf()wQ*&_q+f6 z^z>~wi&fp99e;j2?%$Mfkm=@@%*lKw6gk@eEm#%4UXS1Q%Y=95HH|XvnkF6L*vs=` zvR3)KJG;J0Uemv(8`TlJqu}7Y=qK-XzrS``Mu(wYtRUjM_jJ9hjczsSd)P0DZOgwO zH+=@zy~MeR_OY8%I^)9k##j`@6eU z^S!5PO?`4|s`vIK)vs1Aw`rcXe$S__Ikwf;f_=zS|1TmAjrR7PgD8_8ld;cp&CxZkh)z1Ht)N673O z`4bOa-nnM`uCoO_mX{r-X@z?2Du1tcdt2`0_51%t$2i7Zido>9m`4k$-|rRYXJDOD z`1sh(`rbQTqS`f_!fHGfwM{IXHJ6w9Zhqb|i;Y)`Wsmr&%l`J@SrJ?J3hnT9Jm00J z$Xb`(DE?71SU(ADem)hCZ)9R+ns#xu&5sAo z5BEL(`T2S6-m0&kK(i^IP0xLLGTHyvy7>Kh`;9KVyu94@yL|AgtE->SHqVdS@$&ut z|NH*(HU9hcT0j11m+0ZM@AY`4&A!aFEdN;U$^Act)cxN4lsva7_qN&Z z(7N5_@4s!$xp}F$F5MF}0RS4OkAE7zGH7YT&r?%0g-hh~@9n8Pu&46VlaF(4tFQfA zoqA4Cv8YkR~+M4zA*}1u|PtUb3Kk%hT()bssl!?E* zCUSGbe%Fv!*Vn(_UGZ^I-CXH?)&Kwf{rc-umF_;{zUNakgV}uczh1Z7=KAe_e}8}d z_|~rPu4?|hJ^RkiHov{TYuEaHzqIaDKl=0Wh_HXl?0+ZK=igYrDPi{06BCv1)VveQ znVoxclj@y4wZFc6{QCO3{)?(Jb1XOKKR-A3n>EX!DjB<)9s1tWbmpxuowh1;^{eC) zr|S{J!F?Ldjh`mZ8^Gi|H4{ROW;6On#+?+&!3)72ah*x{8>{`Ahn z!|iV^mD;*&If9t$9N8@8<*DjHV%akKJQe7Pkb8l^V_)jiS(jcMXZ)aV_`gXah6UBAuno(Oa zc4WrA-wqnHu)F)2O}mv_{9EkKqN8=CS9Ub3+z8{CVYPhbrnIwCe`n3Ol@{lyz5emp z*mpah%l(%9qZhyLP4?|=YoCMM))-fC#^U+u>H722Cs;eT@yt88B!TtdhJ;3Ua7#}X z(y-jcyg=!4tY!Oxrf}A6(|e`O+p2A&HpVA@AU^4er^94vR*ROFmtI`A23l}8) zJ}Mr6<#bbN<29`e&Bg-_moF{#u01(foxei&nmv=_{Mv6b-_I?-$GLrtMz56VruzpU zZJoa}T5w^iMAQ+B=Z*&suB`q2jj`VSU}4Jxp(y4@yLUv-R|t6YOti&-^*;Y^-l*dV zduKmpWVB%E+rR^Ac=4@B{JSoG|2^~CUnTL+&&@r&S3F8&7pNM2`0Q}qrKR5D_p9IU zUB12b_xoi!k(-XxiF1DwFW zY-(6LpX{Nt(sOg4@kPySO5R`o{+`u??rAyi_A5KQ&eLrXoBHl2m#Eg0>fdj-f8EBr zjaOhv@u8o`WM7ns$w>eF{QSD^->9uwPqQyA>Ezq8v)?nv*{57=iw$TPYtfCfk|s`x z;C8zPpVKRq^ig`GUk+HfCVKn1dCC?cY`f#1i;5I& z7jkUfVcfB?^!2rZm$$V-RtT7c-rmnU_4hlkNSm|$T~+2GLH!bjhvYU_us++sJ9mSu z07KFF=W7cf4?r_xP6Tea`KCH|w`nuqp~99N6Xf z+KAaP>T?uJ$3{P;riS*m#o# z+_*fM8U4Q-DY8CX>OK99rB2*){_<}9^~EAwm#nOUnHGtzym^0b)Vi%17nP#+D}$P* zU+x#N_wA`Z3Yt(_6u~?9*6ypT!}T-VKj(pJxAs35G;3C@FF&*?W>3XMxy?^bOmsdq zMKigdb$iLnpz0Irv#zfCHbLGhy?j^U<2D()nj3P$FR!hg{Z8VZ#|(po?^f6cs>uGT zo@toeR<}QaRrb33(Vw56KRs)H{|IyRH<62T|M<@|a`l?7m+SxW@Fx3TFBX5Bv9(Xl zZ%#&kq?BpalKYo6LF?1D=fzf^IbRZ0|MOF-q(OqifuaSM|A6}LLCbtH{RKVeSZqvJ z|MvCu_3iCCwZFb_Mm&FcdHMAG{eQ#u-_tCAcjwy#`D>mbpe0tDil6&cpSiTNI2|0k3b)+6~=^P1rl+v+mgp2xgINx{QZB+4pbf7`M6!aZUPf4*NtEu-RNys>Wf!}uAZjiIq8Vp=56oS#qNG% z$lYhGvs`#vZ*{eMX*^R+{Psnz-Jnk7(!|4UiKn~IuL@Zibi=Gz&idlrwCL@5Q=8fO zZzWGV)XM$({p%QY3$;SOa^u&3?(8hSv_5`+L+T+jDchOq>onHXMb*LEPYg? z4;l=AdOf~=YSPiJo53!ZmU^qJdQG`-xc>j&?Q?9a!}z5w-YxoU4PKeOk(=2al)4Ie zw7&0Qa(~zLH{rvt`hP!<%YD|4-nPb8#5DW*x~=Vh!1KtiJO_oho8{hWSzS@W-k0$I z-``*VKR!Nw`pit@uNywT*?it>s#fTmjVl~k-(6Vf+$@%UKucsri+$CX6}D-Wzg{kP z=32w3b@gss{om5_r*6K!zW%mz9S7gRC7zQH>HZG(w-wb>U^v&%@bJ$5ZMnDAE-&}r zeq4t`DRKAn^YiT&Y{|WC7Sp=Lc!8kgo^PMe+iyRvb8?dEWXEQycDG-Y2{H zxX$bA>-o3e3t;1u$vFS;c}#hnBL|DguCljT{gtuZ-b zCcD49vU0MXy5F1)&$ms{kH06kY2SM5A3X^Z!XFrIsy&(gJL!Jin~ld0t>vGxI(+@D z;>bmt^d;jQCnX+kW3633<4#(f<7&`&fA%oBXFP3O{;vA#E71VXo-nTW z`+l#p6*H}nU%y~ZaEP|s-L*UhJ+V(d&1do~Z2p#`4des3_LWH9tQ!h}jmr z-}}97^$)(Zo10P@8)Y3Pu&mv8N8mv*`_DU!b|GgLmrk7=xo>{mFVAP^=B{pMeEs&c z{{Ah;bt1~&EntoMUa@w!ar(I%#St6wt(yhn*7nY;|5sUkLb@qKR4e4d+QWAaPUuiD zNU310u`YR$z|R`BIn8&+``0#Yd$#dE`yM5)k#}Rd5?5YD;d=8u>`_vz!jo^Gk==60 zuxpxa+@0f!Q9=)6_~VX0VCJ_;;AcJ5%=GSQxt&IX!v<>xP@&`gYxV=toFX=f&W?@_ zjdw|q8nJKZ)#ZEcigvh#Xic1ZN0;HiYtC}>C0xb&r;E?qF4va7+qBif>DLNocD@_I zI?e3-eBm4Awbn0~BdnFTI&^hfe=A!fzk0~AS*Pxw$ho&ClKuFcfX4Tsfqe{emzG#A zRPFSPe(J~F@%7EsSDb4l#B`%l`XjTht&yDIcKYw!MM~b&bgXnERtQ8C9RAcIrSl=` z+O4hG)%)buZn`teG&_y|r{dNb!rvU1ym5ME^xW?6z3TU^x6AWW?^-sSKj3ppkY3mt zY{2oOC6C50$K~s9B#VX2+xO?w>2DDV>kkP2QgVvd^Luf6aqaJK-y*Iow4bNy zJ?%t%{okjN0yU1awgk+ztBvxTXOr0hV0a(5cc<6LxIx^_%%hvpL*8Kj9 z>((>HTqESZ8?jo?n;3LSHYWf2y4VAiXZHGSs8!-V@lfXdyZahi`<+1rhsbW|@K*Z* zrNW1YTEESR4~dddEO;{2kHb;oyYLggjLs%8yLSn_;oi(kmVe6H%lJb5MC?Mo6&kMD zBKilJ+|Nz()eKs4A#=x~S=&x=9@Gx`!LAKjwDz2*cXPfB^UB*7j{6wA^Lu@F0^jM} ztE)mmb?%L1u`OMOqGzY;$6xzzt$3obVUjRY=#67}@BV5h9y)NFW6PzkHB%+0B_8b( z{TA_J&$WkhEQ=3?u9A++l(@U+n&PiXMcW@a>{{2v%6%)j?%e^wed6D;nHzQAoPT#s z{M}c!g=La@9Y0>KCZ)Y&P_z*_`V14 zggF~!w>&D5)3%rwSNk=z`i#(2h9!*-yP`va0)zxXgLsfFM1e9*`?T)JE?S%M=jyPvCHJjXgp{$*on@Z? z?j{%e)HyHmS>HDP%Y%!z2{}DAh&n%G z0r#beJEL0^4m52^)-QCvfPRv++nMfcEsr znQz!%|K+0lw+IE6r*jSpvz(hV_1lUW-?KQIMY?WoPTzi9r~cp1<@eh1GS;@`URoKf zesZ>X{*Gx;fw`8=3F~GT$2%Vo()~AK)w#2O_bt1xqrS#|O5)+Rmw#6!9qpR;Qva@_ z#`;>B-;=CURib_@C>8mofB3ob0ZE+-iHR%NJoCPrIXApryZzp!`{KVJy|}pe>AKzT zxXN`DHS+q>m+UUt9&#u3|PT`Wytk+K9j<4&LqjI2O(W8RSZ9I;?u~SZ8kFU?&-~9B}*6e+so}R8gCmrYs zTBUkvsrR?tKfb=ae7yMI39m&ioi)ttd|U3T?wD=x;oFg z?B(t4>z^AfR`Ho}VY)@(qYWS5+}wP7{ioF-D}xSX`yAYL`1Re(hHr1@@825#_WG{U z*9D(?U~@7Lq&E7xgHnWXCdYhBFFr1O&Zy!H1!`MGOP<>y~gW;rib$L`*?KH*>!}!$;4U%USF0m8FVpv(Wm0u#uYcv< z_g$jeOwT@QS%fd~pKq5SwXM1Ou8dWQ#+%J^S&vs=T@_l}D`omAbWOy?=~kt$8uovG zfB$}6`-R-QyG$S01{Az2dVfF9aO>HkXJ;fo{7U#eVfUV&&t^ZIwlREt+`P|^Z09}~ zNw56#@p!Fy-klBi4>sLr`(6WTLH?JD0WDwOdoK3d`}_Hjjd>eo-__57P4F!7oozNx zv}B@a$c$aG)@457XR6N1uQAEEaA5N!(Ww*XT9<#T@!imrz_0bdIdn%s;`#56Gp)e;O5w5T{@n^6S{C$)hkRq_p0Z%Ur+;s^-{&*` zd$;`l*87SVKppA4dmUU_mljLk`Tg~JyfTlB)#+zvXTJ^q*(+gq$oRywP_6KFZ+^=8 z9q*U_zUIsEbe*_8H|Cwby|eiFqMAFEtnZ7So)R_i|N82xGEakogRo9R8W)oY$1Ka` ztkw5BnAka1fR-rc7eD{9%y)LxzU%$=|0Evndl@RG7n8Bys^lW?q$5YnZf{EU-ch-$ z^!2mT^X=<*yj+$bf7t9}(X%r%Cp7=JD7#nv-uCy@M!A{~2OBB{OAdYSJu^i!Sc#|R zVGVd|V_~~>!I6+sP~B44vTGXm^?nbHqUYz<250X~JvS$EnogwB;dcJ(FP{ssyp-n1 zd@;d_vv%8p&DHCF3aR<52wwa5*X#8`i`{t7*Eur0yaXDOn!ArL^ZSMTfE7(kS376z zy>Um=`kH*u7Dd@v)=#H4?kkwUcTT%iVcXeDOTA0A_8*b^`2bWxlgZUODJ{ zoNWCPb>p31#rbWyw@>XVeXUaY>B+Z{{Rx??Cs=XczN3A0M&rNa33czkUXQ#Z%kvLdi5wt8=S@G_s7 zCA$o^uZ!LN>aV?$1>3W8bG7sL{Y=}D`>?acIf6ITW=_c}Yv^zHtZbG84D?2`}t@8;%{W4zv^ z)FP}fPXp9XJIcTE-v{$0(>^zSnOt#xo^5rTw{vEKysNys$H(utve(}XX0BZNj{94k zpGSY!mXaHM5n|uVdUNW*qX{>385eneGXR%#$uF!kA0O-8^+-Z=-wGDj4Qx}la@4u7 z{<`gus(MejR(&Cpv3sA)uFqc*4)*_Gn)=GR{M{7e^m8w`Zmo&j{Hm@d;HT8g;^*g1 zt_odUa$nIr|K5}yN#j@l;x5z&thgXA&}8sJo`Z3M*Ho>S|MQRTtNs0DU-73Wp0<4o zOyA}@wQ^OmEzV=TcJO}v|Fyr*JH|(HNGMuFZOI5czo6yz!DjZa`#MvP?(4X&{G)MS z&cECpqPI6BHov*IH~Kw4$C||1Vj2Ms(-R!0L^nPb{Cj^vzV@5q8}%FJCJAlhX5!Kg zTeD$#gd@+J?-SRie-YkN^);*Zor8Rwh1-SuBEOy&LWau+FMH75|qx}jqvACOTOJ!X>-JRF_s3puILsmFmamULX)i$v_jt8J{7Cg$v1Ko}sxMe{oPf+}# ztwNX7l|&Vzgcq{jzP2{{>2dk`E19q67~DV7Df~G1wfGwGEq6-pRegVX+5KMq|60f- z$cz0)4}i@R6m&fe+Q1XLt7PMGrSCr;_n+R7cvvO#(vojeemsA@e*d*vW6S)#%l+r; zmEW)34q3VY9#cxP%QS-+ad+Z0oya79*ELaFvy76D@yKR$op)58VV)o7aDn5m#MO1N zw;{9SU9~qJftvFj9UV?ZZ*Q4K?kZV%X0CNOXm1hX+-#E-T z?`J`C#lJ?V_rcVomi1NBH?{9s8@2V6+@=jjA#R0|=-bZ4OhRR$Qef)tO|&4efwa{@ zWh)p`{}57yvO@{d*52V=i!j~`ue*6^xJ|KU8mjt?Q(7FyRC5F_t$$Ae-=j0 z;gQje-4!BN_akv<#m7Z*`FD41^_gkpI!!-bPgvb=io1Mm$Rsu2RsY3;L6fPVdjI&L z-8DZq*@~DeUT7=rm}H#pSFHsOWI@5ZFNM^6G&ZN5-E>^%gj>_g-{0R~f2_a%&nD0S z5C43-+Nl3;KRi5KHAiDt)|C~4(-@Dhp7Hnm**DGYe6pLCyS)2;zka%sYgb4A$_R~V zk$WmOn&jV$F-kk5u`+1sB%{<*C)nj{1j4@ieu?jx+_?C9e0?l?(Sq3BWk!{sQZg?t zY7JQ##1KXAjoaIDH$UHy zV0BNu{N0^R1rME81~2bh;xWU3IHnzD@%)bO~xBR!Kdu{{G^kGncsDn(K`FvL~zgGU;jf z&$UwR6js0XzWsfs!jAULna1gSzyHYB|1o^C*^oy&eBBlMZ!_AuF9g&d5dT-}u{_?o z>eD1S`@&~l5wmvitv_?+a>CzjlRy1o?_L`A{AAFsvlT0Uo=AE5@1T`pp>>H`Oew;>?z}i7Oxb zt$M0|J8#dwKYD+kbrwf!6 zndj*|JvDXm{(rx`uOI#Q;V?gFggW;4pM2xecP@o`1ugQuKR-Xeovift_xJ7XOo|5{ zwjFQ@d9atAS8B=p1s}Q6w&dTB+g@N*{VnIleZeU!!`9B~k++Xy&)<}CQVCROf=0pE zS6o{kzy5jgp_*PP(@TsZTVig37R#P~F*|?X#^)VYHF`~%2G!qk{z@LZu`&7U{|Nbv zxuR$8?X6y#bhOJT<%Gb^jmhnORga%EF1Q$5epmH=?f1F!^qt#yem!C1Xpl_%aimk& zYOaFC|9cA@nX6xXo4NTKD7sDet)IC!FDQTrB!u zW~xf3@TsGxucy8`wD;4I+n-AqG**3>wfxuF>5ae^V*N2^a zJzw|w=Tx8RKCi;JMOEv@R=fDk`^LWNU&Idg|NXH)_O-Eo`7mMrwbu<)n^JF5h24s^H2Urc2PEP25A>dMOC z*G=pTJ|=9GbeC0lb#GJJ*;Vqp-d$TeJ7!0L<9@!c88_Hhhpk=p{UE3h`Ld!z@}Sz6 z=D2M+k#i&4HMZ@l{JiYl>i;{R&zsE1%;vE%>1au}@|DeXf4^Se5R24RpG($w#mnMYS%3BpC9KnMME&moaemV?=?1GE;#QhbXgg+H08m8#$A3A zyn+`b7{2baxaV_MFJ@PXCwP6%_nM!dPJVcJ_-pn0h>eHlDgQ}dq{wnqw@|NOOaA?R z8>U%gFa~eQ2(*>q`t!qu^_S?Oqx`duD)Gvdl`MDZ6ng0($agPrvD?Y7udhE{xqRNF z)#2-3$!l&guqt@auqJkQnEV$GgRifyYR3q0eSXZ+XgBNGxw+Z?U)d`PHdse%FEkat z$IM#K{p{m$`Ro6acM6!> zd6!o#_$PnbCii5VZOzYDyfe4HX^>kN74_F4#as3E_qkIOAFmZITg!Db_2i4{)Q2ao z87-&|watA!&-l~fD{HG}fa|CZ4Yh}jL03cpc&%Qpb8JE-wLl@Z{T0_NqWLrcK%%Dsduy2?_FlhzOb)L!|d1d`Sm4xjhW2j ze3U!3<=%dk17N_Tu8=uO-Fvj=jF? zc3mdjhUTv))#qRFf2eSEwqgD~8`%?uP6e!MXA5*V8L&I59XMF2J{%iLGm*xhkIhMt0ZyMZ1ZtuCi$hG?rlgszJ<@5i^H!5$b zI&_l7X91^H=&B{m0UTK~LmCYeANK_py_s_Ld&tzF$R(9`_e?UXOv;Q?Ump_oxWS}+ zcG=uZhyCV8i%ve$DfHq~LUH{phb=5!TIs8oEq&d0O1Sp9w|MBa{O`+8MQ^%xiaU0B z5Z}p3iaX{0B{y#U`+Vi~_$|Tbw`Rr!td*bmQ~U4x${#;mUs@$hwE1?;=4a|Rz3Np} z=S|O;g1e_KE(;I-wVNkr&g$Q_TfRp1*Y=#7n_QQ_{q^OtziRHSExX?Fel1ubP#!j6 z_ru1#lrxU9(oJqly{BJ$?<^uclP6GcX^P45L+bNugvxXl$la9TK4DS%^pvQq59^hy zN)cTLcx(Rsd~Wqv)F4o57}2!S?yEe+#I$x%Jb9|&C=Q* zpb7qH8O2^Xg@D!vf!lI!ez|{SVOk%5HH`pC33>Cejx%X~Uk7+zT$9qzu5(NXF0A&!eFHDXMjYBN|k zWM-Cj|DUYxzplHoe@4NlH>rlQtf}Yc1l3M3<*_u#bLO%(U(#!AwCpSYe5>-Sa$I*i zFNb~L3d^_C^S&;7G4;0G|GI)(b@yF3g*{%g{rqb1%(mjoqP(Xq>nEzE3hi9&miKqN zaQdJ3JCpC<-0(eS=f(MxF6>cW@C7A)MroGj0-ps6Z&$3m+&af{?K)$gE3u13<%6C-jBw(zW@!_6;dJ-g zL}mAqE-PluFFv(qGtQgLZ*Q{7e4ZZkM*KOGJI97AtHaOBZJu?kvXCu(g0g6VgXD_@ z9ixs_Zb$x>%cvat`~CiUehrxo@0!%h=iE6cw4QtOi?}tm-)i*c^8D$ntNC6gZkgdV?+VwfG_U9N=gsG@d-8MMe%{Qi^Nx@z zRmAX0=z{k=!5>1Z4FcbCHE68bz`w|wJ$*vP^>wkk)^Yw`b=}S)@eoVw_tt+WE(WYI?|6A% zT)qC~MH&8!AwPaTpI>UVWo7X4SARM!JPHaH7~33nak#jJzm_$2cbV_=h@MPQtq_jx z3yb6xbtX45zu0`Q~J=t1g_m=5XQk7Pc-PrNbO|4lHnNKE#)F`G26x1s}l; zZ%#C4Hd+11`NJ`LzqHz489y}*kN549Bi`QH`nBY;qT(-)Q&Ti2%e95B4r?{7b;&xg zV%_|bm1`5u-Q>Rh5ZzopqUOOrFS9z+&1V?`B zTC->JcPFtw?Jkslv+~7njUTPW24A&*FaFl-wr=9(=WC}qylBq6dhGF~><2=BE!`Sp zGMCg8X8)}*uiPB7JJ0lM3EPxcVV}P9f4#fp?55uf?E7D=V}71;VZ~O)%-4{rt0Rf) zlIlY{xvx4d+nHZ&UKPH6-Rp}No-##QfJQ>CHuGt1*!%5Z@N&PGztk?z{|-8Jq~74- z%68>n<_Ym~RwXOmCCm3J2R!fI75zoFWmj&>1f%0jzh;>qXL@FOoJqj}G|UpK-gn0T z1W)RMrx&ir*RS2J;&@l@*RA7)jdop42RF8a`AQl^lrEF6|5NCoWwoWi>95T+*4X|p z@9tVF%;-KZV^>o##cp!ad<#hnCxw(F9fFCvX#z_e?cAT-&%L~?H*ZqA?4^ni2id>= zzY*v?MPnhq!XC9{ijTU~r3J1y6|71b5rWCe70YfOn(#>FK~7; zP}lzK{PxX#4YeuyX|C4=6Ebh4c7gh_H6}^D@8+*~zd5wzmwCn4$*Dna55_O~uI^p> zc(Kc`_fxNyam&B7EB)5B<%ON^^s~GDUS}TVUUGeH-J(^olbeFBz6;L$x5_!_^~94w z-#5lD4LZ*G=|cAA)LV~gi!PT6UcSaBbazLlul^+Sxl=SB@yjLsS-DO1%ZJ9r;!AE8 z*L$ozH+gB%^3Edv>-JA>d(M9P=;?~>_dt^kpwXkF4UEhs@>*^q-y^!o_BA_>ci=e ze$@W|``!7UPgkwbk4FVJYLEBHg1R5I1q&->__$13ouy1l+R|q&Rtoz4YW4b4I|?5^ z`SSAeFL!2k?q3E>GE*!p7#rnXTp2IkP@i8D#4o)=h%Ln4ioJo{bEX+Jnpk)eCs`-W93l%O}eF7&{F>HWkG{i7Z=j(d7x8PC6-CbKjJ?Qi79;WT` z*_T&w>aGKgK->1cR0~yTiskqs8S#DD<+JMZDxBPxEdI2(?$4Lhm;bM7MgBW~aYJ3L zTz0HaT;-Wt|6XsOJLRFU`O7f(^z-pkx2&A(byR5P)0JhaOV=n%T+Y5AG;`Ytt~b4Z zS8V)aQ9AofY+*p&y)Q4roY&ij8ZOwctgpZ7`;WtQ{h9G5)BjiozfNS?TKA)NwomL1 z_p*2PtD~h;{pQDTJ@s52&A&A}CLl=V`*IzZ3(L& zzS0&QCudfZ2M)=+CN>G&`*)m{wdk6>@)bg1$BX-|Z-QPdm&^P*VJp|&#S5Y(*?QmU zpbX{(F1c`BXjhP9mQ_h{)4!ezs@!+cHWO*gOIl?G%^P6q(-GKUC!`&LKDKrYvUve? z)L`G1w+5?iG`?v}vTgh~|F`NA&e|uO4pe<@WlY7pk)8>Q!)h$(S!U z4;<_hqxjvgzDZ?Ix$%Q{)9VA4J1c(fnrD_?p?z|qYAa+D)1nhsR|Gmw(~DizF0L1& zu{HbpwZnO!UctuX#1t_nqNs@gBd_bhtr`}Dx$2VNG3Ke;{s`iZ{1>QA4{JYDqj zRH^4&qs}L%XU5ICrmIq_^?YNzU`MUY#kqOAv>t~uks>_h(ru+E?9Id$1LlbW)WXR9woPpuC*xzLM0bl1v9U#4lj zU$x0W^u4x~^lytrH@F%X*ZuwV(g?J>ODiy=Z{8jiTXwyPyw-jvRZA~UHm}Y)Ip4Tf z#qSKa6gc%Q`oSjpd4-3$;JxukLoRZ2TCa><&)qAZ{(L@vdRy-8FCQKp zY+edFnn?n*fy{G~%Ese)XTQC@eRy8L>kA8=Z%oeqzs-8((Tk>~A14|lGI=gJwO@0U zZlBpZo27bvYr21CrEd1@O6mMk5TX-R8!_)qyT$GkhjqJ7WycnHse=M%(F(4uM=!p* zy87t>#*pd`lbjm?LCbtrwm(+d_GZWDKW5dd@9d}y?h-qpl3!~Se_y_OtA$nRw@osZ zauJdJU4QE4>rc=Q&-Xa>r1NTa)GIN`gebv>d*j{&DL;raFMQMzWRcHSty6Gs`jtI? z?<(isc=Y0&Y5L2&pD9m@Y-83{m{snHwLCf3cI}+q1)x z|FXBAiO66rvoh0H<=>*Sw4GnZa{2wkndciXTY0c9?Mj)*sBd=R_v?$o;;GLb%?(;v z!gq3(=F~a+D?;mjlv~S1k#AY8dLZqAARVV@HI0+lkq$ z7N`pJF{F1dUb!kIQD! z^Gch&Q1Azh3uj(h0zRwp!$J1aSxn1k8mD{ht@^40-g(#Zr7U!H*i<>&3k`mtd3MH3 zUeJb`x^|%#P5Td?nyRguc&Mc+YPw$Rm3=b5SVi;%E=nz}+@2Zq^i=QQpr@xziF8|Ec z*QVr`4aR+QcBt6e#pq16@|%*CbJA2-^{FH6%{|m1-q<+sd`mA3s{3efCtd+I*!SDOqUtLeUJNxUG z0m)g{ahgzRLogP1}`1!e;#Su!o*PC2g;{5`gVD*JQUfqOsI(`bF%lxrkPBqCO&@t)z;c%U8sRh#*-;3o=Tdt z^cO!lKiBR}=|LvPs(XJHp7k!@=4l*IyZT)4%1K`D)w8`AxB9Di&IvGD=B>xO>N!8R z6yrC+&HEQ5$U7BqewdY3%Kb9h411A8=Pm(AJmU#n=nm7LGh;%h#dPY;GI{c7{$ z&K}E4tCE+__#6K9UZ;e_q8~4xzc$`L}Hh zXTBW$U1GqrHs5He_cCUMY_s_j!tG<#?EfWhU9n5{!;#~U^UqKHdfV^R)okn;mbLFz>Fw9Qq5OCMC-#%+tg zC$-CoPj2^$>FK}sZT@t~-8-fI*1UxhCRuCuSiI1W-1%`v+_%@}HNW->6l7n1?SHdg z<;$`M;7+^9tdo<~Pfzx@)2#mXX5#7T`mfpfZ*R}npKYed+4FSm_Is1ea&Miuv$Oc= zsj1qNG=tSZvj99&CLUQ=SE;6-kGlS6$NHSBtFG2p#e04{o?pDis)>cuCCWr&P5WIw zd29Xe-)CsNoj+e=Zk6vO$NRcdlhr5Q(6Bjk+wZLSsXZmnonCL-+rG9qYMal>C$~GZ zpR6?hKf%5FzuMn+y-B*(e;eiWPhXRraJcOCj$NUjJljf6e%&BmbM4U7>aPXc&a7PG zWf?3g%dxR^$;scz`>u9z{{Caj`zWuz)Mfi2?K$slf~)^abv)>Byufx)Y0FjTc&CLQ zuHWg3=+}xkqx^fuwrf&fTCNmxeD(`Uovw9%brZX4)~Y6BSN+flT>NV%<*BpvX&m_a z`ubO12E8}MPfsn?fAq2C=B=&SrBzHZcfP-By&Ifza*}G5-H+ez_ou$UxA&Km{Mt$P z>g5gnC-U3zB*amtK>m#26$Lv*M6{9H5BWPNsNcANV2Y3r<&;x&B#C=4KRI z$@*2x6+g6!**2u!DSoj>PA}YK@}Hln#eZ!t-+XPlEJ3#JmzQp&@xHkwuQN(@%Y)xa zUlvznUUB02`m56t*I&PQ_`+6a&6_4Wo6r1TH#O&ewcGYJO=n(CeqFlh&vCO)9;X*o z-RitN{b~JTWh-9r9`nEwg$UH|iI;bguT#)a2}-}3JdWPSN|UN~!bYzFtgRxPy+!ZV(0Ju@h9 zVVtvbP2t1-D}}w%=GQctCI~TrPP%0F*;)Mj+T#x&4)cRfQB8euVPVm)FPW9!Zl=H8 z@3Ibb;O(&omzH{edOAJ6t=3ONz+zRH+Uh@lp8Hik{w!*hd-wR_>us`cs`=+nmo{HC z?@+=~`{OAO@3%8?F-iGFoVmU$WXhq+OQ&K@|Jd&<)p|A|?CWRGmxm;mX1!cfC8ejv zFTY(%#|eTf1R7Iw`$G(clk?pq^#YqueG>xZq22QnTdDBgJ&v9s#acd z*_3iu@bC5`okAy0_fMP7lR4RQ?Wdbp_k<~&&iv=~|GAu9UEubfsyAyZKb_7wvQF3g zTEzU_KDyIC#z8;{wk(sC9wnP#!)zJG=evVZ|5C?JUdv=1NWT%Dca>w&?xd z@2`G)30pLQ&XxQ>_xn_jM)8Zasz!+q_6atwTye)d=+A>)sr=8c-~7k!9c{iz&Z5Mr zYW;M%^?LXDG8FCkGqvUS-tj0(+uG!*qh8KmA?JGsnco3$HCr zy|X-b$?N8@uZI8ZsxDcbuPr%#FL+boZ$sOdZ4qIb6V&(0eJgr<%Xj9s1GlyZE%Q+7 z&5Eim->vFDDBrBA1zP-7b$m&0pvB@p{+?0Y9tW5702b_oE~K%*0}KH=a)g1ujaBcK7Dod05>B`=B1_EqC}Q@O!N59|Fh`V{3s(vo*h~G z$2pHrc3*8Se_eM>V?0`JFl*p5&bIctahZ)vMb-G9_3D* z)E+f`CebC@fF>oRCGwNd7AADS)POPOEx;odmi)p{l89MrzbSHUi4Afhefk%oH*-DnVne^|M8xFt(R}p zxubBwlfLDy47FA>`)vGIbF(k0HRh}M^7iqcJK*Vso%?w+SN)%-*!%z4`zw+40w*os zlmy2%Bv>zakfajQDfH`lXvlo=Gc&IJuf5Q8%Hh?%$?0pJ`YhC2G|9TD3f#Uac|C{! zPvzbB3+Kl$H!6JptJ3w-T72J+N8KLpwHX^V@0iE!t=c_l(}lTNr{?5l?cdxMZTe;1 z9P^j^=j2&LO;Ra(^Ezb# zyzQq$-1;x3lpT9`IPBKu9!Wv&t#9t^G+y&`(#EW-T6gP%x69g}+AA)vyS%A*{#DJylCyI6jA8;*moW)^)%vZ^!qyw3y!4Qpd7-XpN_gs({OC6;w@)|TDmyLv>@(qA zM@9Cv@9bFr{>M3Rls?&>bJJ+1U2T;^;Wz(k?SlFYCa-2T-b;T)C8M|HObm~!RMp9i zUGaVD1k2*I+WQfkQch~zHNQ0X>7}W!i@yC4jr9rcot^dI4QuwS${kl6?mHL%-}J83 zc$v4Jsdn4@=d9na`0uw2RXcY>rK}KF;Le ze*EI_RnaKsnXA{tt*Y2A{-sU%zi8-(n-%f~TdyojyYuJM(I<~T^T-4;*jRqM8Xo_0 z+5hY7Vkd)+6Kdm;Eb(5Fb92*4&_aUZ5axgNe?A`ndbIl1mdw%voS&KXeqH3$dhpe? zJIepdnuv`~LCgKt<|{4pnYn2B-L7Aue;jA9$Io5+`)#Gi-}gCRg>P@k4hmQ`ZPUC1 z&hj=}Q2O z{@+#ID@*L_K25U8@t3x~8p*2h>G>nsqKoS+@&osG)IGRzy7Th%lq*Y0Fa4b>dFkiW z`%mVc7eBRea#&e6)6UD@pV|J2$*KFf+Pt?_+`_id`gHSJFVAgf!mR!+v|l%g&$e#j z_cq;Yk5>k%Omx3Jg||aGc5jt)n$9M*JL5_t|^D zpMHLyt*_cy7k}Mp?(ejP*IgA3tog86Ynks0&Cm&E>)IACIIj>a+`W48`H+JpHtXUe zr&g|F_!P~%g-yA|;r!)Q3)rh#vI>tRNiLYGr61j_=s@|IP2eDX>(A@vAX`HTYr(@oLeuu#iqK;*M@+O zSYr0enAmd7^~INxV?B~VD<@s$RQU7ZFh6L0zN|@?Xa6=mwe#EbHE$X(zwq+ZH(5*l z_oeH#TtDCc7gBn$b-^|BzpqYf_fMN1)N15mRC=*%nvsWU_-?1N%C+9CC*NLlpD4cM ziS$Q5X3cPu$#wB-+T;4COcg8rJJaa$@{jBjtL$RJ?B2$DXH7Y+mKm&i@$8g~DLZR6 z`h1FM4@zvbcydzqYo2pvknQ$&`#E3UUp4)#T65LIEt1uHuI!xi=lxQtpq(jVd(UJr z%`^7)dRb7e`19%G-AQ}=p~rlkZD3?hd32=n*FOP%;dxf2Ug@(A)IN;P->a${{b**~ z>wTMwpPy5_8!qH38nn`XZg%Lo#rlhOzY@80IB&=FH~$JmSH>w$PdPosYtpL9z)w$o z)aTBcK8Zg*Ph#3T?$37rJ&t^4dtKf3E+#WreRAVoY46RuT2+&OiR_x6{lz_YeU{zN zA6L~Tg};^eE1v$IGrPBC-vp&w=@*JP*4|o>(b%)gUsr#t*3)TTON%^~@o1`ePHNdT zkK=E_)m1ax@4XIc5(c$)4kNSzv0f*1vminw(cJ+qO!f zpry|&KswHMs($EC*QqPEa7C>>We_^y|7sPr8v=iR#Z0}tY5}WoQ%ptvm$M?lLO*Wo zo2}s&z2Vh_5Z%e9Yo1=5c6a&HlXah;-dK6sYVW-!!L_Qrcf~>5+XMvzYc{=wPNLk+ zdVBEiq$J_Z@oqD;`#T=36F6-D!tYpTqw*q)bxG}dNGrABqyDY zH7z>*qFmZ216&qBh`>W)kbyWCmlF4+(|ldNHy(8)DQ^QAwecv}1{iUdYnugVG#ZAx zmc!SngXeiVY!DjmPP{Rl=cwA7#~n$^-wIty+LPsB)`0CT(Uw3lO9}n#yc@?a%D(#a z^z`f675RA_IbM2l!Nmw zZ%V!&`7`H?{idA1f}qu|ac$2^KcAeO>-FM1=hZ)C6{$=Oxs>Sz4=k`~= z{#jv~8DKi!R&CS!3z0uFPq9Vr|JniSMr=y)(JWp4Wb(Fh@#!g^f4`^Q_l?k=oSwV! zIMdS5?-TCx@43Etx5T%?lIOpY|CL2zTXD(JaqiFS>mGlayEAGjzIbo|l zt<&lbv0Tpe?Clb-{Ln=~kEY5Sk7&&QkJoNfa<1MUw*E7@cCb$YP*(g$jfD2 zm!nrDScjqb&bW1*a`}GNIOk%OW&P`wXy6;6{%$L}`WzO=}okD68&d0CT{i^-^ zN_}(r{(sSRf0Ae0F5`Rmr1R;bT?H(A%I>)LE{*v2rK;xgy33zFWN$8Axz8dhp_@dbY=0ugWhU&ebk|diDR=i;T+KgIqVA z*sXtsf46z^gN{2^UuI}bUw3E2ai*!7vqJB^jkM31-;r_OMIa+!{;?o~?V(kihy!Pq)YY7${Qh(QW zt?Zq%(u+HE-77=wfRck!R}Rj!T%~d`SulFFmvCs`%Z(0OLn2prZBWkJucaE|xsHp; zSvkb9Yp}gRdTC&d3Grsedth3TShJQObsSF*i0Q zx0_^N^YNQ+xAyqsRavQE4nSGs%imU%y7`b{M;j(GuTP z&0hI6`<&Lr>|ObvZ~vKlEB_y__WSoF&(^+4wBYG0-kB!p+vVD}?~f1+`*{ET%~M8? zPd~e~q$3wzAf1UZ$cmB?v)Bk6N%D%SBWO;2hgLO4uD{Jp5 zv9lV%_W5du|Mk5>BlXmh zqWa51MnATy8GSk&cIoZHQ z>gU%l>9TF@5L*3dgBHgxnIP7K3u9I>L@DqFAHBl6D3rg+je~EY*oQq@89$jb8o#uf zN+`-~d>iU`f#cx(^`VvvPq~JEsQ8n-%H@l(p|faBUV7-fpr^T^2LDw;d)}>5Sn+kC z*7n!x?Tw2o7{q`1&NjR1zisdDce^)Leop(#BKhFu#`E_7WB3o>&fl*ax+-L%PUI$! zOG`Yj^2dA4-L)Y9{=QwJ!l0`U_p3)q9|Wz^Ea1AlD*U_s(}FKA0$*NS+%BRQ6ER8E zTkYkgrIXcsXPsCRx%rKy4(J%a>e}ggu_~*2AIN1!hRE&Tz9U3$=FxeNa&PWh{B45A z>R&%gxu?s_4E9?4>00Zf&dbwNFJ{fL)9Dn7Y{MP41BmA&(?qbGhcGUy2XWIv))AT-?g4P zv1#XJufJNBOEYy}bLz9Ci>*DTY5nJy!D+FaTAR!Dji9w^dhPwunO_dnq&;%sTyp-g zs7m>^kWXL!s(#(ZzGZ<`^|`7(g(a2eXQ%VIXqC-bVgLSJ`m$TWi?-Rf%>J(Tf6p_w z$Ks~>BK(}-RLr_6boH|Lhv%qPm%YBn%&2nb{{jp7C)pPkINtbD{Ct9p>yy*^`+0W9 z|9Z3e{FABSaTj$PCm8LC+gtVNyuC+~(2MW)>#y^3rk$G;dH?#;Gc$uhM`1<_etmga zea%+E9%*yEH^v{$D}Fp|Uz&P)+NGVv&l`SkZf58Ay1p)UsY4^vuiC=?@a=hb3v{P# zIP=VQqLBWk)OnW0%jV6qtF7{!q|&)her?p&Rr}_bcuiL8t@FQ=Y*fkRs^%P}{dM|g z8Oypjdk(JNY|$xKG}k^qHgQqj?Y!6b)>JI?DGHzKG)dVzt8z_l_CKZC$ z+wM!T^*vg+CUWzuY3^+ERE$Aa%Q0JW2t8c(tnJswn;R0FL5E!2w`r*=+*kfSZe_&A zMf*G*POE)cTk`gnsjSJa*Xwqt9N{q8^t*g!xATs|!~bpP9F{Jhx2fI5%2apFfBT9z zi~el=*5McY{dY}$*VbR5YqylW-X1MJJ-}rB*TcM(o0jucPvX=~zA(i?>EONP9a3iE zt2m5~Jozj5%hRaq3FjZ5!z^Y=P6x`*JpbQwsPDY-X_1S+43whHa&`-+PuLlvQoilV zq(c|u10L>q`Q`tOe>dI*&NNpFyea=>&$n+^KHs`+x#~9`sPTT(?({U>%lvmOPoJIr zaQ$lm4$iBq*Y8^uZM3j|5x2PBi6&O=l7{E6LjNE3-BEtnq~>0yu=|R>*MrEGn@*irxTB}(nT%MZ! zuWE%%7M`{v-KK1#f+o?bs3uskVl?mq#s)s^Ss_bmGzc*u_1 zl{;n9m&}XH8atXkay_>`f92Wr16f9i8*lxLoOAef2&WI5q+FDlWChQPHZ6__#jP>% zp=-1kJeY8bZ@+U!VvGCv{o$EhF4qndv@&Cui$3d&b%EBjd3ah;cbE^pAV_b4)=UTPfFCKH4JIqM?RQb4;PsU?X6 z|7$NHr(Je^1^sPJ`&paAoHI7E=3X;g@w}7Bu}@d9&>Ja5c5pcds++Y#IW^oYu`HyI^5b-x_ZxlyLn4hyCh$4 zlesGTE?{kq-pP44<0sbtTJzsdFZI)b-#bFSS-d-YE|$ZlZDP?~mdO{^pJ{qp{q!k+ z`stMt`^uN^NI$x(c~jZssq@x(?CS~IB4=F5lElb8BlpTD&Fzhu?@Gjj}E-+61N zoBiK6Q`4DC^2Y9sd5$gLYZhErdHM0(e58$O50OetP> zj?M9I-c4t*?^XM1zP9m&Sf0M6d(En_XrJDVZCqC;3Qs>&`|MqF*e&kmGya?jaC!RK zY3BFM;n}BWeSBMTa-L+bJ@d}^=l8<=7M|Pv<@fI|&;S0bG_LkqaN-;L@)c*mw*`H? zytv;^3v^!N%R4>-YyvrqciLx$`JT7=++*|M0P`fX+^D%~eBUcTn;h!9wPI#3x*v1E zR*uQaLpywDQEKHY&6NAwpE=t5<(*44JE&)HI!Dfq2@QMxf`R^^_kkVswY@g&9Feke{JOB_fO=1u4JqgnyMM>2D)i+ zZXHAADs{g(E9QSODwrrIxkbfjZRdnfd7vrGqhGpN)H+(Y|2;W5`Sm1=!Y{vGak{P& z>3q7JU&{0NvR2jfX;UUC<{GUG((1l*pQU}8YWplck4UqOD^jJ6EBxdlgHP_sk3P9c z{`QIE`d6=9PSd%m&g>rb+90^9esV&3drLx-cc+l*gp$ljuf){+zsD>1?|rP#yw8>A z_E)>U1yhV2T5Wa)ZcRD+u;IM(OpDX6lAo8=rWpkO+_OSYT5nFl!KZs(aD9_2IJa@F z(K2tbrIo!)JlC8rVUuCLr#|T~vK;A z9MX>1uwX_5CzD0mjV(70+RhDJ)N<84!{N4{B_d`B77@x_jq+7M;zB z({?5vZnHWuRU=TTc7E5iz`MIjFW1T_{%-v&C$j!{`r>-kMJp^SzU)~OQy;)Der~#> zmnh#G(L*y|y}q>c!0#R0)Bk=?Q7O^RYH`~K{_TgZzc;(yczmM#wn=PP*Vy%)o3mRfdD)NX ze7_kRJ-;7ho%>!}JDL5y`hET!-J{$ommHTm-q)LYxbNTO4vihHtF8pH_ODy8RItgs zH>9vCO7x3j%b)0s+7^>C{S`@a#Rp%n;nQt8o${amZK&gF#gd9o9BMbhZv1y=kxfug zo%{1m-l~L|zgB;0*2-Ve^rf6bOYy?j30m3UX|$uxJ7&lmFnkQ={^WW1#6;!8m##fr zX}Co0fb0Ly=NBu+R2-c5!E374RK13OQ!e;V`kZ!hO4-|6FDngt7=*o2%)PdA9bB}1 z{z{e2?c1lQE`C4t;(OC6+1LN{GOwO`a@qg;wGZZ;Gv*FGoibHNa!vP%-PzBst?f@Z zY9Hpk#;Da-*==I(??3*nZ!AmV*4=s^t5g50;X%{%hVM6D*Uw*DeQrf*3h#8yNr7w2 zvn|x7l+`>dJHF|$F>g(p59c@8?Qg&F&ra>isFgUE>TK`u;`phX(?ywD)Gic1c)_}} z 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 From 896a997a5309dc344c9eafde9dfd80e067ed1c10 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 21 Sep 2023 10:20:12 -0400 Subject: [PATCH 087/170] utest: ++ fixed --- utest/fixed.test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utest/fixed.test.cpp b/utest/fixed.test.cpp index d882e542..c2b7146b 100644 --- a/utest/fixed.test.cpp +++ b/utest/fixed.test.cpp @@ -37,6 +37,10 @@ namespace ut { fixed_tcase(0.05, 1, "0.1"), fixed_tcase(0.05, 2, "0.05"), + fixed_tcase(-0.05, 0, "-0"), + fixed_tcase(-0.05, 1, "-0.1"), + fixed_tcase(-0.05, 2, "-0.05"), + fixed_tcase(1e-6, 0, "0"), fixed_tcase(1e-6, 1, "0.0"), fixed_tcase(1e-6, 2, "0.00"), From d656a3970dd166d317eca921b6bbb07c4e9af30d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 21 Sep 2023 11:10:22 -0400 Subject: [PATCH 088/170] cosmetic: code layout in quoted.hpp --- include/indentlog/print/quoted.hpp | 240 ++++++++++++++--------------- 1 file changed, 120 insertions(+), 120 deletions(-) diff --git a/include/indentlog/print/quoted.hpp b/include/indentlog/print/quoted.hpp index 15d7a397..3691d874 100644 --- a/include/indentlog/print/quoted.hpp +++ b/include/indentlog/print/quoted.hpp @@ -12,136 +12,136 @@ #include namespace xo { - namespace print { - /* use this to avoid template conversion hassles - * since literal strings get treated as arrays - */ - template - char const * ccs(T x) { return x; } + namespace print { + /* use this to avoid template conversion hassles + * since literal strings get treated as arrays + */ + template + char const * ccs(T x) { return x; } - /* Printing cases: - * 1. T&&: - * move into quoted_impl. T must be moveable! - * 2. T&: - * copy reference into quoted_impl. - * similarly for T const &, copy reference into quoted_impl - */ + /* Printing cases: + * 1. T&&: + * move into quoted_impl. T must be moveable! + * 2. T&: + * copy reference into quoted_impl. + * similarly for T const &, copy reference into quoted_impl + */ - template - class quoted_impl { - public: - quoted_impl(bool unq_flag, T const & x) : unq_flag_{unq_flag}, value_{x} {} - quoted_impl(bool unq_flag, T && x) : unq_flag_{unq_flag}, value_{std::move(x)} {} + template + class quoted_impl { + public: + quoted_impl(bool unq_flag, T const & x) : unq_flag_{unq_flag}, value_{x} {} + quoted_impl(bool unq_flag, T && x) : unq_flag_{unq_flag}, value_{std::move(x)} {} - bool unq_flag() const { return unq_flag_; } - T const & value() const { return value_; } + bool unq_flag() const { return unq_flag_; } + T const & value() const { return value_; } - void print(std::ostream & os) const { - std::string xs = xo::tostr(value_); + void print(std::ostream & os) const { + std::string xs = xo::tostr(value_); - if (xs.empty()) { - /* print empty string as "" */ - os << "\"\""; - } else if ((xs.at(0) == '<') && (xs.at(xs.size() - 1) == '>')) { - /* assume string represents output of a well-formed object printer, - * and already self-escapes - */ - os << xs; - } else if (xs.find_first_of(" \"\n\r\\") == std::string::npos) { - /* no escapes needed, just print xs */ - if (unq_flag_) - os << xs; - else - os << "\"" << xs << "\""; - } else { - /* printed value contains a space - * and/or a must-be-escaped character. - * in any case, need quotes - */ + if (xs.empty()) { + /* always print empty string as "" */ + os << "\"\""; + } else if ((xs.at(0) == '<') && (xs.at(xs.size() - 1) == '>')) { + /* assume string represents output of a well-formed object printer, + * and already self-escapes + */ + os << xs; + } else if (xs.find_first_of(" \"\n\r\\") == std::string::npos) { + /* no escapes needed, just print xs */ + if (unq_flag_) + os << xs; + else + os << "\"" << xs << "\""; + } else { + /* printed value contains a space + * and/or a must-be-escaped character. + * in any case, need quotes + */ - os << "\""; + os << "\""; - /* print contents of ss, with escapes: - * \ => \\ - * " => \" - * newline => \n - * cr => \r - */ - for (char ch : xs) { - switch (ch) { - case '"': - /* " => \" */ - os << "\\\""; - break; - case '\n': - /* newline -> \n */ - os << "\\\n"; - break; - case '\r': - /* cr -> \r */ - os << "\\\r"; - break; - case '\\': - /* \ => \\ (mind c++ requires we escape \) */ - os << "\\\\"; - break; - default: - os << ch; - break; + /* print contents of ss, with escapes: + * \ => \\ + * " => \" + * newline => \n + * cr => \r + */ + for (char ch : xs) { + switch (ch) { + case '"': + /* " => \" */ + os << "\\\""; + break; + case '\n': + /* newline -> \n */ + os << "\\\n"; + break; + case '\r': + /* cr -> \r */ + os << "\\\r"; + break; + case '\\': + /* \ => \\ (mind c++ requires we escape \) */ + os << "\\\\"; + break; + default: + os << ch; + break; + } + } + + os << "\""; + } + } /*print*/ + + private: + /* .unq_flag: if true, omit surrounding " chars + * if printed value satisfies both: + * - no escaped chars + * - no spaces + */ + bool unq_flag_ = false; + /* .value: value to be printed */ + T value_; + }; /*quoted_impl*/ + + template + std::ostream & + operator<<(std::ostream & os, quoted_impl const & x) { + x.print(os); + return os; + } /*operator*/ + + /* writing out std::forward behavior for completeness' sake: + * + * 1. call quoted(x) with rvalue std::string x, then: + * - T will be deduced to [std::string] + * (in particular: _not_ std::string &, std::string const &, std::string &&) + * - rvalue std::string passed to quoted_impl ctor + * + * 2a. call quoted(x) with std::string & x, then: + * - T deduced to [std::string &] + * - std::string & passed to quoted_impl ctor + * + * 2b. call quoted(x) with std::string const & x, then: + * - T deduced to [std::string const &] + * - std::string const & passed to quoted_impl ctor + */ + template + auto quoted(T && x) { + return quoted_impl(false /*unq_flag*/, std::forward(x)); } - } - os << "\""; - } - } /*print*/ + inline auto qcstr(char const * x) { + return quoted(x); + } /*qcstr*/ - private: - /* .unq_flag: if true, omit surrounding " chars - * if printed value satisfies both: - * - no escaped chars - * - no spaces - */ - bool unq_flag_ = false; - /* .value: value to be printed */ - T value_; - }; /*quoted_impl*/ - - template - std::ostream & - operator<<(std::ostream & os, quoted_impl const & x) { - x.print(os); - return os; - } /*operator*/ - - /* writing out std::forward behavior for completeness' sake: - * - * 1. call quoted(x) with rvalue std::string x, then: - * - T will be deduced to [std::string] - * (in particular: _not_ std::string &, std::string const &, std::string &&) - * - rvalue std::string passed to quoted_impl ctor - * - * 2a. call quoted(x) with std::string & x, then: - * - T deduced to [std::string &] - * - std::string & passed to quoted_impl ctor - * - * 2b. call quoted(x) with std::string const & x, then: - * - T deduced to [std::string const &] - * - std::string const & passed to quoted_impl ctor - */ - template - auto quoted(T && x) { - return quoted_impl(false /*unq_flag*/, std::forward(x)); - } - - inline auto qcstr(char const * x) { - return quoted(x); - } /*qcstr*/ - - template - auto unq(T && x) { - return quoted_impl(true /*unq_flag*/, std::forward(x)); - } - } /*namespace print*/ + template + auto unq(T && x) { + return quoted_impl(true /*unq_flag*/, std::forward(x)); + } + } /*namespace print*/ } /*namespace xo*/ /* end quoted.hpp */ From bc4474c72fdebad50ef5fecb809e954462a7375e Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 21 Sep 2023 11:10:50 -0400 Subject: [PATCH 089/170] print: utest for print::quoted, print::unq --- utest/CMakeLists.txt | 2 +- utest/quoted.test.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 utest/quoted.test.cpp diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 707b7fd1..c4ecf78e 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -1,7 +1,7 @@ # indentlog unit test set(SELF_EXECUTABLE_NAME utest.indentlog) -set(SELF_SOURCE_FILES fixed.test.cpp indentlog_utest_main.cpp) +set(SELF_SOURCE_FILES fixed.test.cpp quoted.test.cpp indentlog_utest_main.cpp) add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) xo_include_options(${SELF_EXECUTABLE_NAME}) diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp new file mode 100644 index 00000000..35583d4d --- /dev/null +++ b/utest/quoted.test.cpp @@ -0,0 +1,76 @@ +/* @file fixed.test.cpp */ + +#include "indentlog/print/quoted.hpp" +#include "indentlog/print/tag.hpp" +#include +#include + +using namespace xo; +using namespace xo::print; + +namespace ut { + struct quoted_tcase { + quoted_tcase() = default; + quoted_tcase(std::string x, bool unq_flag, std::string s) + : x_{x}, unq_flag_{unq_flag}, s_{std::move(s)} {} + + /* string to be printed-in-machine-readable-form */ + std::string x_; + /* if true: omit surrounding " chars when unambiguous + * (printed string does not contain spaces or escaped chars) + * if false: always require surrounding " chars + */ + bool unq_flag_ = true; + /* expected result */ + std::string s_; + }; /*quoted_tcase*/ + + std::vector s_quoted_tcase_v( + { + quoted_tcase("", true, "\"\""), + quoted_tcase("", false, "\"\""), + + quoted_tcase("foo", true, "foo"), + quoted_tcase("foo", false, "\"foo\""), + + quoted_tcase("foo\n", true, "\"foo\\\n\""), + quoted_tcase("foo\n", false, "\"foo\\\n\""), + + quoted_tcase("two words", true, "\"two words\""), + quoted_tcase("two words", false, "\"two words\""), + + quoted_tcase("1st\n2nd", true, "\"1st\\\n2nd\""), + quoted_tcase("1st\n2nd", true, "\"1st\\\n2nd\""), + + quoted_tcase("misakte\rfix", true, "\"misakte\\\rfix\""), + quoted_tcase("misakte\rfix", true, "\"misakte\\\rfix\""), + + quoted_tcase("\"oh!\", she said", true, "\"\\\"oh!\\\", she said\""), + quoted_tcase("\"oh!\", she said", false, "\"\\\"oh!\\\", she said\""), + + quoted_tcase("", true, ""), + quoted_tcase("", false, ""), + }); + + TEST_CASE("quoted", "[quoted]") { + for (std::uint32_t i_tc = 0, z_tc = s_quoted_tcase_v.size(); i_tc < z_tc; ++i_tc) { + quoted_tcase const & tc = s_quoted_tcase_v[i_tc]; + + INFO(tostr(xtag("i_tc", i_tc), xtag("x", tc.x_), xtag("unq_flag", tc.unq_flag_))); + + std::stringstream ss; + if (tc.unq_flag_) + ss << unq(tc.x_); + else + ss << quoted(tc.x_); + + INFO(xtag("ss.str", ss.str())); + + REQUIRE(ss.str() == tc.s_); + } + + REQUIRE(s_quoted_tcase_v.size() > 1); + } +} /*namespace ut*/ + +/* end quoted.test.cpp */ From cc82199a8e403f6bbde06ab452448d3e2498ff1d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 21 Sep 2023 11:20:56 -0400 Subject: [PATCH 090/170] utest: + array,vector printers --- utest/CMakeLists.txt | 2 +- utest/array.test.cpp | 40 ++++++++++++++++++++++++++++++++++ utest/vector.test.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 utest/array.test.cpp create mode 100644 utest/vector.test.cpp diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index c4ecf78e..95a6e5d3 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -1,7 +1,7 @@ # indentlog unit test set(SELF_EXECUTABLE_NAME utest.indentlog) -set(SELF_SOURCE_FILES fixed.test.cpp quoted.test.cpp indentlog_utest_main.cpp) +set(SELF_SOURCE_FILES fixed.test.cpp quoted.test.cpp vector.test.cpp array.test.cpp indentlog_utest_main.cpp) add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) xo_include_options(${SELF_EXECUTABLE_NAME}) diff --git a/utest/array.test.cpp b/utest/array.test.cpp new file mode 100644 index 00000000..4ba8b83a --- /dev/null +++ b/utest/array.test.cpp @@ -0,0 +1,40 @@ +/* @file array.test.cpp */ + +#include "indentlog/print/array.hpp" /* overload operator<< for std::array */ +#include "indentlog/print/tag.hpp" +#include +#include + +using namespace xo; + +namespace ut { + TEST_CASE("array", "[array]") { + tag_config::tag_color = color_spec_type::none(); + + { + std::array x = {}; + std::stringstream ss; + ss << x; + + REQUIRE(ss.str() == "[]"); + } + + { + std::array x = {1}; + std::stringstream ss; + ss << x; + + REQUIRE(ss.str() == "[1]"); + } + + { + std::array x = {1, 2}; + std::stringstream ss; + ss << x; + + REQUIRE(ss.str() == "[1 2]"); + } + } +} /*namespace ut*/ + +/* end array.test.cpp */ diff --git a/utest/vector.test.cpp b/utest/vector.test.cpp new file mode 100644 index 00000000..8b4f1f4c --- /dev/null +++ b/utest/vector.test.cpp @@ -0,0 +1,50 @@ +/* @file vector.test.cpp */ + +#include "indentlog/print/vector.hpp" /* overload operator<< for std::vector */ +#include "indentlog/print/tag.hpp" +#include +#include + +using namespace xo; + +namespace ut { + struct vector_tcase { + vector_tcase() = default; + vector_tcase(std::vector const & x, std::string s) + : x_{x}, s_{std::move(s)} {} + + /* vector to print */ + std::vector x_; + /* expected result */ + std::string s_; + }; /*vector_tcase*/ + + std::vector s_vector_tcase_v( + {vector_tcase({}, "[]"), + vector_tcase({1}, "[1]"), + vector_tcase({1, 2}, "[1 2]"), + vector_tcase({10, 20, 30}, "[10 20 30]"), + + }); + + TEST_CASE("vector", "[vector]") { + tag_config::tag_color = color_spec_type::none(); + + for (std::uint32_t i_tc = 0, z_tc = s_vector_tcase_v.size(); i_tc < z_tc; ++i_tc) { + vector_tcase const & tc = s_vector_tcase_v[i_tc]; + + INFO(tostr(xtag("i_tc", i_tc), xtag("x", tc.x_))); + + std::stringstream ss; + ss << tc.x_; + + INFO(xtag("ss.str", ss.str())); + + REQUIRE(ss.str() == tc.s_); + } + + REQUIRE(s_vector_tcase_v.size() > 1); + } +} /*namespace ut*/ + +/* end vector.test.cpp */ From b07b3e09b5b5b580a2d528066a98f1ba32ece240 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 21 Sep 2023 17:44:00 -0400 Subject: [PATCH 091/170] timeutil: bugfix: needs timegm() instead of mktime() ! --- include/indentlog/timeutil/timeutil.hpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/include/indentlog/timeutil/timeutil.hpp b/include/indentlog/timeutil/timeutil.hpp index 6e24d3ce..740283f3 100644 --- a/include/indentlog/timeutil/timeutil.hpp +++ b/include/indentlog/timeutil/timeutil.hpp @@ -162,16 +162,16 @@ namespace xo { * .tm_isdst (daylight savings time flag) * usec (0-999999) */ - static std::pair split_tm(utc_nanos t0) { + static std::pair utc_split_tm(utc_nanos t0) { using xo::time::microseconds; using xo::time::utc_nanos; /* use yyyymmdd.hh:mm:ss.nnnnnn */ - time_t t0_time_t = (std::chrono::system_clock::to_time_t - (std::chrono::time_point_cast(t0))); + time_t t0_time_t = (std::chrono::system_clock::to_time_t(t0)); + //time_t t0_time_t = (std::chrono::system_clock::to_time_t(std::chrono::time_point_cast(t0))); - /* convert to std::tm, un UTC coords, + /* convert to std::tm, in UTC coords, * only provides 1-second precision */ std::tm t0_tm; @@ -186,7 +186,7 @@ namespace xo { midnight_tm.tm_sec = 0; /* convert back to epoch seconds */ - time_t midnight_time_t = ::mktime(&midnight_tm); + time_t midnight_time_t = ::timegm(&midnight_tm); utc_nanos t0_midnight = (std::chrono::time_point_cast( @@ -198,7 +198,7 @@ namespace xo { .count(); return std::make_pair(t0_tm, usec); - } /*split_tm*/ + } /*utc_split_tm*/ static void print_hms_msec(nanos dt, std::ostream & os) { /* use hhmmss.nnn */ @@ -236,6 +236,12 @@ namespace xo { os << buf; } /*print_hms_usec*/ + /* print t0 like: + * yyyymmdd:hh:mm:ss.uuuuuu + * e.g. + * 19700101:00:00:00.000000 // epoch + * 20230921:16:29:35.123456 // 21sep2023 4:29:35 pm + 12345 us + */ static void print_utc_ymd_hms_usec(utc_nanos t0, std::ostream & os) { using xo::time::microseconds; using xo::time::utc_nanos; @@ -246,7 +252,7 @@ namespace xo { //uint32_t t0_usec; /* (structured binding ftw!) */ - auto [t0_tm, t0_usec] = split_tm(t0); + auto [t0_tm, t0_usec] = utc_split_tm(t0); /* no std::format in clang11 afaict */ char usec_buf[7]; @@ -272,7 +278,7 @@ namespace xo { * 2012-04-23T18:25:43.511Z */ static void print_iso8601(utc_nanos t0, std::ostream & os) { - auto [t0_tm, t0_usec] = split_tm(t0); + auto [t0_tm, t0_usec] = utc_split_tm(t0); char msec_buf[8]; snprintf(msec_buf, sizeof(msec_buf), "%03d", t0_usec / 1000); From 9cfa6db5db26af9d475a713e4961e0af10064007 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 21 Sep 2023 17:45:01 -0400 Subject: [PATCH 092/170] utest: + timeutil tests --- CMakeLists.txt | 3 + utest/CMakeLists.txt | 2 +- utest/timeutil.test.cpp | 168 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 utest/timeutil.test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cbfe6953..b8365f9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,9 @@ add_code_coverage() # add_code_coverage_all_targets(EXCLUDE /nix/store/* utest/*) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED True) + # always write compile_commands.json set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 95a6e5d3..6c4c07a0 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -1,7 +1,7 @@ # indentlog unit test set(SELF_EXECUTABLE_NAME utest.indentlog) -set(SELF_SOURCE_FILES fixed.test.cpp quoted.test.cpp vector.test.cpp array.test.cpp indentlog_utest_main.cpp) +set(SELF_SOURCE_FILES fixed.test.cpp quoted.test.cpp vector.test.cpp array.test.cpp timeutil.test.cpp indentlog_utest_main.cpp) add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) xo_include_options(${SELF_EXECUTABLE_NAME}) diff --git a/utest/timeutil.test.cpp b/utest/timeutil.test.cpp new file mode 100644 index 00000000..816c92da --- /dev/null +++ b/utest/timeutil.test.cpp @@ -0,0 +1,168 @@ +/* @file timeutil.test.cpp */ + +#include "indentlog/timeutil/timeutil.hpp" +#include "indentlog/print/tag.hpp" +#include +#include + +using namespace xo; +using namespace xo::time; +using namespace std::chrono; + +namespace ut { + TEST_CASE("epoch", "[timeutil]") { + //tag_config::tag_color = color_spec_type::none(); + + utc_nanos t0 = timeutil::epoch(); + + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(0)); + } /*TEST_CASE(epoch)*/ + + TEST_CASE("ymd_hms", "[timeutil]") { + { + utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 0 /*hms*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(0)); + } + + { + utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 1 /*hms*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(1)); + } + + { + utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 100 /*hms*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(60)); + } + + { + utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 10000 /*hms*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(3600)); + } + + { + utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 235959 /*hms*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(86399)); + } + + { + utc_nanos t0 = timeutil::ymd_hms(19700102 /*ymd*/, 235959 /*hms*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(86400 + 86399)); + } + + { + utc_nanos t0 = timeutil::ymd_hms(19700131 /*ymd*/, 235959 /*hms*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(30 * 86400 + 86399)); + } + + { + utc_nanos t0 = timeutil::ymd_hms(19700201 /*ymd*/, 235959 /*hms*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(31 * 86400 + 86399)); + } + } /*TEST_CASE(ymd_hms)*/ + + TEST_CASE("ymd_midnight", "[timeutil]") { + { + utc_nanos t0 = timeutil::ymd_midnight(19700101 /*ymd*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(0)); + } + + { + utc_nanos t0 = timeutil::ymd_midnight(19700102 /*ymd*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(86400)); + } + + { + utc_nanos t0 = timeutil::ymd_midnight(19700131 /*ymd*/); + REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(30 * 86400)); + } + + { + utc_nanos t0 = timeutil::ymd_midnight(19700201 /*ymd*/); + REQUIRE(system_clock::to_time_t(t0) == std::time_t(31 * 86400)); + } + } /*TEST_CASE(ymd_midnight)*/ + + struct timeutil_tcase { + timeutil_tcase() = default; + timeutil_tcase(uint32_t ymd, uint32_t hms, uint32_t usec, + std::time_t epoch_sec, std::time_t midnight_sec, std::uint32_t fractional_sec, std::uint32_t fractional_usec, + std::string const & utc_ymd_hms_usec_str, + std::string const & iso8601_str) + : ymd_{ymd}, hms_{hms}, usec_{usec}, + epoch_sec_{epoch_sec}, + midnight_sec_{midnight_sec}, + fractional_sec_{fractional_sec}, + fractional_usec_{fractional_usec}, + utc_ymd_hms_usec_str_{utc_ymd_hms_usec_str}, + iso8601_str_{iso8601_str} {} + + /* target time value to test */ + std::uint32_t ymd_ = 19700101; + std::uint32_t hms_ = 0; + std::uint32_t usec_ = 0; + + std::time_t epoch_sec_ = 0; + std::time_t midnight_sec_ = 0; + std::uint32_t fractional_sec_ = 0; + std::uint32_t fractional_usec_ = 0; + + std::string utc_ymd_hms_usec_str_; + std::string iso8601_str_; + }; /*timeutil_tcase*/ + + std::vector s_timeutil_tcase_v( + /* -------- inputs ------- ------------------------------------------------ outputs --------------------------------------- + * fractional_usec + * fractional_sec | + * ymd hms usec epoch_sec midnight_sec v v utc_ymd_hms_usec_str iso8601_str + */ + { + timeutil_tcase(19700101, 0, 0, 0, 0, 0, 0, "19700101:00:00:00.000000", "1970-01-01T00:00:00.000Z"), + timeutil_tcase(19700101, 0, 1, 0, 0, 0, 1, "19700101:00:00:00.000001", "1970-01-01T00:00:00.000Z"), + timeutil_tcase(19700101, 0, 123456, 0, 0, 0, 123456, "19700101:00:00:00.123456", "1970-01-01T00:00:00.123Z"), + timeutil_tcase(19700101, 0, 500000, 0, 0, 0, 500000, "19700101:00:00:00.500000", "1970-01-01T00:00:00.500Z"), + timeutil_tcase(19700101, 0, 987654, 0, 0, 0, 987654, "19700101:00:00:00.987654", "1970-01-01T00:00:00.987Z"), + + timeutil_tcase(19700101, 0, 999999, 0, 0, 0, 999999, "19700101:00:00:00.999999", "1970-01-01T00:00:00.999Z"), + + timeutil_tcase(19700101, 1, 999999, 1, 0, 1, 999999, "19700101:00:00:01.999999", "1970-01-01T00:00:01.999Z"), + + timeutil_tcase(19700101, 100, 999999, 60, 0, 60, 999999, "19700101:00:01:00.999999", "1970-01-01T00:01:00.999Z"), + timeutil_tcase(19700101, 10000, 999999, 3600, 0, 3600, 999999, "19700101:01:00:00.999999", "1970-01-01T01:00:00.999Z"), + timeutil_tcase(19700101, 235959, 999999, 24*3600-1, 0, 86399, 999999, "19700101:23:59:59.999999", "1970-01-01T23:59:59.999Z"), + + timeutil_tcase(19700102, 100, 999999, 86400+60, 86400, 60, 999999, "19700102:00:01:00.999999", "1970-01-02T00:01:00.999Z"), + + }); + + TEST_CASE("ymd_hms_usec", "[timeutil]") { + for (std::uint32_t i_tc = 0, z_tc = s_timeutil_tcase_v.size(); i_tc < z_tc; ++i_tc) { + timeutil_tcase const & tc = s_timeutil_tcase_v[i_tc]; + + INFO(tostr(xtag("i_tc", i_tc), xtag("ymd", tc.ymd_))); + INFO(xtag("tc.epoch_sec", tc.epoch_sec_)); + INFO(xtag("tc.utc_ymd_hms_usec_str", tc.utc_ymd_hms_usec_str_)); + + utc_nanos const t0 = timeutil::ymd_hms_usec(tc.ymd_, tc.hms_, tc.usec_); + REQUIRE(system_clock::to_time_t(t0) == std::time_t(tc.epoch_sec_)); + + auto x = timeutil::utc_split_vs_midnight(t0); + REQUIRE(system_clock::to_time_t(x.first) == tc.midnight_sec_); + REQUIRE(x.second == seconds(tc.fractional_sec_) + microseconds(tc.fractional_usec_)); + + { + std::stringstream ss; + timeutil::print_utc_ymd_hms_usec(t0, ss); + REQUIRE(ss.str() == tc.utc_ymd_hms_usec_str_); + } + + { + std::stringstream ss; + timeutil::print_iso8601(t0, ss); + REQUIRE(ss.str() == tc.iso8601_str_); + } + } + } /*TEST_CASE(ymd_hms_usec)*/ +} /*namespace ut*/ + +/* end timeutil.test.cpp */ From e7317b122c709df629d2563b954ad446e6bce21f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Sep 2023 12:15:09 -0400 Subject: [PATCH 093/170] print: simplify quoted_impl --- include/indentlog/print/quoted.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/indentlog/print/quoted.hpp b/include/indentlog/print/quoted.hpp index 3691d874..8629ac39 100644 --- a/include/indentlog/print/quoted.hpp +++ b/include/indentlog/print/quoted.hpp @@ -30,8 +30,7 @@ namespace xo { template class quoted_impl { public: - quoted_impl(bool unq_flag, T const & x) : unq_flag_{unq_flag}, value_{x} {} - quoted_impl(bool unq_flag, T && x) : unq_flag_{unq_flag}, value_{std::move(x)} {} + quoted_impl(bool unq_flag, T x) : unq_flag_{unq_flag}, value_{std::move(x)} {} bool unq_flag() const { return unq_flag_; } T const & value() const { return value_; } From 20b19d9cfe2fbb8cd9acabd4f51d91372a59aac7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Sep 2023 12:15:43 -0400 Subject: [PATCH 094/170] tidy: forward instead of move in tag_impl --- include/indentlog/print/tag.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/indentlog/print/tag.hpp b/include/indentlog/print/tag.hpp index 6c7eafbb..7d4a0abc 100644 --- a/include/indentlog/print/tag.hpp +++ b/include/indentlog/print/tag.hpp @@ -29,7 +29,7 @@ namespace xo { tag_impl(Name const & n, Value const & v) : name_{n}, value_{v} {} tag_impl(Name && n, Value && v) - : name_{std::move(n)}, value_{std::move(v)} {} + : name_{std::forward(n)}, value_{std::forward(v)} {} Name const & name() const { return name_; } Value const & value() const { return value_; } @@ -72,6 +72,8 @@ namespace xo { return tag_impl(n, ""); } /*xtag_pre*/ + // ----- tag ----- + template tag_impl tag(Name && n, Value && v) @@ -86,6 +88,8 @@ namespace xo { return tag_impl(n, v); } /*tag*/ + // ----- operator<< on tag_impl ----- + template inline std::ostream & operator<<(std::ostream &s, From 2b7d7f9d784401fd06b1f2a491d023b61612a084 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Sep 2023 12:16:06 -0400 Subject: [PATCH 095/170] cosmetic: consistent comment in color.hpp --- include/indentlog/print/color.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/indentlog/print/color.hpp b/include/indentlog/print/color.hpp index 49eb0bcf..47167b66 100644 --- a/include/indentlog/print/color.hpp +++ b/include/indentlog/print/color.hpp @@ -21,7 +21,7 @@ namespace xo { * * | enum | escape | example | description | foreground codes | * +-------+-----------+---------------------+---------------+------------------+ - * | ansi | \033[31 | \033[31;42m | 4-bit colors | 30..37, 90..97 | + * | ansi | \033[31 | \033[31;34m | 4-bit colors | 30..37, 90..97 | * | xterm | \033[38;5 | \033[38;5;143m | 8-bit colors | 0..255 | * | rgb | \033[38;2 | \033[38;2;10;20;30m | 24-bit colors | 3x 0..255 | * From ca64cdd91194bf95dbf4240529818f922f9755e2 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Sep 2023 12:16:41 -0400 Subject: [PATCH 096/170] utest: + tag/xtag + basename tests --- utest/CMakeLists.txt | 5 ++- utest/filename.test.cpp | 41 +++++++++++++++++++++++++ utest/tag.test.cpp | 67 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 utest/filename.test.cpp create mode 100644 utest/tag.test.cpp diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 6c4c07a0..6e6352b5 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -1,7 +1,10 @@ # indentlog unit test set(SELF_EXECUTABLE_NAME utest.indentlog) -set(SELF_SOURCE_FILES fixed.test.cpp quoted.test.cpp vector.test.cpp array.test.cpp timeutil.test.cpp indentlog_utest_main.cpp) +set(SELF_SOURCE_FILES + fixed.test.cpp quoted.test.cpp vector.test.cpp array.test.cpp timeutil.test.cpp tag.test.cpp + filename.test.cpp + indentlog_utest_main.cpp) add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) xo_include_options(${SELF_EXECUTABLE_NAME}) diff --git a/utest/filename.test.cpp b/utest/filename.test.cpp new file mode 100644 index 00000000..ee5fdfaf --- /dev/null +++ b/utest/filename.test.cpp @@ -0,0 +1,41 @@ +/* @file filename.test.cpp */ + +#include "indentlog/print/filename.hpp" +#include "indentlog/print/tag.hpp" +#include +#include + +using namespace xo; + +namespace ut { + struct filename_tcase { + filename_tcase() = default; + filename_tcase(std::string_view path, std::string_view basename) + : path_{path}, basename_{basename} {} + + /* target time value to test */ + std::string_view path_; + std::string_view basename_; + }; /*filename_tcase*/ + + std::vector s_filename_tcase_v( + { + filename_tcase("foo", "foo"), + }); + + TEST_CASE("filename", "[filename]") { + for (std::uint32_t i_tc = 0, z_tc = s_filename_tcase_v.size(); i_tc < z_tc; ++i_tc) { + filename_tcase const & tc = s_filename_tcase_v[i_tc]; + + INFO(tostr(xtag("i_tc", i_tc), xtag("path", tc.path_))); + INFO(xtag("tc.basename", tc.basename_)); + + std::stringstream ss; + ss << basename(tc.path_); + + REQUIRE(ss.str() == tc.basename_); + } + } /*TEST_CASE(filename)*/ +} /*namespace ut*/ + +/* end filename.test.cpp */ diff --git a/utest/tag.test.cpp b/utest/tag.test.cpp new file mode 100644 index 00000000..8ecabb8d --- /dev/null +++ b/utest/tag.test.cpp @@ -0,0 +1,67 @@ +/* @file tag.test.cpp */ + +#include "indentlog/print/tag.hpp" +#include "indentlog/print/vector.hpp" +#include "indentlog/print/concat.hpp" +#include +#include + +using namespace xo; + +namespace ut { + TEST_CASE("tag", "[tag]") { + tag_config::tag_color = color_spec_type::none(); + + { + std::stringstream ss; + ss << tag("foo", "hello,world!"); + + REQUIRE(ss.str() == ":foo hello,world!"); + } + + { + std::stringstream ss; + ss << tag("foo", "hello, world!"); + + REQUIRE(ss.str() == ":foo \"hello, world!\""); + } + + { + std::stringstream ss; + std::vector v = {1, 2, 3}; + ss << tag("foo", v); + + REQUIRE(ss.str() == ":foo \"[1 2 3]\""); + } + + { + std::stringstream ss; + ss << tag("foo", concat("farenheit", 451)); + + REQUIRE(ss.str() == ":foo farenheit451"); + } + + { + std::stringstream ss; + ss << tag("foo", "hello") << xtag("bar", "there"); + + REQUIRE(ss.str() == ":foo hello :bar there"); + } + + tag_config::tag_color = color_spec_type::blue(); + + { + std::stringstream ss; + ss << tag("foo", "hello,world!"); + + /* color on color off + * <---------> <-----> + * + * see [indentlog/print/color.hpp] for escape sequences + */ + REQUIRE(ss.str() == "\033[31;34m:foo\033[0m hello,world!"); + } + } /*TEST_CASE(tag)*/ +} /*namespace ut*/ + +/* end tag.test.cpp */ From b2d939363e5f6e2d0623d6705e5d7a30284a5fe5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Sep 2023 14:55:38 -0400 Subject: [PATCH 097/170] utest: + code_location test --- include/indentlog/print/color.hpp | 18 ++++++++++++ include/indentlog/print/concat.hpp | 5 ++++ utest/CMakeLists.txt | 2 +- utest/code_location.test.cpp | 47 ++++++++++++++++++++++++++++++ utest/filename.test.cpp | 2 ++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 utest/code_location.test.cpp diff --git a/include/indentlog/print/color.hpp b/include/indentlog/print/color.hpp index 47167b66..f8b64985 100644 --- a/include/indentlog/print/color.hpp +++ b/include/indentlog/print/color.hpp @@ -14,6 +14,18 @@ namespace xo { rgb }; + inline std::ostream & + operator<< (std::ostream & os, color_encoding x) { + switch(x) { + case color_encoding::none: os << "none"; break; + case color_encoding::ansi: os << "ansi"; break; + case color_encoding::xterm: os << "xterm"; break; + case color_encoding::rgb: os << "rgb"; break; + default: os << "???"; break; + } + return os; + } /*operator<<*/ + /* specify a color (consistent with ANSI escape sequences - the Select Graphics Rendition subset * see [[https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences]] * @@ -106,6 +118,12 @@ namespace xo { std::uint32_t code_ = 0; }; /*color_spec_type*/ + inline std::ostream & + operator<< (std::ostream & os, color_spec_type const & x) { + os << ""; + return os; + } /*operator<<*/ + enum class coloring_control_flags : std::uint8_t { none = 0x0, color_on = 0x01, diff --git a/include/indentlog/print/concat.hpp b/include/indentlog/print/concat.hpp index 31bd6b43..223900ec 100644 --- a/include/indentlog/print/concat.hpp +++ b/include/indentlog/print/concat.hpp @@ -20,6 +20,11 @@ namespace xo { T2 x2_; }; /*concat_impl*/ + template + T1 concat(T1 && x1) { + return x1; + } /*concat*/ + template concat_impl concat(T1 && x1, T2 && x2) { return concat_impl(std::move(x1), std::move(x2)); diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 6e6352b5..1513f8bc 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -3,7 +3,7 @@ set(SELF_EXECUTABLE_NAME utest.indentlog) set(SELF_SOURCE_FILES fixed.test.cpp quoted.test.cpp vector.test.cpp array.test.cpp timeutil.test.cpp tag.test.cpp - filename.test.cpp + filename.test.cpp code_location.test.cpp indentlog_utest_main.cpp) add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) diff --git a/utest/code_location.test.cpp b/utest/code_location.test.cpp new file mode 100644 index 00000000..64f1a0c4 --- /dev/null +++ b/utest/code_location.test.cpp @@ -0,0 +1,47 @@ +/* @file code_location.test.cpp */ + +#include "indentlog/print/code_location.hpp" +#include "indentlog/print/color.hpp" +#include "indentlog/print/tag.hpp" +#include +#include + +using namespace xo; + +namespace ut { + struct code_location_tcase { + code_location_tcase() = default; + code_location_tcase(std::string_view file, std::uint32_t line, color_spec_type color, std::string_view output) + : file_{file}, line_{line}, color_{color}, output_{output} {} + + /* target time value to test */ + std::string_view file_; + std::uint32_t line_; + color_spec_type color_; + std::string_view output_; + }; /*code_location_tcase*/ + + std::vector s_code_location_tcase_v( + { + code_location_tcase("/foo/bar", 123, color_spec_type::none(), "[bar:123]"), + code_location_tcase("/foo/bar", 123, color_spec_type::blue(), "[\033[31;34mbar\033[0m:123]"), + code_location_tcase("/foo/bar", 123, color_spec_type::xterm(196), "[\033[38;5;196mbar\033[0m:123]"), + code_location_tcase("/foo/bar", 123, color_spec_type::rgb(255, 127, 63), "[\033[38;2;255;127;63mbar\033[0m:123]"), + }); + + TEST_CASE("code_location", "[code_location]") { + for (std::uint32_t i_tc = 0, z_tc = s_code_location_tcase_v.size(); i_tc < z_tc; ++i_tc) { + code_location_tcase const & tc = s_code_location_tcase_v[i_tc]; + + INFO(tostr(xtag("i_tc", i_tc), xtag("file", tc.file_), xtag("line", tc.line_), xtag("color", tc.color_))); + INFO(xtag("tc.output", tc.output_)); + + std::stringstream ss; + ss << code_location(tc.file_, tc.line_, tc.color_); + + REQUIRE(ss.str() == tc.output_); + } + } /*TEST_CASE(code_location)*/ +} /*namespace ut*/ + +/* end code_location.test.cpp */ diff --git a/utest/filename.test.cpp b/utest/filename.test.cpp index ee5fdfaf..ebff42b4 100644 --- a/utest/filename.test.cpp +++ b/utest/filename.test.cpp @@ -21,6 +21,8 @@ namespace ut { std::vector s_filename_tcase_v( { filename_tcase("foo", "foo"), + filename_tcase("/foo", "foo"), + filename_tcase("/foo/bar", "bar"), }); TEST_CASE("filename", "[filename]") { From 3983361e78f56d84c6137b3b9861e2830cab08a4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Sep 2023 15:14:50 -0400 Subject: [PATCH 098/170] color: bugfix: color_off() needs to know color spec --- include/indentlog/print/color.hpp | 8 ++++---- include/indentlog/print/function.hpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/indentlog/print/color.hpp b/include/indentlog/print/color.hpp index f8b64985..bcd3e634 100644 --- a/include/indentlog/print/color.hpp +++ b/include/indentlog/print/color.hpp @@ -175,19 +175,19 @@ namespace xo { }; /*color_impl*/ template - color_impl with_color(color_spec_type spec, Contents && contents) { + color_impl with_color(color_spec_type const & spec, Contents && contents) { return color_impl(coloring_control_flags::all, spec, std::forward(contents)); } /*with_color*/ inline color_impl - color_on(color_spec_type spec) { + color_on(color_spec_type const & spec) { return color_impl(coloring_control_flags::color_on, spec, 0); } /*color_on*/ inline color_impl - color_off() { + color_off(color_spec_type const & spec) { /* any spec other than color_spec_type::none() works here */ - return color_impl(coloring_control_flags::color_off, color_spec_type::white(), 0); + return color_impl(coloring_control_flags::color_off, spec, 0); } /*color_off*/ template diff --git a/include/indentlog/print/function.hpp b/include/indentlog/print/function.hpp index 5bbfbd05..0e5584f8 100644 --- a/include/indentlog/print/function.hpp +++ b/include/indentlog/print/function.hpp @@ -262,12 +262,12 @@ namespace xo { /* omit namespace qualifiers and template arguments */ os << color_on(fn.colorspec()); function_name::print_streamlined(os, fn.pretty()); - os << color_off(); + os << color_off(fn.colorspec()); break; case function_style::simple: os << color_on(fn.colorspec()); function_name::print_simple(os, fn.pretty()); - os << color_off(); + os << color_off(fn.colorspec()); break; } From 7aa534567ff171cfcd43bb3342b7a9ae3b8808db Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Sep 2023 15:15:11 -0400 Subject: [PATCH 099/170] utest: + function_name test --- include/indentlog/print/function.hpp | 12 ++++++ utest/CMakeLists.txt | 2 +- utest/function.test.cpp | 59 ++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 utest/function.test.cpp diff --git a/include/indentlog/print/function.hpp b/include/indentlog/print/function.hpp index 0e5584f8..2689ef1a 100644 --- a/include/indentlog/print/function.hpp +++ b/include/indentlog/print/function.hpp @@ -24,6 +24,18 @@ namespace xo { simple }; + inline std::ostream & + operator<< (std::ostream & os, function_style x) { + switch(x) { + case function_style::literal: os << "literal"; break; + case function_style::pretty: os << "pretty"; break; + case function_style::streamlined: os << "streamlined"; break; + case function_style::simple: os << "simple"; break; + default: os << "???"; break; + } + return os; + } /*operator<<*/ + /* Tag to drive header-only expression */ template class function_name_impl { diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 1513f8bc..c6e6e596 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -3,7 +3,7 @@ set(SELF_EXECUTABLE_NAME utest.indentlog) set(SELF_SOURCE_FILES fixed.test.cpp quoted.test.cpp vector.test.cpp array.test.cpp timeutil.test.cpp tag.test.cpp - filename.test.cpp code_location.test.cpp + filename.test.cpp code_location.test.cpp function.test.cpp indentlog_utest_main.cpp) add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) diff --git a/utest/function.test.cpp b/utest/function.test.cpp new file mode 100644 index 00000000..323a3f30 --- /dev/null +++ b/utest/function.test.cpp @@ -0,0 +1,59 @@ +/* @file function.test.cpp */ + +#include "indentlog/print/function.hpp" +#include "indentlog/print/tag.hpp" +#include +#include + +using namespace xo; + +namespace ut { + struct function_tcase { + function_tcase() = default; + function_tcase(function_style style, color_spec_type spec, std::string_view pretty, std::string_view output) + : style_{style}, spec_{spec}, pretty_{pretty}, output_{output} {} + + /* function style: literal|pretty|streamlined|simple*/ + function_style style_; + /* color spec for output */ + color_spec_type spec_; + /* function signature (as per __PRETTY_FUNCTION__) */ + std::string_view pretty_; + /* output text */ + std::string_view output_; + }; /*function_tcase*/ + + std::vector s_function_tcase_v( + { + function_tcase(function_style::pretty, color_spec_type::none(), "void foo() const", "[void foo() const]"), + function_tcase(function_style::streamlined, color_spec_type::none(), "void foo() const", "foo"), + function_tcase(function_style::simple, color_spec_type::none(), "void foo() const", "foo"), + + function_tcase(function_style::pretty, color_spec_type::none(), "void xo::class::foo() const", "[void xo::class::foo() const]"), + function_tcase(function_style::streamlined, color_spec_type::none(), "void xo::class::foo() const", "class::foo"), + function_tcase(function_style::simple, color_spec_type::none(), "void xo::class::foo() const", "foo"), + + function_tcase(function_style::pretty, color_spec_type::blue(), "void xo::class::foo() const", "[\033[31;34mvoid xo::class::foo() const\033[0m]"), + }); + + TEST_CASE("function", "[function]") { + tag_config::tag_color = color_spec_type::none(); + + for (std::uint32_t i_tc = 0, z_tc = s_function_tcase_v.size(); i_tc < z_tc; ++i_tc) { + function_tcase const & tc = s_function_tcase_v[i_tc]; + + INFO(tostr(xtag("i_tc", i_tc), xtag("style", tc.style_), xtag("spec", tc.spec_), xtag("pretty", tc.pretty_))); + + std::stringstream ss; + ss << function_name(tc.style_, tc.spec_, tc.pretty_); + + INFO(xtag("ss.str", ss.str())); + + REQUIRE(ss.str() == tc.output_); + } + + REQUIRE(s_function_tcase_v.size() > 1); + } +} /*namespace ut*/ + +/* end function.test.cpp */ From 4f6f045423289cae4d1422594ead8a5b82120b63 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Sep 2023 15:19:06 -0400 Subject: [PATCH 100/170] utest: ++ function test --- utest/function.test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utest/function.test.cpp b/utest/function.test.cpp index 323a3f30..bd71bd35 100644 --- a/utest/function.test.cpp +++ b/utest/function.test.cpp @@ -25,6 +25,8 @@ namespace ut { std::vector s_function_tcase_v( { + function_tcase(function_style::literal, color_spec_type::none(), "anything goes here", "anything goes here"), + function_tcase(function_style::pretty, color_spec_type::none(), "void foo() const", "[void foo() const]"), function_tcase(function_style::streamlined, color_spec_type::none(), "void foo() const", "foo"), function_tcase(function_style::simple, color_spec_type::none(), "void foo() const", "foo"), From 5d6bd7cd405bec3663efbf475c891c3db8be509a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 22 Sep 2023 19:46:26 -0400 Subject: [PATCH 101/170] build: + cmake boilerplate to make indentlog cmake-findable --- CMakeLists.txt | 51 +++++++++++++++++++++++++++------- cmake/indentlogConfig.cmake.in | 4 +++ 2 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 cmake/indentlogConfig.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index b8365f9c..472cd5cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required(VERSION 3.10) -project(nestlog VERSION 0.1) +project(indentlog VERSION 0.1) enable_language(CXX) include(cmake/nestlog.cmake) include(cmake/code-coverage.cmake) enable_testing() -# activate code coverage for all executables + libraries (when -DCODE_COVERAGE=ON ??) +# activate code coverage for all executables + libraries (when -DCODE_COVERAGE=ON) add_code_coverage() # 1. assuming that /nix/store/ prefixes .hpp files belonging to gcc, catch2 etc. @@ -27,6 +27,9 @@ if(NOT USER) set(USER $ENV{USER}) endif() +# hmm. this works if explicitly given with cmake: +# cmake -DCMAKE_INSTALL_PREFIX=/home/roland/local path/to/source +# but not as default if(NOT CMAKE_INSTALL_PREFIX) set(CMAKE_INSTALL_PREFIX /home/${USER}/local CACHE STRING "install directory") endif() @@ -37,16 +40,44 @@ endif() add_subdirectory(example) add_subdirectory(utest) -# header-only library -#add_library(indentlog INTERFACE) -#target_include_directories(indentlog INTERFACE -# $ -# $ -# ) +# header-only library. +# see [[https://stackoverflow.com/questions/47718485/install-and-export-interface-only-library-cmake]] # -#install(TARGETS indentlog -# PUBLIC_HEADER DESTINATION include) # COMPONENT Development +add_library(indentlog INTERFACE) +target_include_directories(indentlog INTERFACE + $ + $ + ) +include(CMakePackageConfigHelpers) +write_basic_package_version_file("${PROJECT_BINARY_DIR}/indentlogConfigVersion.cmake" + VERSION 0.1 + COMPATIBILITY AnyNewerVersion +) + +install( + TARGETS indentlog + EXPORT indentlogTargets + LIBRARY DESTINATION lib COMPONENT Runtime + ARCHIVE DESTINATION lib COMPONENT Development + RUNTIME DESTINATION bin COMPONENT Runtime + PUBLIC_HEADER DESTINATION include COMPONENT Development + BUNDLE DESTINATION bin COMPONENT Runtime + ) + +include(CMakePackageConfigHelpers) +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/indentlogConfig.cmake.in" + "${PROJECT_BINARY_DIR}/indentlogConfig.cmake" + INSTALL_DESTINATION lib/cmake/indentlog + ) + +install(EXPORT indentlogTargets DESTINATION lib/cmake/indentlog) +install( + FILES + "${PROJECT_BINARY_DIR}/indentlogConfigVersion.cmake" + "${PROJECT_BINARY_DIR}/indentlogConfig.cmake" + DESTINATION lib/cmake/indentlog) install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION include) install(TARGETS hello DESTINATION bin/indentlog/example) diff --git a/cmake/indentlogConfig.cmake.in b/cmake/indentlogConfig.cmake.in new file mode 100644 index 00000000..cc57615e --- /dev/null +++ b/cmake/indentlogConfig.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/indentlogTargets.cmake") +check_required_components("@PROJECT_NAME@") From bf92724aa5d123b6acb9b00318e579828fb9ff38 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 24 Sep 2023 12:49:03 -0400 Subject: [PATCH 102/170] bugfix: default CMAKE_INSTALL_RPATH --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 472cd5cf..eb5f2cf2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ if(NOT CMAKE_INSTALL_PREFIX) set(CMAKE_INSTALL_PREFIX /home/${USER}/local CACHE STRING "install directory") endif() if(NOT CMAKE_INSTALL_RPATH) - set(CMAKE_INSTALL_RPATH /home/${USER}/local/lib CACHE STRING "runpath in installed libraries/executables") + set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib CACHE STRING "runpath in installed libraries/executables") endif() add_subdirectory(example) From efa8afa9c2b9924638022a73366b4ac4332ee8bb Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 26 Sep 2023 17:24:44 -0400 Subject: [PATCH 103/170] github: fetch new xo-cmake dep --- .github/workflows/cmake-single-platform.yml | 27 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 059cf017..7be18768 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -26,16 +26,35 @@ jobs: # install catch2. see [[https://stackoverflow.com/questions/57982945/how-to-apt-get-install-in-a-github-actions-workflow]] run: sudo apt-get install -y catch2 - - name: Configure CMake + # ---------------------------------------------------------------- + + - name: Clone xo-cmake + uses: actions/checkout@v3 + with: + repository: Rconybea/xo-cmake + path: repo/xo-cmake + + - name: Configure xo-cmake + run: cmake -B ${{github.workspace}}/build_xo-cmake -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local repo/xo-cmake + + - name: Build xo-cmake (trivial) + run: cmake --build ${{github.worskpace}}/build_xo-cmake --config ${{env.BUILD_TYPE}} + + - name: Install xo-cmake + run: cmake --install ${{github.workspace}}/build_xo-cmake + + # ---------------------------------------------------------------- + + - name: Configure self (indentlog) # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + run: cmake -B ${{github.workspace}}/build -DCMAKE_MODULE_PATH=${{github.workspace}/local/share/cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - - name: Build + - name: Build self (indentlog) # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - - name: Test + - name: Test self (indentlog) working-directory: ${{github.workspace}}/build # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail From 31abb2ae417c555a3fb9c2eb93c7e45de092dfa6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 26 Sep 2023 17:25:43 -0400 Subject: [PATCH 104/170] github: bugfix: typo in .yml --- .github/workflows/cmake-single-platform.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 7be18768..37a27cad 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -48,7 +48,7 @@ jobs: - name: Configure self (indentlog) # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_MODULE_PATH=${{github.workspace}/local/share/cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + run: cmake -B ${{github.workspace}}/build -DCMAKE_MODULE_PATH=${{github.workspace}}/local/share/cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build self (indentlog) # Build your program with the given configuration From 27c4535bf6b7b11eb8529b4066ff67132772612b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 26 Sep 2023 17:26:48 -0400 Subject: [PATCH 105/170] github: bugfix: typo (#2) in .yml --- .github/workflows/cmake-single-platform.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 37a27cad..7787e3c5 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -38,7 +38,7 @@ jobs: run: cmake -B ${{github.workspace}}/build_xo-cmake -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local repo/xo-cmake - name: Build xo-cmake (trivial) - run: cmake --build ${{github.worskpace}}/build_xo-cmake --config ${{env.BUILD_TYPE}} + run: cmake --build ${{github.workspace}}/build_xo-cmake --config ${{env.BUILD_TYPE}} - name: Install xo-cmake run: cmake --install ${{github.workspace}}/build_xo-cmake From aa1256fca7b7eb1c70c1e420212075c4ab359ce0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 27 Sep 2023 11:05:31 -0400 Subject: [PATCH 106/170] build: + xo-cmake dependency --- CMakeLists.txt | 2 ++ README.md | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb5f2cf2..fb740612 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.10) project(indentlog VERSION 0.1) enable_language(CXX) +# common XO cmake macros (see proj/xo-cmake) +include(xo_macros/xo_cxx) include(cmake/nestlog.cmake) include(cmake/code-coverage.cmake) diff --git a/README.md b/README.md index bd376bd9..d0202a94 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,11 @@ Indentlog is a lightweight header-only library for console logging. ## Getting Started +### build + install `xo-cmake` dependency (cmake macros) + +see [github/Rconybea/xo-cmake](https://github.com/Rconybea/xo-cmake) +(almost trivial, installs a few `.cmake` files) + ### copy repository locally ``` @@ -32,7 +37,7 @@ indentlog $ cd indentlog $ mkdir build $ cd build -$ cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. +$ cmake -DCMAKE_MODULE_PATH=/usr/local/share/cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. $ make $ make install ``` From 41c20930278677731acb2a64d65845cfd6a50aa0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 27 Sep 2023 13:19:50 -0400 Subject: [PATCH 107/170] build: indentlog: use new xo-cmake macros --- CMakeLists.txt | 69 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb740612..86f6de3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,36 +51,51 @@ target_include_directories(indentlog INTERFACE $ ) -include(CMakePackageConfigHelpers) -write_basic_package_version_file("${PROJECT_BINARY_DIR}/indentlogConfigVersion.cmake" - VERSION 0.1 - COMPATIBILITY AnyNewerVersion -) +# ---------------------------------------------------------------- +# provide find_package() support -install( - TARGETS indentlog - EXPORT indentlogTargets - LIBRARY DESTINATION lib COMPONENT Runtime - ARCHIVE DESTINATION lib COMPONENT Development - RUNTIME DESTINATION bin COMPONENT Runtime - PUBLIC_HEADER DESTINATION include COMPONENT Development - BUNDLE DESTINATION bin COMPONENT Runtime - ) +xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) -include(CMakePackageConfigHelpers) -configure_package_config_file( - "${PROJECT_SOURCE_DIR}/cmake/indentlogConfig.cmake.in" - "${PROJECT_BINARY_DIR}/indentlogConfig.cmake" - INSTALL_DESTINATION lib/cmake/indentlog - ) +# ---------------------------------------------------------------- -install(EXPORT indentlogTargets DESTINATION lib/cmake/indentlog) -install( - FILES - "${PROJECT_BINARY_DIR}/indentlogConfigVersion.cmake" - "${PROJECT_BINARY_DIR}/indentlogConfig.cmake" - DESTINATION lib/cmake/indentlog) -install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION include) +xo_install_library2(${PROJECT_NAME}) + +#include(CMakePackageConfigHelpers) +#write_basic_package_version_file("${PROJECT_BINARY_DIR}/indentlogConfigVersion.cmake" +# VERSION 0.1 +# COMPATIBILITY AnyNewerVersion +#) +# +#install( +# TARGETS indentlog +# EXPORT indentlogTargets +# LIBRARY DESTINATION lib COMPONENT Runtime +# ARCHIVE DESTINATION lib COMPONENT Development +# RUNTIME DESTINATION bin COMPONENT Runtime +# PUBLIC_HEADER DESTINATION include COMPONENT Development +# BUNDLE DESTINATION bin COMPONENT Runtime +# ) + +#include(CMakePackageConfigHelpers) +#configure_package_config_file( +# "${PROJECT_SOURCE_DIR}/cmake/indentlogConfig.cmake.in" +# "${PROJECT_BINARY_DIR}/indentlogConfig.cmake" +# INSTALL_DESTINATION lib/cmake/indentlog +# ) +# +#install(EXPORT indentlogTargets DESTINATION lib/cmake/indentlog) +#install( +# FILES +# "${PROJECT_BINARY_DIR}/indentlogConfigVersion.cmake" +# "${PROJECT_BINARY_DIR}/indentlogConfig.cmake" +# DESTINATION lib/cmake/indentlog) + +# ---------------------------------------------------------------- +# install .hpp + +xo_install_include_tree() + +# ---------------------------------------------------------------- install(TARGETS hello DESTINATION bin/indentlog/example) install(TARGETS ex1 DESTINATION bin/indentlog/example) From 7f6579bf30e315cda4c60c679ae455dc443f5520 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 27 Sep 2023 16:20:50 -0400 Subject: [PATCH 108/170] indentlog: github: fix workflow --- .github/workflows/cmake-single-platform.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 7787e3c5..433a3f9f 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -48,8 +48,7 @@ jobs: - name: Configure self (indentlog) # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_MODULE_PATH=${{github.workspace}}/local/share/cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - + run: cmake -B ${{github.workspace}}/build -DCMAKE_MODULE_PATH=${{github.workspace}}/local/share/cmake -DCMAKE_PREFIX_PATH=${{github.workspace}}/local -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build self (indentlog) # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} From 49567a59a150370b219793d1d588fd99e5ca9a1c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 27 Sep 2023 17:30:13 -0400 Subject: [PATCH 109/170] indentlog: build: streamline using xo-cmake macros --- CMakeLists.txt | 42 ++++++------------------------------ example/ex1/CMakeLists.txt | 2 +- example/ex2/CMakeLists.txt | 2 +- example/ex3/CMakeLists.txt | 2 +- example/ex4/CMakeLists.txt | 2 +- example/hello/CMakeLists.txt | 2 +- utest/CMakeLists.txt | 2 +- 7 files changed, 12 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86f6de3a..c8c5c655 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,7 @@ enable_language(CXX) # common XO cmake macros (see proj/xo-cmake) include(xo_macros/xo_cxx) -include(cmake/nestlog.cmake) -include(cmake/code-coverage.cmake) +include(xo_macros/code-coverage) enable_testing() # activate code coverage for all executables + libraries (when -DCODE_COVERAGE=ON) @@ -46,10 +45,11 @@ add_subdirectory(utest) # see [[https://stackoverflow.com/questions/47718485/install-and-export-interface-only-library-cmake]] # add_library(indentlog INTERFACE) -target_include_directories(indentlog INTERFACE - $ - $ - ) +xo_include_headeronly_options2(indentlog) +#target_include_directories(indentlog INTERFACE +# $ +# $ +# ) # ---------------------------------------------------------------- # provide find_package() support @@ -60,36 +60,6 @@ xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets xo_install_library2(${PROJECT_NAME}) -#include(CMakePackageConfigHelpers) -#write_basic_package_version_file("${PROJECT_BINARY_DIR}/indentlogConfigVersion.cmake" -# VERSION 0.1 -# COMPATIBILITY AnyNewerVersion -#) -# -#install( -# TARGETS indentlog -# EXPORT indentlogTargets -# LIBRARY DESTINATION lib COMPONENT Runtime -# ARCHIVE DESTINATION lib COMPONENT Development -# RUNTIME DESTINATION bin COMPONENT Runtime -# PUBLIC_HEADER DESTINATION include COMPONENT Development -# BUNDLE DESTINATION bin COMPONENT Runtime -# ) - -#include(CMakePackageConfigHelpers) -#configure_package_config_file( -# "${PROJECT_SOURCE_DIR}/cmake/indentlogConfig.cmake.in" -# "${PROJECT_BINARY_DIR}/indentlogConfig.cmake" -# INSTALL_DESTINATION lib/cmake/indentlog -# ) -# -#install(EXPORT indentlogTargets DESTINATION lib/cmake/indentlog) -#install( -# FILES -# "${PROJECT_BINARY_DIR}/indentlogConfigVersion.cmake" -# "${PROJECT_BINARY_DIR}/indentlogConfig.cmake" -# DESTINATION lib/cmake/indentlog) - # ---------------------------------------------------------------- # install .hpp diff --git a/example/ex1/CMakeLists.txt b/example/ex1/CMakeLists.txt index 6af29d79..a9d1b27d 100644 --- a/example/ex1/CMakeLists.txt +++ b/example/ex1/CMakeLists.txt @@ -1,2 +1,2 @@ add_executable(ex1 ex1.cpp) -xo_include_options(ex1) +xo_include_options2(ex1) diff --git a/example/ex2/CMakeLists.txt b/example/ex2/CMakeLists.txt index 1ac5735a..20026b03 100644 --- a/example/ex2/CMakeLists.txt +++ b/example/ex2/CMakeLists.txt @@ -1,2 +1,2 @@ add_executable(ex2 ex2.cpp) -xo_include_options(ex2) +xo_include_options2(ex2) diff --git a/example/ex3/CMakeLists.txt b/example/ex3/CMakeLists.txt index d81e0e99..9791a931 100644 --- a/example/ex3/CMakeLists.txt +++ b/example/ex3/CMakeLists.txt @@ -1,2 +1,2 @@ add_executable(ex3 ex3.cpp) -xo_include_options(ex3) +xo_include_options2(ex3) diff --git a/example/ex4/CMakeLists.txt b/example/ex4/CMakeLists.txt index 02c1f301..2a6b9c31 100644 --- a/example/ex4/CMakeLists.txt +++ b/example/ex4/CMakeLists.txt @@ -1,2 +1,2 @@ add_executable(ex4 ex4.cpp) -xo_include_options(ex4) +xo_include_options2(ex4) diff --git a/example/hello/CMakeLists.txt b/example/hello/CMakeLists.txt index d6f694e6..1ff23000 100644 --- a/example/hello/CMakeLists.txt +++ b/example/hello/CMakeLists.txt @@ -1,2 +1,2 @@ add_executable(hello hello.cpp) -xo_include_options(hello) +xo_include_options2(hello) diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index c6e6e596..fbbeb9d7 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -7,7 +7,7 @@ set(SELF_SOURCE_FILES indentlog_utest_main.cpp) add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) -xo_include_options(${SELF_EXECUTABLE_NAME}) +xo_include_options2(${SELF_EXECUTABLE_NAME}) add_test(NAME ${SELF_EXECUTABLE_NAME} COMMAND ${SELF_EXECUTABLE_NAME}) target_code_coverage(${SELF_EXECUTABLE_NAME} AUTO ALL) From 66d8b439416e80918c4ff5b1cdea4b8f8e32ca6a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 27 Sep 2023 17:59:12 -0400 Subject: [PATCH 110/170] indentlog: build: streamline using xo-cmake macros --- CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c8c5c655..db51a3d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,9 +34,8 @@ endif() if(NOT CMAKE_INSTALL_PREFIX) set(CMAKE_INSTALL_PREFIX /home/${USER}/local CACHE STRING "install directory") endif() -if(NOT CMAKE_INSTALL_RPATH) - set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib CACHE STRING "runpath in installed libraries/executables") -endif() + +xo_toplevel_compile_options() add_subdirectory(example) add_subdirectory(utest) From 50b787759391477b66810471812812037b1f9c45 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 27 Sep 2023 18:13:46 -0400 Subject: [PATCH 111/170] indentlog: consolidate CMAKE_CXX_STANDARD setting --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db51a3d9..423b00e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,9 +18,6 @@ add_code_coverage() # add_code_coverage_all_targets(EXCLUDE /nix/store/* utest/*) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) - # always write compile_commands.json set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") From afd595185b5d4b879a19eb03af3d8e971feffdcc Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 27 Sep 2023 18:23:21 -0400 Subject: [PATCH 112/170] indentlog: consolidate CMAKE_EXPORT_COMPILE_COMMANDS + tidy --- CMakeLists.txt | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 423b00e4..b8553e93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,20 +18,6 @@ add_code_coverage() # add_code_coverage_all_targets(EXCLUDE /nix/store/* utest/*) -# always write compile_commands.json -set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") - -if(NOT USER) - set(USER $ENV{USER}) -endif() - -# hmm. this works if explicitly given with cmake: -# cmake -DCMAKE_INSTALL_PREFIX=/home/roland/local path/to/source -# but not as default -if(NOT CMAKE_INSTALL_PREFIX) - set(CMAKE_INSTALL_PREFIX /home/${USER}/local CACHE STRING "install directory") -endif() - xo_toplevel_compile_options() add_subdirectory(example) From 8a325bab4b4b4876c3bd63adcfb71957ec5c31a9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Oct 2023 16:59:44 -0400 Subject: [PATCH 113/170] make catch2 include path precise --- utest/CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index c6e6e596..a135895a 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -15,7 +15,18 @@ target_code_coverage(${SELF_EXECUTABLE_NAME} AUTO ALL) # ---------------------------------------------------------------- # 3rd party dependency: catch2 +# 1. using target_link_libraries(.. Catch2) here doesn't work; +# build tries to link to a Catch2 library. +# perhaps Catch2 target not declared INTERFACE? +# 2. nix build doesn't need this; dependency on catch2 +# puts include directory in NIX_CFLAGS_COMPILE, so stuff 'just works' +# find_package(Catch2 2 REQUIRED) +set(Catch2_INCLUDES "${Catch2_DIR}/../..") +target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC ${Catch2_INCLUDES}) + +#xo_internal_dependency(${SELF_EXECUTABLE_NAME} Catch2) +#target_link_libraries(${SELF_EXECUTABLE_NAME} PUBLIC Catch2) # ---------------------------------------------------------------- # make standard directories for std:: includes explicit From 2fc5a385fda05db2c87425197bc902e64bd9c2b1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Oct 2023 17:00:05 -0400 Subject: [PATCH 114/170] + .gitignore --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..81c5ae6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# symlink to ${my_build_directory}/compile_commands.json to make LSP work +compile_commands.json +# lsp keeps state here +.cache +# typical build dirs +build +ccov From abec2b994edc734d119eacbf7825780fde7fecb8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Oct 2023 17:01:57 -0400 Subject: [PATCH 115/170] + MARKDOWN + TODO --- MARKDOWN | 31 +++++++++++++++++++++++++++++++ TODO | 5 +++++ 2 files changed, 36 insertions(+) create mode 100644 MARKDOWN create mode 100644 TODO diff --git a/MARKDOWN b/MARKDOWN new file mode 100644 index 00000000..990d8275 --- /dev/null +++ b/MARKDOWN @@ -0,0 +1,31 @@ +# heading level 1 +## heading level 2 +###### heading level 6 + +blank line new paragraph +two spaces at eod force line break + +**bold** bold text +__bold__ also bold text (but don't embed within a word) + +*italics* + +***bolditalic*** + +> text to blockquote +> +> + more paragraphs + +> text to blockquote +> +>> with nested blockquote + +- bullets also can prefix with + or * + +1. numbered lists + +indent 4 spaces (or 1 tab) for code blocks + +`inline code` + +--- on a line by itself -> horizontal rule diff --git a/TODO b/TODO new file mode 100644 index 00000000..bc404053 --- /dev/null +++ b/TODO @@ -0,0 +1,5 @@ + + +sphinx_markdown_builder + +https://stackoverflow.com/questions/13396856/markdown-output-for-sphinx-based-documentation From 19ca2b6a340b26f6227e2bb80e425792cc6504a0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Oct 2023 17:09:26 -0400 Subject: [PATCH 116/170] (abandoned experiment with get_target_property()) --- utest/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 19bf25e6..466cbe0d 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -22,7 +22,8 @@ target_code_coverage(${SELF_EXECUTABLE_NAME} AUTO ALL) # puts include directory in NIX_CFLAGS_COMPILE, so stuff 'just works' # find_package(Catch2 2 REQUIRED) -set(Catch2_INCLUDES "${Catch2_DIR}/../..") +set(Catch2_INCLUDES "${Catch2_DIR}/../../../include") +#get_target_property(Catch2_INCLUDES Catch2 INCLUDE_DIRECTORIES) target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC ${Catch2_INCLUDES}) #xo_internal_dependency(${SELF_EXECUTABLE_NAME} Catch2) From dfbc753fd6faae93f6df85b42cddb3378c1bb9e4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Oct 2023 17:16:52 -0400 Subject: [PATCH 117/170] try canonical cmake form for catch2 dep --- utest/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 466cbe0d..b94f1dd5 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -22,9 +22,10 @@ target_code_coverage(${SELF_EXECUTABLE_NAME} AUTO ALL) # puts include directory in NIX_CFLAGS_COMPILE, so stuff 'just works' # find_package(Catch2 2 REQUIRED) -set(Catch2_INCLUDES "${Catch2_DIR}/../../../include") -#get_target_property(Catch2_INCLUDES Catch2 INCLUDE_DIRECTORIES) -target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC ${Catch2_INCLUDES}) +target_link_libraries(${SELF_EXECUTABLE_NAME} Catch2::Catch2) + +#set(Catch2_INCLUDES "${Catch2_DIR}/../../../include") +#target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC ${Catch2_INCLUDES}) #xo_internal_dependency(${SELF_EXECUTABLE_NAME} Catch2) #target_link_libraries(${SELF_EXECUTABLE_NAME} PUBLIC Catch2) From dfc7aa23d7815e65b099b1e6790fd05e92c6bc60 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 3 Oct 2023 17:27:35 -0400 Subject: [PATCH 118/170] indentlog: use xo_external_target_dependency() for catch2 --- utest/CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index b94f1dd5..1b92e999 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -15,14 +15,17 @@ target_code_coverage(${SELF_EXECUTABLE_NAME} AUTO ALL) # ---------------------------------------------------------------- # 3rd party dependency: catch2 +xo_external_target_dependency(${SELF_EXECUTABLE_NAME} Catch2 Catch2::Catch2) + # 1. using target_link_libraries(.. Catch2) here doesn't work; # build tries to link to a Catch2 library. # perhaps Catch2 target not declared INTERFACE? # 2. nix build doesn't need this; dependency on catch2 # puts include directory in NIX_CFLAGS_COMPILE, so stuff 'just works' # -find_package(Catch2 2 REQUIRED) -target_link_libraries(${SELF_EXECUTABLE_NAME} Catch2::Catch2) + +#find_package(Catch2 2 REQUIRED) +#target_link_libraries(${SELF_EXECUTABLE_NAME} Catch2::Catch2) #set(Catch2_INCLUDES "${Catch2_DIR}/../../../include") #target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC ${Catch2_INCLUDES}) From e27c64ce15b3ea96bec488d035d6207989f98c17 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 4 Oct 2023 00:01:55 -0400 Subject: [PATCH 119/170] build: standardizing --- CMakeLists.txt | 22 +- README.md | 3 +- cmake/code-coverage.cmake | 678 -------------------------------------- cmake/nestlog.cmake | 30 -- 4 files changed, 11 insertions(+), 722 deletions(-) delete mode 100644 cmake/code-coverage.cmake delete mode 100644 cmake/nestlog.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index b8553e93..5a780b05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,5 @@ +# indentlog/CMakeLists.txt + cmake_minimum_required(VERSION 3.10) project(indentlog VERSION 0.1) @@ -7,6 +9,9 @@ enable_language(CXX) include(xo_macros/xo_cxx) include(xo_macros/code-coverage) +# ---------------------------------------------------------------- +# unit test setup + enable_testing() # activate code coverage for all executables + libraries (when -DCODE_COVERAGE=ON) add_code_coverage() @@ -18,6 +23,8 @@ add_code_coverage() # add_code_coverage_all_targets(EXCLUDE /nix/store/* utest/*) +# ---------------------------------------------------------------- + xo_toplevel_compile_options() add_subdirectory(example) @@ -28,24 +35,13 @@ add_subdirectory(utest) # add_library(indentlog INTERFACE) xo_include_headeronly_options2(indentlog) -#target_include_directories(indentlog INTERFACE -# $ -# $ -# ) - -# ---------------------------------------------------------------- -# provide find_package() support - -xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) # ---------------------------------------------------------------- +# standard install + provide find_package() support xo_install_library2(${PROJECT_NAME}) - -# ---------------------------------------------------------------- -# install .hpp - xo_install_include_tree() +xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) # ---------------------------------------------------------------- diff --git a/README.md b/README.md index d0202a94..9bc7e7aa 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,8 @@ indentlog $ cd indentlog $ mkdir build $ cd build -$ cmake -DCMAKE_MODULE_PATH=/usr/local/share/cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. +$ PREFIX=/usr/local # for example +$ cmake -DCMAKE_MODULE_PATH=${PREFIX}/share/cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} .. $ make $ make install ``` diff --git a/cmake/code-coverage.cmake b/cmake/code-coverage.cmake deleted file mode 100644 index b6b36064..00000000 --- a/cmake/code-coverage.cmake +++ /dev/null @@ -1,678 +0,0 @@ -# -# Copyright (C) 2018-2020 by George Cave - gcave@stablecoder.ca -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -# USAGE: To enable any code coverage instrumentation/targets, the single CMake -# option of `CODE_COVERAGE` needs to be set to 'ON', either by GUI, ccmake, or -# on the command line. -# -# From this point, there are two primary methods for adding instrumentation to -# targets: -# -# 1 - A blanket instrumentation by calling `add_code_coverage()`, where -# all targets in that directory and all subdirectories are automatically -# instrumented. -# -# 2 - Per-target instrumentation by calling -# `target_code_coverage()`, where the target is given and thus only -# that target is instrumented. This applies to both libraries and executables. -# -# To add coverage targets, such as calling `make ccov` to generate the actual -# coverage information for perusal or consumption, call -# `target_code_coverage()` on an *executable* target. -# -# Example 1: All targets instrumented -# -# In this case, the coverage information reported will will be that of the -# `theLib` library target and `theExe` executable. -# -# 1a: Via global command -# -# ~~~ -# add_code_coverage() # Adds instrumentation to all targets -# -# add_library(theLib lib.cpp) -# -# add_executable(theExe main.cpp) -# target_link_libraries(theExe PRIVATE theLib) -# target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target -# # (instrumentation already added via global anyways) -# # for generating code coverage reports. -# ~~~ -# -# 1b: Via target commands -# -# ~~~ -# add_library(theLib lib.cpp) -# target_code_coverage(theLib) # As a library target, adds coverage instrumentation but no targets. -# -# add_executable(theExe main.cpp) -# target_link_libraries(theExe PRIVATE theLib) -# target_code_coverage(theExe) # As an executable target, adds the 'ccov-theExe' target and instrumentation for generating code coverage reports. -# ~~~ -# -# Example 2: Target instrumented, but with regex pattern of files to be excluded -# from report -# -# ~~~ -# add_executable(theExe main.cpp non_covered.cpp) -# target_code_coverage(theExe EXCLUDE non_covered.cpp test/*) # As an executable target, the reports will exclude the non-covered.cpp file, and any files in a test/ folder. -# ~~~ -# -# Example 3: Target added to the 'ccov' and 'ccov-all' targets -# -# ~~~ -# add_code_coverage_all_targets(EXCLUDE test/*) # Adds the 'ccov-all' target set and sets it to exclude all files in test/ folders. -# -# add_executable(theExe main.cpp non_covered.cpp) -# target_code_coverage(theExe AUTO ALL EXCLUDE non_covered.cpp test/*) # As an executable target, adds to the 'ccov' and ccov-all' targets, and the reports will exclude the non-covered.cpp file, and any files in a test/ folder. -# ~~~ - -# Options -option( - CODE_COVERAGE - "Builds targets with code coverage instrumentation. (Requires GCC or Clang)" - OFF) - -# Programs -find_program(LLVM_COV_PATH llvm-cov) -find_program(LLVM_PROFDATA_PATH llvm-profdata) -find_program(LCOV_PATH lcov) -find_program(GENHTML_PATH genhtml) -# Hide behind the 'advanced' mode flag for GUI/ccmake -mark_as_advanced(FORCE LLVM_COV_PATH LLVM_PROFDATA_PATH LCOV_PATH GENHTML_PATH) - -# Variables -set(CMAKE_COVERAGE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/ccov) -set_property(GLOBAL PROPERTY JOB_POOLS ccov_serial_pool=1) - -# Common initialization/checks -if(CODE_COVERAGE AND NOT CODE_COVERAGE_ADDED) - set(CODE_COVERAGE_ADDED ON) - - # Common Targets - add_custom_target( - ccov-preprocessing - COMMAND ${CMAKE_COMMAND} -E make_directory - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY} - DEPENDS ccov-clean) - - if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" - OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") - # Messages - message(STATUS "Building with llvm Code Coverage Tools") - - if(NOT LLVM_COV_PATH) - message(FATAL_ERROR "llvm-cov not found! Aborting.") - else() - # Version number checking for 'EXCLUDE' compatibility - execute_process(COMMAND ${LLVM_COV_PATH} --version - OUTPUT_VARIABLE LLVM_COV_VERSION_CALL_OUTPUT) - string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" LLVM_COV_VERSION - ${LLVM_COV_VERSION_CALL_OUTPUT}) - - if(LLVM_COV_VERSION VERSION_LESS "7.0.0") - message( - WARNING - "target_code_coverage()/add_code_coverage_all_targets() 'EXCLUDE' option only available on llvm-cov >= 7.0.0" - ) - endif() - endif() - - # Targets - if(${CMAKE_VERSION} VERSION_LESS "3.17.0") - add_custom_target( - ccov-clean - COMMAND ${CMAKE_COMMAND} -E remove -f - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list - COMMAND ${CMAKE_COMMAND} -E remove -f - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list) - else() - add_custom_target( - ccov-clean - COMMAND ${CMAKE_COMMAND} -E rm -f - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list - COMMAND ${CMAKE_COMMAND} -E rm -f - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list) - endif() - - # Used to get the shared object file list before doing the main all- - # processing - add_custom_target( - ccov-libs - COMMAND ; - COMMENT "libs ready for coverage report.") - - elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES - "GNU") - # Messages - message(STATUS "Building with lcov Code Coverage Tools") - - if(CMAKE_BUILD_TYPE) - string(TOUPPER ${CMAKE_BUILD_TYPE} upper_build_type) - if(NOT ${upper_build_type} STREQUAL "DEBUG") - message( - WARNING - "Code coverage results with an optimized (non-Debug) build may be misleading" - ) - endif() - else() - message( - WARNING - "Code coverage results with an optimized (non-Debug) build may be misleading" - ) - endif() - if(NOT LCOV_PATH) - message(FATAL_ERROR "lcov not found! Aborting...") - endif() - if(NOT GENHTML_PATH) - message(FATAL_ERROR "genhtml not found! Aborting...") - endif() - - # Targets - add_custom_target(ccov-clean COMMAND ${LCOV_PATH} --directory - ${CMAKE_BINARY_DIR} --zerocounters) - - else() - message(FATAL_ERROR "Code coverage requires Clang or GCC. Aborting.") - endif() -endif() - -# Adds code coverage instrumentation to a library, or instrumentation/targets -# for an executable target. -# ~~~ -# EXECUTABLE ADDED TARGETS: -# GCOV/LCOV: -# ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter. -# ccov-${TARGET_NAME} : Generates HTML code coverage report for the associated named target. -# ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report. -# -# LLVM-COV: -# ccov : Generates HTML code coverage report for every target added with 'AUTO' parameter. -# ccov-report : Generates HTML code coverage report for every target added with 'AUTO' parameter. -# ccov-${TARGET_NAME} : Generates HTML code coverage report. -# ccov-report-${TARGET_NAME} : Prints to command line summary per-file coverage information. -# ccov-export-${TARGET_NAME} : Exports the coverage report to a JSON file. -# ccov-show-${TARGET_NAME} : Prints to command line detailed per-line coverage information. -# ccov-all : Generates HTML code coverage report, merging every target added with 'ALL' parameter into a single detailed report. -# ccov-all-report : Prints summary per-file coverage information for every target added with ALL' parameter to the command line. -# ccov-all-export : Exports the coverage report to a JSON file. -# -# Required: -# TARGET_NAME - Name of the target to generate code coverage for. -# Optional: -# PUBLIC - Sets the visibility for added compile options to targets to PUBLIC instead of the default of PRIVATE. -# INTERFACE - Sets the visibility for added compile options to targets to INTERFACE instead of the default of PRIVATE. -# PLAIN - Do not set any target visibility (backward compatibility with old cmake projects) -# AUTO - Adds the target to the 'ccov' target so that it can be run in a batch with others easily. Effective on executable targets. -# ALL - Adds the target to the 'ccov-all' and 'ccov-all-report' targets, which merge several executable targets coverage data to a single report. Effective on executable targets. -# EXTERNAL - For GCC's lcov, allows the profiling of 'external' files from the processing directory -# COVERAGE_TARGET_NAME - For executables ONLY, changes the outgoing target name so instead of `ccov-${TARGET_NAME}` it becomes `ccov-${COVERAGE_TARGET_NAME}`. -# EXCLUDE - Excludes files of the patterns provided from coverage. Note that GCC/lcov excludes by glob pattern, and clang/LLVM excludes via regex! **These do not copy to the 'all' targets.** -# OBJECTS - For executables ONLY, if the provided targets are shared libraries, adds coverage information to the output -# ARGS - For executables ONLY, appends the given arguments to the associated ccov-* executable call -# ~~~ -function(target_code_coverage TARGET_NAME) - # Argument parsing - set(options AUTO ALL EXTERNAL PUBLIC INTERFACE PLAIN) - set(single_value_keywords COVERAGE_TARGET_NAME) - set(multi_value_keywords EXCLUDE OBJECTS ARGS) - cmake_parse_arguments( - target_code_coverage "${options}" "${single_value_keywords}" - "${multi_value_keywords}" ${ARGN}) - - # Set the visibility of target functions to PUBLIC, INTERFACE or default to - # PRIVATE. - if(target_code_coverage_PUBLIC) - set(TARGET_VISIBILITY PUBLIC) - set(TARGET_LINK_VISIBILITY PUBLIC) - elseif(target_code_coverage_INTERFACE) - set(TARGET_VISIBILITY INTERFACE) - set(TARGET_LINK_VISIBILITY INTERFACE) - elseif(target_code_coverage_PLAIN) - set(TARGET_VISIBILITY PUBLIC) - set(TARGET_LINK_VISIBILITY) - else() - set(TARGET_VISIBILITY PRIVATE) - set(TARGET_LINK_VISIBILITY PRIVATE) - endif() - - if(NOT target_code_coverage_COVERAGE_TARGET_NAME) - # If a specific name was given, use that instead. - set(target_code_coverage_COVERAGE_TARGET_NAME ${TARGET_NAME}) - endif() - - if(CODE_COVERAGE) - - # Add code coverage instrumentation to the target's linker command - if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" - OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") - target_compile_options(${TARGET_NAME} ${TARGET_VISIBILITY} - -fprofile-instr-generate -fcoverage-mapping) - target_link_options(${TARGET_NAME} ${TARGET_VISIBILITY} - -fprofile-instr-generate -fcoverage-mapping) - elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES - "GNU") - target_compile_options(${TARGET_NAME} ${TARGET_VISIBILITY} -fprofile-arcs - -ftest-coverage) - target_link_libraries(${TARGET_NAME} ${TARGET_LINK_VISIBILITY} gcov) - endif() - - # Targets - get_target_property(target_type ${TARGET_NAME} TYPE) - - # Add shared library to processing for 'all' targets - if(target_type STREQUAL "SHARED_LIBRARY" AND target_code_coverage_ALL) - if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" - OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") - add_custom_target( - ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND - ${CMAKE_COMMAND} -E echo "-object=$" >> - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list - DEPENDS ccov-preprocessing ${TARGET_NAME}) - - if(NOT TARGET ccov-libs) - message( - FATAL_ERROR - "Calling target_code_coverage with 'ALL' must be after a call to 'add_code_coverage_all_targets'." - ) - endif() - - add_dependencies(ccov-libs - ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME}) - endif() - endif() - - # For executables add targets to run and produce output - if(target_type STREQUAL "EXECUTABLE") - if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" - OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") - - # If there are shared objects to also work with, generate the string to - # add them here - foreach(SO_TARGET ${target_code_coverage_OBJECTS}) - # Check to see if the target is a shared object - if(TARGET ${SO_TARGET}) - get_target_property(SO_TARGET_TYPE ${SO_TARGET} TYPE) - if(${SO_TARGET_TYPE} STREQUAL "SHARED_LIBRARY") - set(SO_OBJECTS ${SO_OBJECTS} -object=$) - endif() - endif() - endforeach() - - # Run the executable, generating raw profile data Make the run data - # available for further processing. Separated to allow Windows to run - # this target serially. - add_custom_target( - ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND - ${CMAKE_COMMAND} -E env - LLVM_PROFILE_FILE=${target_code_coverage_COVERAGE_TARGET_NAME}.profraw - $ ${target_code_coverage_ARGS} - COMMAND - ${CMAKE_COMMAND} -E echo "-object=$" - ${SO_OBJECTS} >> ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list - COMMAND - ${CMAKE_COMMAND} -E echo - "${CMAKE_CURRENT_BINARY_DIR}/${target_code_coverage_COVERAGE_TARGET_NAME}.profraw" - >> ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list - JOB_POOL ccov_serial_pool - DEPENDS ccov-preprocessing ccov-libs ${TARGET_NAME}) - - # Merge the generated profile data so llvm-cov can process it - add_custom_target( - ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND - ${LLVM_PROFDATA_PATH} merge -sparse - ${target_code_coverage_COVERAGE_TARGET_NAME}.profraw -o - ${target_code_coverage_COVERAGE_TARGET_NAME}.profdata - DEPENDS ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME}) - - # Ignore regex only works on LLVM >= 7 - if(LLVM_COV_VERSION VERSION_GREATER_EQUAL "7.0.0") - foreach(EXCLUDE_ITEM ${target_code_coverage_EXCLUDE}) - set(EXCLUDE_REGEX ${EXCLUDE_REGEX} - -ignore-filename-regex='${EXCLUDE_ITEM}') - endforeach() - endif() - - # Print out details of the coverage information to the command line - add_custom_target( - ccov-show-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND - ${LLVM_COV_PATH} show $ ${SO_OBJECTS} - -instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata - -show-line-counts-or-regions ${EXCLUDE_REGEX} - DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME}) - - # Print out a summary of the coverage information to the command line - add_custom_target( - ccov-report-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND - ${LLVM_COV_PATH} report $ ${SO_OBJECTS} - -instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata - ${EXCLUDE_REGEX} - DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME}) - - # Export coverage information so continuous integration tools (e.g. - # Jenkins) can consume it - add_custom_target( - ccov-export-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND - ${LLVM_COV_PATH} export $ ${SO_OBJECTS} - -instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata - -format="text" ${EXCLUDE_REGEX} > - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}.json - DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME}) - - # Generates HTML output of the coverage information for perusal - add_custom_target( - ccov-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND - ${LLVM_COV_PATH} show $ ${SO_OBJECTS} - -instr-profile=${target_code_coverage_COVERAGE_TARGET_NAME}.profdata - -show-line-counts-or-regions - -output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME} - -format="html" ${EXCLUDE_REGEX} - DEPENDS ccov-processing-${target_code_coverage_COVERAGE_TARGET_NAME}) - - elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES - "GNU") - set(COVERAGE_INFO - "${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}.info" - ) - - # Run the executable, generating coverage information - add_custom_target( - ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND $ ${target_code_coverage_ARGS} - DEPENDS ccov-preprocessing ${TARGET_NAME}) - - # Generate exclusion string for use - foreach(EXCLUDE_ITEM ${target_code_coverage_EXCLUDE}) - set(EXCLUDE_REGEX ${EXCLUDE_REGEX} --remove ${COVERAGE_INFO} - '${EXCLUDE_ITEM}') - endforeach() - - if(EXCLUDE_REGEX) - set(EXCLUDE_COMMAND ${LCOV_PATH} ${EXCLUDE_REGEX} --output-file - ${COVERAGE_INFO}) - else() - set(EXCLUDE_COMMAND ;) - endif() - - if(NOT ${target_code_coverage_EXTERNAL}) - set(EXTERNAL_OPTION --no-external) - endif() - - # Capture coverage data - if(${CMAKE_VERSION} VERSION_LESS "3.17.0") - add_custom_target( - ccov-capture-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND ${CMAKE_COMMAND} -E remove -f ${COVERAGE_INFO} - COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters - COMMAND $ ${target_code_coverage_ARGS} - COMMAND - ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --base-directory - ${CMAKE_SOURCE_DIR} --capture ${EXTERNAL_OPTION} --output-file - ${COVERAGE_INFO} - COMMAND ${EXCLUDE_COMMAND} - DEPENDS ccov-preprocessing ${TARGET_NAME}) - else() - add_custom_target( - ccov-capture-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND ${CMAKE_COMMAND} -E rm -f ${COVERAGE_INFO} - COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters - COMMAND $ ${target_code_coverage_ARGS} - COMMAND - ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --base-directory - ${CMAKE_SOURCE_DIR} --capture ${EXTERNAL_OPTION} --output-file - ${COVERAGE_INFO} - COMMAND ${EXCLUDE_COMMAND} - DEPENDS ccov-preprocessing ${TARGET_NAME}) - endif() - - # Generates HTML output of the coverage information for perusal - add_custom_target( - ccov-${target_code_coverage_COVERAGE_TARGET_NAME} - COMMAND - ${GENHTML_PATH} -o - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME} - ${COVERAGE_INFO} - DEPENDS ccov-capture-${target_code_coverage_COVERAGE_TARGET_NAME}) - endif() - - add_custom_command( - TARGET ccov-${target_code_coverage_COVERAGE_TARGET_NAME} - POST_BUILD - COMMAND ; - COMMENT - "Open ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/${target_code_coverage_COVERAGE_TARGET_NAME}/index.html in your browser to view the coverage report." - ) - - # AUTO - if(target_code_coverage_AUTO) - if(NOT TARGET ccov) - add_custom_target(ccov) - endif() - add_dependencies(ccov ccov-${target_code_coverage_COVERAGE_TARGET_NAME}) - - if(NOT CMAKE_C_COMPILER_ID MATCHES "GNU" AND NOT CMAKE_CXX_COMPILER_ID - MATCHES "GNU") - if(NOT TARGET ccov-report) - add_custom_target(ccov-report) - endif() - add_dependencies( - ccov-report - ccov-report-${target_code_coverage_COVERAGE_TARGET_NAME}) - endif() - endif() - - # ALL - if(target_code_coverage_ALL) - if(NOT TARGET ccov-all-processing) - message( - FATAL_ERROR - "Calling target_code_coverage with 'ALL' must be after a call to 'add_code_coverage_all_targets'." - ) - endif() - - add_dependencies(ccov-all-processing - ccov-run-${target_code_coverage_COVERAGE_TARGET_NAME}) - endif() - endif() - endif() -endfunction() - -# Adds code coverage instrumentation to all targets in the current directory and -# any subdirectories. To add coverage instrumentation to only specific targets, -# use `target_code_coverage`. -function(add_code_coverage) - if(CODE_COVERAGE) - if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" - OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") - add_compile_options(-fprofile-instr-generate -fcoverage-mapping) - add_link_options(-fprofile-instr-generate -fcoverage-mapping) - elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES - "GNU") - add_compile_options(-fprofile-arcs -ftest-coverage) - link_libraries(gcov) - endif() - endif() -endfunction() - -# Adds the 'ccov-all' type targets that calls all targets added via -# `target_code_coverage` with the `ALL` parameter, but merges all the coverage -# data from them into a single large report instead of the numerous smaller -# reports. Also adds the ccov-all-capture Generates an all-merged.info file, for -# use with coverage dashboards (e.g. codecov.io, coveralls). -# ~~~ -# Optional: -# EXCLUDE - Excludes files of the patterns provided from coverage. Note that GCC/lcov excludes by glob pattern, and clang/LLVM excludes via regex! -# ~~~ -function(add_code_coverage_all_targets) - # Argument parsing - set(multi_value_keywords EXCLUDE) - cmake_parse_arguments(add_code_coverage_all_targets "" "" - "${multi_value_keywords}" ${ARGN}) - - if(CODE_COVERAGE) - if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang" - OR CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") - - # Merge the profile data for all of the run executables - if(WIN32) - add_custom_target( - ccov-all-processing - COMMAND - powershell -Command $$FILELIST = Get-Content - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list\; llvm-profdata.exe - merge -o ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata - -sparse $$FILELIST) - else() - add_custom_target( - ccov-all-processing - COMMAND - ${LLVM_PROFDATA_PATH} merge -o - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata -sparse `cat - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/profraw.list`) - endif() - - # Regex exclude only available for LLVM >= 7 - if(LLVM_COV_VERSION VERSION_GREATER_EQUAL "7.0.0") - foreach(EXCLUDE_ITEM ${add_code_coverage_all_targets_EXCLUDE}) - set(EXCLUDE_REGEX ${EXCLUDE_REGEX} - -ignore-filename-regex='${EXCLUDE_ITEM}') - endforeach() - endif() - - # Print summary of the code coverage information to the command line - if(WIN32) - add_custom_target( - ccov-all-report - COMMAND - powershell -Command $$FILELIST = Get-Content - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list\; llvm-cov.exe - report $$FILELIST - -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata - ${EXCLUDE_REGEX} - DEPENDS ccov-all-processing) - else() - add_custom_target( - ccov-all-report - COMMAND - ${LLVM_COV_PATH} report `cat - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list` - -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata - ${EXCLUDE_REGEX} - DEPENDS ccov-all-processing) - endif() - - # Export coverage information so continuous integration tools (e.g. - # Jenkins) can consume it - add_custom_target( - ccov-all-export - COMMAND - ${LLVM_COV_PATH} export `cat - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list` - -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata - -format="text" ${EXCLUDE_REGEX} > - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/coverage.json - DEPENDS ccov-all-processing) - - # Generate HTML output of all added targets for perusal - if(WIN32) - add_custom_target( - ccov-all - COMMAND - powershell -Command $$FILELIST = Get-Content - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list\; llvm-cov.exe show - $$FILELIST - -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata - -show-line-counts-or-regions - -output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged - -format="html" ${EXCLUDE_REGEX} - DEPENDS ccov-all-processing) - else() - add_custom_target( - ccov-all - COMMAND - ${LLVM_COV_PATH} show `cat - ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/binaries.list` - -instr-profile=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.profdata - -show-line-counts-or-regions - -output-dir=${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged - -format="html" ${EXCLUDE_REGEX} - DEPENDS ccov-all-processing) - endif() - - elseif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES - "GNU") - set(COVERAGE_INFO "${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged.info") - - # Nothing required for gcov - add_custom_target(ccov-all-processing COMMAND ;) - - # Exclusion regex string creation - set(EXCLUDE_REGEX) - foreach(EXCLUDE_ITEM ${add_code_coverage_all_targets_EXCLUDE}) - set(EXCLUDE_REGEX ${EXCLUDE_REGEX} --remove ${COVERAGE_INFO} - '${EXCLUDE_ITEM}') - endforeach() - - if(EXCLUDE_REGEX) - set(EXCLUDE_COMMAND ${LCOV_PATH} ${EXCLUDE_REGEX} --output-file - ${COVERAGE_INFO}) - else() - set(EXCLUDE_COMMAND ;) - endif() - - # Capture coverage data - if(${CMAKE_VERSION} VERSION_LESS "3.17.0") - add_custom_target( - ccov-all-capture - COMMAND ${CMAKE_COMMAND} -E remove -f ${COVERAGE_INFO} - COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --capture - --output-file ${COVERAGE_INFO} - COMMAND ${EXCLUDE_COMMAND} - DEPENDS ccov-preprocessing ccov-all-processing) - else() - add_custom_target( - ccov-all-capture - COMMAND ${CMAKE_COMMAND} -E rm -f ${COVERAGE_INFO} - COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --capture - --output-file ${COVERAGE_INFO} - COMMAND ${EXCLUDE_COMMAND} - DEPENDS ccov-preprocessing ccov-all-processing) - endif() - - # Generates HTML output of all targets for perusal - add_custom_target( - ccov-all - COMMAND ${GENHTML_PATH} -o ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged - ${COVERAGE_INFO} -p ${CMAKE_SOURCE_DIR} - DEPENDS ccov-all-capture) - - endif() - - add_custom_command( - TARGET ccov-all - POST_BUILD - COMMAND ; - COMMENT - "Open ${CMAKE_COVERAGE_OUTPUT_DIRECTORY}/all-merged/index.html in your browser to view the coverage report." - ) - endif() -endfunction() diff --git a/cmake/nestlog.cmake b/cmake/nestlog.cmake deleted file mode 100644 index 4a1a26ae..00000000 --- a/cmake/nestlog.cmake +++ /dev/null @@ -1,30 +0,0 @@ -# ---------------------------------------------------------------- -# use this in subdirs that compile c++ code -# -macro(xo_include_options target) - # ---------------------------------------------------------------- - # PROJECT_SOURCE_DIR: - # so we can for example write - # #include "nestlog/scope.hpp" - # from anywhere in the project - # PROJECT_BINARY_DIR: - # since generated version file will be in build directory, - # need that build directory to also appear in - # compiler's include path - # - target_include_directories( - ${target} PUBLIC - ${PROJECT_SOURCE_DIR}/include - ${PROJECT_BINARY_DIR} - ) - - # ---------------------------------------------------------------- - # make standard directories for std:: includes explicit - # so that - # (1) they appear in compile_commands.json. - # (2) clangd (run from emacs lsp-mode) can find them - # - if(CMAKE_EXPORT_COMPILE_COMMANDS) - set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) - endif() -endmacro() From c6a258eb3cffe52d61bd9ab08b713050b0c9ab5b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 6 Oct 2023 18:30:10 -0400 Subject: [PATCH 120/170] indentlog: insert xo/ into include path --- example/ex1/ex1.cpp | 6 +++++- example/ex2/ex2.cpp | 2 +- example/ex3/ex3.cpp | 2 +- example/ex4/ex4.cpp | 2 +- include/{ => xo}/indentlog/log_config.hpp | 0 include/{ => xo}/indentlog/log_level.hpp | 0 include/{ => xo}/indentlog/log_state.hpp | 0 include/{ => xo}/indentlog/log_streambuf.hpp | 0 include/{ => xo}/indentlog/print/array.hpp | 0 include/{ => xo}/indentlog/print/code_location.hpp | 0 include/{ => xo}/indentlog/print/color.hpp | 0 include/{ => xo}/indentlog/print/concat.hpp | 0 include/{ => xo}/indentlog/print/filename.hpp | 0 include/{ => xo}/indentlog/print/fixed.hpp | 0 include/{ => xo}/indentlog/print/function.hpp | 0 include/{ => xo}/indentlog/print/pad.hpp | 0 include/{ => xo}/indentlog/print/printer.hpp | 0 include/{ => xo}/indentlog/print/quoted.hpp | 0 include/{ => xo}/indentlog/print/quoted_char.hpp | 0 include/{ => xo}/indentlog/print/tag.hpp | 0 include/{ => xo}/indentlog/print/tag_config.hpp | 0 include/{ => xo}/indentlog/print/time.hpp | 2 +- include/{ => xo}/indentlog/print/tostr.hpp | 0 include/{ => xo}/indentlog/print/vector.hpp | 0 include/{ => xo}/indentlog/scope.hpp | 0 include/{ => xo}/indentlog/timeutil/timeutil.hpp | 0 utest/array.test.cpp | 4 ++-- utest/code_location.test.cpp | 6 +++--- utest/filename.test.cpp | 4 ++-- utest/fixed.test.cpp | 4 ++-- utest/function.test.cpp | 4 ++-- utest/quoted.test.cpp | 4 ++-- utest/tag.test.cpp | 6 +++--- utest/timeutil.test.cpp | 4 ++-- utest/vector.test.cpp | 4 ++-- 35 files changed, 29 insertions(+), 25 deletions(-) rename include/{ => xo}/indentlog/log_config.hpp (100%) rename include/{ => xo}/indentlog/log_level.hpp (100%) rename include/{ => xo}/indentlog/log_state.hpp (100%) rename include/{ => xo}/indentlog/log_streambuf.hpp (100%) rename include/{ => xo}/indentlog/print/array.hpp (100%) rename include/{ => xo}/indentlog/print/code_location.hpp (100%) rename include/{ => xo}/indentlog/print/color.hpp (100%) rename include/{ => xo}/indentlog/print/concat.hpp (100%) rename include/{ => xo}/indentlog/print/filename.hpp (100%) rename include/{ => xo}/indentlog/print/fixed.hpp (100%) rename include/{ => xo}/indentlog/print/function.hpp (100%) rename include/{ => xo}/indentlog/print/pad.hpp (100%) rename include/{ => xo}/indentlog/print/printer.hpp (100%) rename include/{ => xo}/indentlog/print/quoted.hpp (100%) rename include/{ => xo}/indentlog/print/quoted_char.hpp (100%) rename include/{ => xo}/indentlog/print/tag.hpp (100%) rename include/{ => xo}/indentlog/print/tag_config.hpp (100%) rename include/{ => xo}/indentlog/print/time.hpp (98%) rename include/{ => xo}/indentlog/print/tostr.hpp (100%) rename include/{ => xo}/indentlog/print/vector.hpp (100%) rename include/{ => xo}/indentlog/scope.hpp (100%) rename include/{ => xo}/indentlog/timeutil/timeutil.hpp (100%) diff --git a/example/ex1/ex1.cpp b/example/ex1/ex1.cpp index 91e321e2..b791aee0 100644 --- a/example/ex1/ex1.cpp +++ b/example/ex1/ex1.cpp @@ -1,4 +1,6 @@ -#include "indentlog/scope.hpp" +/* ex1.cpp */ + +#include "xo/indentlog/scope.hpp" using namespace xo; @@ -16,3 +18,5 @@ int main(int argc, char ** argv) { outer(123); } + +/* end ex1.cpp */ diff --git a/example/ex2/ex2.cpp b/example/ex2/ex2.cpp index f329b9d4..4ccfaae2 100644 --- a/example/ex2/ex2.cpp +++ b/example/ex2/ex2.cpp @@ -1,6 +1,6 @@ /* examples ex2/ex2.cpp */ -#include "indentlog/scope.hpp" +#include "xo/indentlog/scope.hpp" using namespace xo; diff --git a/example/ex3/ex3.cpp b/example/ex3/ex3.cpp index 2a09d2d7..0fc0fcc2 100644 --- a/example/ex3/ex3.cpp +++ b/example/ex3/ex3.cpp @@ -1,6 +1,6 @@ /* examples ex3/ex3.cpp */ -#include "indentlog/scope.hpp" +#include "xo/indentlog/scope.hpp" using namespace xo; diff --git a/example/ex4/ex4.cpp b/example/ex4/ex4.cpp index d59e83c1..01a141c8 100644 --- a/example/ex4/ex4.cpp +++ b/example/ex4/ex4.cpp @@ -1,6 +1,6 @@ /* @file ex4.cpp */ -#include "indentlog/scope.hpp" +#include "xo/indentlog/scope.hpp" using namespace xo; diff --git a/include/indentlog/log_config.hpp b/include/xo/indentlog/log_config.hpp similarity index 100% rename from include/indentlog/log_config.hpp rename to include/xo/indentlog/log_config.hpp diff --git a/include/indentlog/log_level.hpp b/include/xo/indentlog/log_level.hpp similarity index 100% rename from include/indentlog/log_level.hpp rename to include/xo/indentlog/log_level.hpp diff --git a/include/indentlog/log_state.hpp b/include/xo/indentlog/log_state.hpp similarity index 100% rename from include/indentlog/log_state.hpp rename to include/xo/indentlog/log_state.hpp diff --git a/include/indentlog/log_streambuf.hpp b/include/xo/indentlog/log_streambuf.hpp similarity index 100% rename from include/indentlog/log_streambuf.hpp rename to include/xo/indentlog/log_streambuf.hpp diff --git a/include/indentlog/print/array.hpp b/include/xo/indentlog/print/array.hpp similarity index 100% rename from include/indentlog/print/array.hpp rename to include/xo/indentlog/print/array.hpp diff --git a/include/indentlog/print/code_location.hpp b/include/xo/indentlog/print/code_location.hpp similarity index 100% rename from include/indentlog/print/code_location.hpp rename to include/xo/indentlog/print/code_location.hpp diff --git a/include/indentlog/print/color.hpp b/include/xo/indentlog/print/color.hpp similarity index 100% rename from include/indentlog/print/color.hpp rename to include/xo/indentlog/print/color.hpp diff --git a/include/indentlog/print/concat.hpp b/include/xo/indentlog/print/concat.hpp similarity index 100% rename from include/indentlog/print/concat.hpp rename to include/xo/indentlog/print/concat.hpp diff --git a/include/indentlog/print/filename.hpp b/include/xo/indentlog/print/filename.hpp similarity index 100% rename from include/indentlog/print/filename.hpp rename to include/xo/indentlog/print/filename.hpp diff --git a/include/indentlog/print/fixed.hpp b/include/xo/indentlog/print/fixed.hpp similarity index 100% rename from include/indentlog/print/fixed.hpp rename to include/xo/indentlog/print/fixed.hpp diff --git a/include/indentlog/print/function.hpp b/include/xo/indentlog/print/function.hpp similarity index 100% rename from include/indentlog/print/function.hpp rename to include/xo/indentlog/print/function.hpp diff --git a/include/indentlog/print/pad.hpp b/include/xo/indentlog/print/pad.hpp similarity index 100% rename from include/indentlog/print/pad.hpp rename to include/xo/indentlog/print/pad.hpp diff --git a/include/indentlog/print/printer.hpp b/include/xo/indentlog/print/printer.hpp similarity index 100% rename from include/indentlog/print/printer.hpp rename to include/xo/indentlog/print/printer.hpp diff --git a/include/indentlog/print/quoted.hpp b/include/xo/indentlog/print/quoted.hpp similarity index 100% rename from include/indentlog/print/quoted.hpp rename to include/xo/indentlog/print/quoted.hpp diff --git a/include/indentlog/print/quoted_char.hpp b/include/xo/indentlog/print/quoted_char.hpp similarity index 100% rename from include/indentlog/print/quoted_char.hpp rename to include/xo/indentlog/print/quoted_char.hpp diff --git a/include/indentlog/print/tag.hpp b/include/xo/indentlog/print/tag.hpp similarity index 100% rename from include/indentlog/print/tag.hpp rename to include/xo/indentlog/print/tag.hpp diff --git a/include/indentlog/print/tag_config.hpp b/include/xo/indentlog/print/tag_config.hpp similarity index 100% rename from include/indentlog/print/tag_config.hpp rename to include/xo/indentlog/print/tag_config.hpp diff --git a/include/indentlog/print/time.hpp b/include/xo/indentlog/print/time.hpp similarity index 98% rename from include/indentlog/print/time.hpp rename to include/xo/indentlog/print/time.hpp index 275f43da..28a1a687 100644 --- a/include/indentlog/print/time.hpp +++ b/include/xo/indentlog/print/time.hpp @@ -2,7 +2,7 @@ #pragma once -#include "indentlog/timeutil/timeutil.hpp" +#include "xo/indentlog/timeutil/timeutil.hpp" namespace xo { namespace time { diff --git a/include/indentlog/print/tostr.hpp b/include/xo/indentlog/print/tostr.hpp similarity index 100% rename from include/indentlog/print/tostr.hpp rename to include/xo/indentlog/print/tostr.hpp diff --git a/include/indentlog/print/vector.hpp b/include/xo/indentlog/print/vector.hpp similarity index 100% rename from include/indentlog/print/vector.hpp rename to include/xo/indentlog/print/vector.hpp diff --git a/include/indentlog/scope.hpp b/include/xo/indentlog/scope.hpp similarity index 100% rename from include/indentlog/scope.hpp rename to include/xo/indentlog/scope.hpp diff --git a/include/indentlog/timeutil/timeutil.hpp b/include/xo/indentlog/timeutil/timeutil.hpp similarity index 100% rename from include/indentlog/timeutil/timeutil.hpp rename to include/xo/indentlog/timeutil/timeutil.hpp diff --git a/utest/array.test.cpp b/utest/array.test.cpp index 4ba8b83a..e916802d 100644 --- a/utest/array.test.cpp +++ b/utest/array.test.cpp @@ -1,7 +1,7 @@ /* @file array.test.cpp */ -#include "indentlog/print/array.hpp" /* overload operator<< for std::array */ -#include "indentlog/print/tag.hpp" +#include "xo/indentlog/print/array.hpp" /* overload operator<< for std::array */ +#include "xo/indentlog/print/tag.hpp" #include #include diff --git a/utest/code_location.test.cpp b/utest/code_location.test.cpp index 64f1a0c4..7be0eb6a 100644 --- a/utest/code_location.test.cpp +++ b/utest/code_location.test.cpp @@ -1,8 +1,8 @@ /* @file code_location.test.cpp */ -#include "indentlog/print/code_location.hpp" -#include "indentlog/print/color.hpp" -#include "indentlog/print/tag.hpp" +#include "xo/indentlog/print/code_location.hpp" +#include "xo/indentlog/print/color.hpp" +#include "xo/indentlog/print/tag.hpp" #include #include diff --git a/utest/filename.test.cpp b/utest/filename.test.cpp index ebff42b4..a47a5ab0 100644 --- a/utest/filename.test.cpp +++ b/utest/filename.test.cpp @@ -1,7 +1,7 @@ /* @file filename.test.cpp */ -#include "indentlog/print/filename.hpp" -#include "indentlog/print/tag.hpp" +#include "xo/indentlog/print/filename.hpp" +#include "xo/indentlog/print/tag.hpp" #include #include diff --git a/utest/fixed.test.cpp b/utest/fixed.test.cpp index c2b7146b..d42ffc63 100644 --- a/utest/fixed.test.cpp +++ b/utest/fixed.test.cpp @@ -1,7 +1,7 @@ /* @file fixed.test.cpp */ -#include "indentlog/print/fixed.hpp" -#include "indentlog/print/tag.hpp" +#include "xo/indentlog/print/fixed.hpp" +#include "xo/indentlog/print/tag.hpp" #include #include diff --git a/utest/function.test.cpp b/utest/function.test.cpp index bd71bd35..2a21b077 100644 --- a/utest/function.test.cpp +++ b/utest/function.test.cpp @@ -1,7 +1,7 @@ /* @file function.test.cpp */ -#include "indentlog/print/function.hpp" -#include "indentlog/print/tag.hpp" +#include "xo/indentlog/print/function.hpp" +#include "xo/indentlog/print/tag.hpp" #include #include diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index 35583d4d..e90c195b 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -1,7 +1,7 @@ /* @file fixed.test.cpp */ -#include "indentlog/print/quoted.hpp" -#include "indentlog/print/tag.hpp" +#include "xo/indentlog/print/quoted.hpp" +#include "xo/indentlog/print/tag.hpp" #include #include diff --git a/utest/tag.test.cpp b/utest/tag.test.cpp index 8ecabb8d..4b2d939e 100644 --- a/utest/tag.test.cpp +++ b/utest/tag.test.cpp @@ -1,8 +1,8 @@ /* @file tag.test.cpp */ -#include "indentlog/print/tag.hpp" -#include "indentlog/print/vector.hpp" -#include "indentlog/print/concat.hpp" +#include "xo/indentlog/print/tag.hpp" +#include "xo/indentlog/print/vector.hpp" +#include "xo/indentlog/print/concat.hpp" #include #include diff --git a/utest/timeutil.test.cpp b/utest/timeutil.test.cpp index 816c92da..fb50ca63 100644 --- a/utest/timeutil.test.cpp +++ b/utest/timeutil.test.cpp @@ -1,7 +1,7 @@ /* @file timeutil.test.cpp */ -#include "indentlog/timeutil/timeutil.hpp" -#include "indentlog/print/tag.hpp" +#include "xo/indentlog/timeutil/timeutil.hpp" +#include "xo/indentlog/print/tag.hpp" #include #include diff --git a/utest/vector.test.cpp b/utest/vector.test.cpp index 8b4f1f4c..eaa1b4ea 100644 --- a/utest/vector.test.cpp +++ b/utest/vector.test.cpp @@ -1,7 +1,7 @@ /* @file vector.test.cpp */ -#include "indentlog/print/vector.hpp" /* overload operator<< for std::vector */ -#include "indentlog/print/tag.hpp" +#include "xo/indentlog/print/vector.hpp" /* overload operator<< for std::vector */ +#include "xo/indentlog/print/tag.hpp" #include #include From 03807c5c232e65c5975131b695d946253e11fdc3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Oct 2023 17:42:27 -0400 Subject: [PATCH 121/170] build: supply indentlog config to cmake customers --- CMakeLists.txt | 5 ++--- indentlogConfig.cmake.in | 4 ++++ 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 indentlogConfig.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a780b05..9e53335a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,13 +33,12 @@ add_subdirectory(utest) # header-only library. # see [[https://stackoverflow.com/questions/47718485/install-and-export-interface-only-library-cmake]] # -add_library(indentlog INTERFACE) -xo_include_headeronly_options2(indentlog) +xo_add_headeronly_library(indentlog) # ---------------------------------------------------------------- # standard install + provide find_package() support -xo_install_library2(${PROJECT_NAME}) +xo_install_library2(indentlog) xo_install_include_tree() xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) diff --git a/indentlogConfig.cmake.in b/indentlogConfig.cmake.in new file mode 100644 index 00000000..cc57615e --- /dev/null +++ b/indentlogConfig.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/indentlogTargets.cmake") +check_required_components("@PROJECT_NAME@") From 4c5992ae40dbdf2269b236eab81fd5ab27b1e2fc Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Oct 2023 17:43:01 -0400 Subject: [PATCH 122/170] cosmetic: tidy comment for atavism --- include/xo/indentlog/log_config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/indentlog/log_config.hpp b/include/xo/indentlog/log_config.hpp index 9e2099cf..98a16304 100644 --- a/include/xo/indentlog/log_config.hpp +++ b/include/xo/indentlog/log_config.hpp @@ -27,7 +27,7 @@ namespace xo { static bool nesting_level_enabled; /* color to use for explicit nesting level */ static color_spec_type nesting_level_color; - /* display style for function names. FS_Simple|FS_Pretty|FS_Streamlined */ + /* display style for function names. function_style:: literal|simple|pretty|streamlined */ static function_style style; /* color to use for function name, on entry/exit (xo::scope creation/destruction) * (ansi color codes, see Select Graphics Rendition subset) From bdde88ebae9f396c3e9f2a9e8e02ae627de35182 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Oct 2023 17:43:17 -0400 Subject: [PATCH 123/170] print: pair.hpp: default printer for std::pair<> --- include/xo/indentlog/print/pair.hpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 include/xo/indentlog/print/pair.hpp diff --git a/include/xo/indentlog/print/pair.hpp b/include/xo/indentlog/print/pair.hpp new file mode 100644 index 00000000..0453fba0 --- /dev/null +++ b/include/xo/indentlog/print/pair.hpp @@ -0,0 +1,24 @@ +/* @file pair.hpp */ + +#pragma once + +#include +#include + +namespace std { + template + inline std::ostream & + operator<<(std::ostream & os, + std::pair const & x) + { + os << "[" + << x.first + << " " + << x.second + << "]"; + + return os; + } /*operator<<*/ +} /*namespace std*/ + +/* end pair.hpp */ From 756e6c521f643daa62d3769a5e276f7c6838e07c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Oct 2023 17:43:48 -0400 Subject: [PATCH 124/170] function: bugfix: exclude [with T = ...] suffix when printing --- include/xo/indentlog/print/function.hpp | 82 +++++++++++++++---------- utest/function.test.cpp | 2 + 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/include/xo/indentlog/print/function.hpp b/include/xo/indentlog/print/function.hpp index 2689ef1a..3c0f97a6 100644 --- a/include/xo/indentlog/print/function.hpp +++ b/include/xo/indentlog/print/function.hpp @@ -54,31 +54,35 @@ namespace xo { std::string_view const & pretty() const { return pretty_; } /* e.g. - * <------------------------------------- s2 -------------------------------------> - * <--------------------- s3 -----------------> - * <----- s4 -----> - * std::vector xo::sometemplateclass::fib(int, char**) const + * <----------------------------------------------------- s ----------------------------------------------------------> + * <----------------------------------------- s2 ---------------------------------------> + * <------------------------------------- s3 -------------------------------------> + * <--------------------- s4 -----------------> + * <----- s5 -----> + * std::vector xo::sometemplateclass::fib(int, char**) const [with T = int; with U = char] * ^ ^ * p q * * fib <- .print_aux() */ static void print_simple(std::ostream & os, std::string_view const & s) { - std::size_t p = exclude_const_suffix(s); - std::string_view s2 = s.substr(0, p); /* no const suffix */ - std::size_t q = exclude_return_type(s2); - std::string_view s3 = s2.substr(q); /* no return type */ - std::size_t r = find_toplevel_sep(s3, true /*last_flag*/); - std::string_view s4 = s3.substr(r); + std::string_view s2 = exclude_template_footnote_suffix(s); + std::string_view s3 = exclude_const_suffix(s2) /*no const suffix*/; + std::size_t q = exclude_return_type(s3); + std::string_view s4 = s3.substr(q); /* no return type */ + std::size_t r = find_toplevel_sep(s4, true /*last_flag*/); + std::string_view s5 = s4.substr(r); - print_aux(os, s4); + print_aux(os, s5); } /*print_simple*/ /* e.g. - * <----------------------------------- s2 ---------------------------------------> - * <--------------------- s3 -----------------> - * <----------------- s4 -----------------> - * std::vector xo::sometemplateclass::fib(int, char**) const + * <------------------------------------------------------------- s --------------------------------------------------> + * <----------------------------------------------- s2 ---------------------------------> + * <----------------------------------- s3 ---------------------------------------> + * <--------------------- s4 -----------------> + * <----------------- s5 -----------------> + * std::vector xo::sometemplateclass::fib(int, char**) const [with T = int; with U = char] * ^ ^ ^ * q r p * @@ -86,19 +90,20 @@ namespace xo { * */ static void print_streamlined(std::ostream & os, std::string_view const & s) { - std::size_t p = exclude_const_suffix(s); - std::string_view s2 = s.substr(0, p); /*no const suffix */ - std::size_t q = exclude_return_type(s2); - std::string_view s3 = s2.substr(q); /*no return type*/ - std::size_t r = find_toplevel_sep(s3, false /*!last_flag*/); - std::string_view s4 = s3.substr(r); /*no namespace qualifier (unless function)*/ + std::string_view s2 = exclude_template_footnote_suffix(s); + std::string_view s3 = exclude_const_suffix(s2) /*no const suffix */; + std::size_t q = exclude_return_type(s3); + std::string_view s4 = s3.substr(q); /*no return type*/ + std::size_t r = find_toplevel_sep(s4, false /*!last_flag*/); + std::string_view s5 = s4.substr(r); /*no namespace qualifier (unless function)*/ - //std::cerr << "print_streamlined: s=[" << s << "], p=" << p << std::endl; - //std::cerr << "print_streamlined: s2=[" << s2 << "], q=" << q << std::endl; - //std::cerr << "print_streamlined: s3=[" << s3 << "], r=" << r << std::endl; - //std::cerr << "print_streamlined: s4=[" << s4 << "]" << std::endl; + //std::cerr << "print_streamlined: s=[" << s << "]" << std::endl; + //std::cerr << "print_streamlined: s2=[" << s2 << "] (excluded [with ..] suffix)" << std::endl; + //std::cerr << "print_streamlined: s3=[" << s3 << "], p=" << p << " (excluded const suffix)" << std::endl; + //std::cerr << "print_streamlined: s4=[" << s4 << "], q=" << q << " (excluded return type)" << std::endl; + //std::cerr << "print_streamlined: s5=[" << s5 << "], r=" << r << " (excluded ns qualifier)" << std::endl; - print_aux(os, s4); + print_aux(os, s5); } /*print_streamlined*/ private: @@ -130,16 +135,29 @@ namespace xo { return 0; } /*exclude_return_type*/ - static std::size_t exclude_const_suffix(std::string_view const & s) { - constexpr std::uint32_t c_prefix_z = 6 /*strlen(" const")*/; + /* e.g. + * void xo::foo::Foo::notify(const T&) [with T = std::pair; S = xo::foo::Bar] + */ + static std::string_view exclude_template_footnote_suffix(std::string_view const & s) { + /* strategy: + * - left-to-right + * - exclude ' [with '... to end of string + */ + std::size_t p = s.find(" [with "); - if ((s.size() > c_prefix_z) - && (s.substr(s.size() - c_prefix_z) == " const")) + return s.substr(0, p); + } /*exclude_template_footnote_suffix*/ + + static std::string_view exclude_const_suffix(std::string_view const & s) { + constexpr std::uint32_t c_suffix_z = 6 /*strlen(" const")*/; + + if ((s.size() > c_suffix_z) + && (s.substr(s.size() - c_suffix_z) == " const")) { - return s.size() - c_prefix_z; + return s.substr(0, s.size() - c_suffix_z); } - return s.size(); + return s; } /*exclude_const_suffix*/ /* e.g. diff --git a/utest/function.test.cpp b/utest/function.test.cpp index 2a21b077..42d3c9b6 100644 --- a/utest/function.test.cpp +++ b/utest/function.test.cpp @@ -36,6 +36,8 @@ namespace ut { function_tcase(function_style::simple, color_spec_type::none(), "void xo::class::foo() const", "foo"), function_tcase(function_style::pretty, color_spec_type::blue(), "void xo::class::foo() const", "[\033[31;34mvoid xo::class::foo() const\033[0m]"), + + function_tcase(function_style::streamlined, color_spec_type::none(), "void xo::reactor::FifoQueue::notify_ev(const T&) [with T = std::pair > >, long unsigned int>; EvTimeFn = xo::reactor::EventTimeFn > >, long unsigned int> >]", "FifoQueue::notify_ev"), }); TEST_CASE("function", "[function]") { From 0f898ff01136b16ec0e8e2aec352d3194fbebe33 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 11 Oct 2023 18:37:09 -0400 Subject: [PATCH 125/170] bugfix: #pragma once in log_level.hpp --- include/xo/indentlog/log_level.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/xo/indentlog/log_level.hpp b/include/xo/indentlog/log_level.hpp index 8b470891..a4392286 100644 --- a/include/xo/indentlog/log_level.hpp +++ b/include/xo/indentlog/log_level.hpp @@ -1,5 +1,7 @@ /* @file log_level.hpp */ +#pragma once + #include namespace xo { From f88484a79d13648030dcdc8b47adf5be831bab1c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Oct 2023 00:17:58 -0400 Subject: [PATCH 126/170] indentlog: xo_install_library2() -> xo_install_library3() --- BUILD.md | 4 ++++ CMakeLists.txt | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index 29023957..4223d6b5 100644 --- a/BUILD.md +++ b/BUILD.md @@ -1,5 +1,9 @@ # indentlog build details +## mac osx + +Note: ~ expansion doesn't work in a pure build environment. + ## Test Coverage ### enable coverage build diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e53335a..1cce6e83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,8 +38,9 @@ xo_add_headeronly_library(indentlog) # ---------------------------------------------------------------- # standard install + provide find_package() support -xo_install_library2(indentlog) -xo_install_include_tree() +#xo_install_library2(indentlog) +#xo_install_include_tree() +xo_install_library3(indentlog ${PROJECT_NAME}Targets) xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) # ---------------------------------------------------------------- From e149d44a930cbfa5c8643fd560a12f4b19192010 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Oct 2023 00:18:42 -0400 Subject: [PATCH 127/170] indentlog: compile fixes for OSX build (clang 11) --- include/xo/indentlog/scope.hpp | 4 +-- include/xo/indentlog/timeutil/timeutil.hpp | 14 +++++--- utest/timeutil.test.cpp | 37 +++++++++++++--------- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/include/xo/indentlog/scope.hpp b/include/xo/indentlog/scope.hpp index 551589e9..30476664 100644 --- a/include/xo/indentlog/scope.hpp +++ b/include/xo/indentlog/scope.hpp @@ -232,7 +232,7 @@ namespace xo { } /*nesting_level*/ template - basic_scope::state_impl_type * + typename basic_scope::state_impl_type * basic_scope::require_indent_thread_local_state() { state_impl_type * local_state = require_thread_local_state(); @@ -244,7 +244,7 @@ namespace xo { } /*require_thread_local_stream*/ template - basic_scope::state_impl_type * + typename basic_scope::state_impl_type * basic_scope::require_thread_local_state() { if(!s_threadlocal_state) { diff --git a/include/xo/indentlog/timeutil/timeutil.hpp b/include/xo/indentlog/timeutil/timeutil.hpp index 740283f3..5e57aeb0 100644 --- a/include/xo/indentlog/timeutil/timeutil.hpp +++ b/include/xo/indentlog/timeutil/timeutil.hpp @@ -13,10 +13,6 @@ namespace xo { namespace time { - - using utc_nanos = std::chrono::time_point; - using nanos = std::chrono::nanoseconds; using microseconds = std::chrono::microseconds; using milliseconds = std::chrono::milliseconds; @@ -24,6 +20,12 @@ namespace xo { using hours = std::chrono::hours; using days = std::chrono::days; + using utc_nanos = std::chrono::time_point; + using utc_micros = std::chrono::time_point; + + struct timeutil { static utc_nanos now() { return utc_nanos(std::chrono::system_clock::now()); @@ -168,7 +170,9 @@ namespace xo { /* use yyyymmdd.hh:mm:ss.nnnnnn */ - time_t t0_time_t = (std::chrono::system_clock::to_time_t(t0)); + time_t t0_time_t + = (std::chrono::system_clock::to_time_t + (std::chrono::time_point_cast(t0))); //time_t t0_time_t = (std::chrono::system_clock::to_time_t(std::chrono::time_point_cast(t0))); /* convert to std::tm, in UTC coords, diff --git a/utest/timeutil.test.cpp b/utest/timeutil.test.cpp index fb50ca63..c0c17bf2 100644 --- a/utest/timeutil.test.cpp +++ b/utest/timeutil.test.cpp @@ -10,75 +10,82 @@ using namespace xo::time; using namespace std::chrono; namespace ut { + template + inline utc_micros to_micros(FromTime tm) { + return std::chrono::time_point_cast(tm); + } /*to_micros*/ + TEST_CASE("epoch", "[timeutil]") { //tag_config::tag_color = color_spec_type::none(); + using xo::time::microseconds; + utc_nanos t0 = timeutil::epoch(); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(0)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(0)); } /*TEST_CASE(epoch)*/ TEST_CASE("ymd_hms", "[timeutil]") { { utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 0 /*hms*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(0)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(0)); } { utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 1 /*hms*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(1)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(1)); } { utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 100 /*hms*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(60)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(60)); } { utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 10000 /*hms*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(3600)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(3600)); } { utc_nanos t0 = timeutil::ymd_hms(19700101 /*ymd*/, 235959 /*hms*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(86399)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(86399)); } { utc_nanos t0 = timeutil::ymd_hms(19700102 /*ymd*/, 235959 /*hms*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(86400 + 86399)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(86400 + 86399)); } { utc_nanos t0 = timeutil::ymd_hms(19700131 /*ymd*/, 235959 /*hms*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(30 * 86400 + 86399)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(30 * 86400 + 86399)); } { utc_nanos t0 = timeutil::ymd_hms(19700201 /*ymd*/, 235959 /*hms*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(31 * 86400 + 86399)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(31 * 86400 + 86399)); } } /*TEST_CASE(ymd_hms)*/ TEST_CASE("ymd_midnight", "[timeutil]") { { utc_nanos t0 = timeutil::ymd_midnight(19700101 /*ymd*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(0)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(0)); } { utc_nanos t0 = timeutil::ymd_midnight(19700102 /*ymd*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(86400)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(86400)); } { utc_nanos t0 = timeutil::ymd_midnight(19700131 /*ymd*/); - REQUIRE(std::chrono::system_clock::to_time_t(t0) == std::time_t(30 * 86400)); + REQUIRE(std::chrono::system_clock::to_time_t(to_micros(t0)) == std::time_t(30 * 86400)); } { utc_nanos t0 = timeutil::ymd_midnight(19700201 /*ymd*/); - REQUIRE(system_clock::to_time_t(t0) == std::time_t(31 * 86400)); + REQUIRE(system_clock::to_time_t(to_micros(t0)) == std::time_t(31 * 86400)); } } /*TEST_CASE(ymd_midnight)*/ @@ -144,10 +151,10 @@ namespace ut { INFO(xtag("tc.utc_ymd_hms_usec_str", tc.utc_ymd_hms_usec_str_)); utc_nanos const t0 = timeutil::ymd_hms_usec(tc.ymd_, tc.hms_, tc.usec_); - REQUIRE(system_clock::to_time_t(t0) == std::time_t(tc.epoch_sec_)); + REQUIRE(system_clock::to_time_t(to_micros(t0)) == std::time_t(tc.epoch_sec_)); auto x = timeutil::utc_split_vs_midnight(t0); - REQUIRE(system_clock::to_time_t(x.first) == tc.midnight_sec_); + REQUIRE(system_clock::to_time_t(to_micros(x.first)) == tc.midnight_sec_); REQUIRE(x.second == seconds(tc.fractional_sec_) + microseconds(tc.fractional_usec_)); { From 298f7a2888f1a94bf756002fedafd5025daff467 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 17 Oct 2023 14:35:58 -0400 Subject: [PATCH 128/170] log_level printing + change XO_LITERAL --- CMakeLists.txt | 2 +- include/xo/indentlog/log_level.hpp | 18 ++++++++++++++++++ include/xo/indentlog/scope.hpp | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e53335a..53d75605 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ xo_add_headeronly_library(indentlog) # ---------------------------------------------------------------- # standard install + provide find_package() support -xo_install_library2(indentlog) +xo_install_library3(indentlog ${PROJECT_NAME}Targets) xo_install_include_tree() xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) diff --git a/include/xo/indentlog/log_level.hpp b/include/xo/indentlog/log_level.hpp index a4392286..dbe49b29 100644 --- a/include/xo/indentlog/log_level.hpp +++ b/include/xo/indentlog/log_level.hpp @@ -2,6 +2,7 @@ #pragma once +#include #include namespace xo { @@ -54,6 +55,23 @@ namespace xo { return (static_cast(x) <= static_cast(y)); } + inline std::ostream & + operator<<(std::ostream & os, + log_level x) { + switch(x) { + case log_level::never: os << "never"; break; + case log_level::verbose: os << "verbose"; break; + case log_level::chatty: os << "chatty"; break; + case log_level::info: os << "info"; break; + case log_level::warning: os << "warning"; break; + case log_level::error: os << "error"; break; + case log_level::severe: os << "severe"; break; + case log_level::always: os << "always"; break; + case log_level::silent: os << "silent"; break; + //default: os << "???"; break; + } + return os; + } /* operator<<*/ } /*namespace xo*/ /* end log_level.hpp */ diff --git a/include/xo/indentlog/scope.hpp b/include/xo/indentlog/scope.hpp index 551589e9..107dfc3e 100644 --- a/include/xo/indentlog/scope.hpp +++ b/include/xo/indentlog/scope.hpp @@ -23,7 +23,7 @@ namespace xo { # define XO_DEBUG(debug_flag) XO_ENTER1(always, debug_flag) # define XO_DEBUG2(debug_flag, name1) XO_ENTER2(always, debug_flag, name1) -# define XO_LITERAL(lvl, name1, name2) xo::scope_setup(xo::log_level::lvl, function_style::literal, name1, name2, __FILE__, __LINE__) +# define XO_LITERAL(lvl, name1, name2) xo::scope_setup(lvl, function_style::literal, name1, name2, __FILE__, __LINE__) //# define XO_SSETUP0() xo::scope_setup(__FUNCTION__) //# define XO_SSETUP0(lvl) xo::scope_setup(xo::log_level::lvl, xo::log_config::style, __PRETTY_FUNCTION__, __FILE__, __LINE__) From f2224d5005a16308044f3917be70cfe5f8e8e3d4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 19 Oct 2023 15:27:37 -0400 Subject: [PATCH 129/170] indentlog: support symlink-only install --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cce6e83..c6799082 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ xo_add_headeronly_library(indentlog) #xo_install_library2(indentlog) #xo_install_include_tree() -xo_install_library3(indentlog ${PROJECT_NAME}Targets) +xo_install_library4(indentlog ${PROJECT_NAME}Targets) xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) # ---------------------------------------------------------------- From 9e680badecb2281c50112e342d6b27168de7b8aa Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 19 Oct 2023 15:27:54 -0400 Subject: [PATCH 130/170] doc: README extensions --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9bc7e7aa..18c7c984 100644 --- a/README.md +++ b/README.md @@ -43,17 +43,17 @@ $ make $ make install ``` -alternatively, if you're a nix user: -``` -$ git clone git@github.com:rconybea/indentlog-nix.git -$ ls -d indentlog-nix -indentlog-nix -$ cd indentlog-nix -$ nix-build -``` - For some more detail see [BUILD.md](BUILD.md) +### LSP support + +lsp will look for `compile_commands.json` in the root of the source tree; cmake creates it in build directory + +``` +$ cd xo-indentlog +$ ln -s build/compile_commands.json +``` + ## Examples ### 1 From 3831e387a9d1102da1bad9eabbc80de384d45fe6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 22 Oct 2023 14:45:18 -0400 Subject: [PATCH 131/170] indentlog: need unique cmake targets across xo for submodule build --- CMakeLists.txt | 8 ++++---- example/ex1/CMakeLists.txt | 4 ++-- example/ex2/CMakeLists.txt | 6 ++++-- example/ex3/CMakeLists.txt | 4 ++-- example/ex4/CMakeLists.txt | 4 ++-- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6799082..65572cc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets # ---------------------------------------------------------------- install(TARGETS hello DESTINATION bin/indentlog/example) -install(TARGETS ex1 DESTINATION bin/indentlog/example) -install(TARGETS ex2 DESTINATION bin/indentlog/example) -install(TARGETS ex3 DESTINATION bin/indentlog/example) -install(TARGETS ex4 DESTINATION bin/indentlog/example) +install(TARGETS indentlog_ex1 DESTINATION bin/indentlog/example) +install(TARGETS indentlog_ex2 DESTINATION bin/indentlog/example) +install(TARGETS indentlog_ex3 DESTINATION bin/indentlog/example) +install(TARGETS indentlog_ex4 DESTINATION bin/indentlog/example) diff --git a/example/ex1/CMakeLists.txt b/example/ex1/CMakeLists.txt index a9d1b27d..f42c56de 100644 --- a/example/ex1/CMakeLists.txt +++ b/example/ex1/CMakeLists.txt @@ -1,2 +1,2 @@ -add_executable(ex1 ex1.cpp) -xo_include_options2(ex1) +add_executable(indentlog_ex1 ex1.cpp) +xo_include_options2(indentlog_ex1) diff --git a/example/ex2/CMakeLists.txt b/example/ex2/CMakeLists.txt index 20026b03..2dc39192 100644 --- a/example/ex2/CMakeLists.txt +++ b/example/ex2/CMakeLists.txt @@ -1,2 +1,4 @@ -add_executable(ex2 ex2.cpp) -xo_include_options2(ex2) +# NOTE: need target names to be globally unique within the xo umbrella + +add_executable(indentlog_ex2 ex2.cpp) +xo_include_options2(indentlog_ex2) diff --git a/example/ex3/CMakeLists.txt b/example/ex3/CMakeLists.txt index 9791a931..bb5110ce 100644 --- a/example/ex3/CMakeLists.txt +++ b/example/ex3/CMakeLists.txt @@ -1,2 +1,2 @@ -add_executable(ex3 ex3.cpp) -xo_include_options2(ex3) +add_executable(indentlog_ex3 ex3.cpp) +xo_include_options2(indentlog_ex3) diff --git a/example/ex4/CMakeLists.txt b/example/ex4/CMakeLists.txt index 2a6b9c31..6ff720f7 100644 --- a/example/ex4/CMakeLists.txt +++ b/example/ex4/CMakeLists.txt @@ -1,2 +1,2 @@ -add_executable(ex4 ex4.cpp) -xo_include_options2(ex4) +add_executable(indentlog_ex4 ex4.cpp) +xo_include_options2(indentlog_ex4) From 86fb63c6794e9dd9d4abfb10a247b48f737bb8b9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 22 Oct 2023 20:39:54 -0400 Subject: [PATCH 132/170] bugfix: drop std::move to allow copy elisison --- include/xo/indentlog/log_state.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/indentlog/log_state.hpp b/include/xo/indentlog/log_state.hpp index d7bec9ae..29ad0dda 100644 --- a/include/xo/indentlog/log_state.hpp +++ b/include/xo/indentlog/log_state.hpp @@ -347,7 +347,7 @@ namespace xo { ss << code_location(this->file_, this->line_, log_config::code_location_color); - std::string ss_str = std::move(ss.str()); /*c++20*/ + std::string ss_str = ss.str(); /*hoping for copy elision here*/ sbuf2->sputn(ss_str.c_str(), ss_str.size()); this->location_flag_ = false; From 264d74caed15bfd6068a0503d34ab7a4c1d5ecad Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 23 Oct 2023 14:33:19 -0400 Subject: [PATCH 133/170] cmake: minor consolidation --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6799082..a4b00e15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,7 @@ project(indentlog VERSION 0.1) enable_language(CXX) # common XO cmake macros (see proj/xo-cmake) -include(xo_macros/xo_cxx) -include(xo_macros/code-coverage) +include(xo_macros/xo-project-macros) # ---------------------------------------------------------------- # unit test setup From aa8f431cc292353c70c7df71db771e052d21cdc8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 13 Mar 2024 15:30:31 -0400 Subject: [PATCH 134/170] indentlog: cosmetic: + comment --- include/xo/indentlog/log_streambuf.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/indentlog/log_streambuf.hpp b/include/xo/indentlog/log_streambuf.hpp index 3a467b82..0c4b3aae 100644 --- a/include/xo/indentlog/log_streambuf.hpp +++ b/include/xo/indentlog/log_streambuf.hpp @@ -80,7 +80,7 @@ namespace xo { char * p_hi = p_base + this->buf_v_.capacity(); this->setp(p_base, p_hi); - this->pbump(old_n + 1); + this->pbump(old_n + 1); /*see 'this->buf_v_[old_n] - new_ch' above*/ return new_ch; } /*overflow*/ From bcf9713e07f2fa7a3c66ecab33c1df63bc17a5a7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Mar 2024 19:23:15 -0400 Subject: [PATCH 135/170] build: streamline CMAKE_MODULE_PATH interaction --- cmake/xo-bootstrap-macros.cmake | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 cmake/xo-bootstrap-macros.cmake diff --git a/cmake/xo-bootstrap-macros.cmake b/cmake/xo-bootstrap-macros.cmake new file mode 100644 index 00000000..16644435 --- /dev/null +++ b/cmake/xo-bootstrap-macros.cmake @@ -0,0 +1,12 @@ +if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "prefix")) + # default to typical install location for xo-project-macros + set(CMAKE_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/share/cmake) +endif() + +message("-- CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") +message("-- CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + +# needs to have been installed somewhere on CMAKE_MODULE_PATH, +# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) +# +include(xo_macros/xo-project-macros) From 94be37cef77355d81cf861bbb9564930cc594571 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 15 Mar 2024 19:23:51 -0400 Subject: [PATCH 136/170] build: streamline CMAKE_MODULE_PATH interaction (2) --- .gitignore | 3 +-- CMakeLists.txt | 2 +- indentlogConfig.cmake.in | 4 ---- 3 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 indentlogConfig.cmake.in diff --git a/.gitignore b/.gitignore index 81c5ae6d..7ebf47c3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,4 @@ compile_commands.json # lsp keeps state here .cache # typical build dirs -build -ccov +.build* diff --git a/CMakeLists.txt b/CMakeLists.txt index f8d04834..43ded08e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ project(indentlog VERSION 0.1) enable_language(CXX) # common XO cmake macros (see proj/xo-cmake) -include(xo_macros/xo-project-macros) +include(cmake/xo-bootstrap-macros.cmake) # ---------------------------------------------------------------- # unit test setup diff --git a/indentlogConfig.cmake.in b/indentlogConfig.cmake.in deleted file mode 100644 index cc57615e..00000000 --- a/indentlogConfig.cmake.in +++ /dev/null @@ -1,4 +0,0 @@ -@PACKAGE_INIT@ - -include("${CMAKE_CURRENT_LIST_DIR}/indentlogTargets.cmake") -check_required_components("@PROJECT_NAME@") From dd2a897192fc51feb6429ed28fcacb1963d0c5df Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 29 Mar 2024 14:33:41 -0400 Subject: [PATCH 137/170] build: suppress bootstrap message in submodule build --- cmake/xo-bootstrap-macros.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/xo-bootstrap-macros.cmake b/cmake/xo-bootstrap-macros.cmake index 16644435..96592216 100644 --- a/cmake/xo-bootstrap-macros.cmake +++ b/cmake/xo-bootstrap-macros.cmake @@ -3,8 +3,10 @@ if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "pr set(CMAKE_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/share/cmake) endif() -message("-- CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") -message("-- CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") +if (NOT XO_SUBMODULE_BUILD) + message("-- CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") + message("-- CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") +endif() # needs to have been installed somewhere on CMAKE_MODULE_PATH, # (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) From d42d29fa52fe1f1f7d3e9dbd9f38f9d56c638807 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 29 Mar 2024 14:52:24 -0400 Subject: [PATCH 138/170] indentlog: allow for multiply STRINGIFY macro defs --- include/xo/indentlog/print/tag.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/xo/indentlog/print/tag.hpp b/include/xo/indentlog/print/tag.hpp index 7d4a0abc..de6a9d75 100644 --- a/include/xo/indentlog/print/tag.hpp +++ b/include/xo/indentlog/print/tag.hpp @@ -9,7 +9,9 @@ #include // STRINGIFY(xyz) -> "xyz" -#define STRINGIFY(x) #x +#ifndef STRINGIFY +# define STRINGIFY(x) #x +#endif // TAG(xyz) -> tag("xyz", xyz) #define TAG(x) xo::make_tag(STRINGIFY(x), x) From 8bbf32680585b25da2a629f8df1519600f30799a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 29 Mar 2024 14:54:05 -0400 Subject: [PATCH 139/170] lsp: prevent some false complaints from LSP clang seeing gcc headers --- include/xo/indentlog/machdep/machdep.hpp | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 include/xo/indentlog/machdep/machdep.hpp diff --git a/include/xo/indentlog/machdep/machdep.hpp b/include/xo/indentlog/machdep/machdep.hpp new file mode 100644 index 00000000..11c2f3e9 --- /dev/null +++ b/include/xo/indentlog/machdep/machdep.hpp @@ -0,0 +1,26 @@ +/* @file machdep.hpp */ + +#pragma once + +/** Carveout for LSP (language server process): + LSP uses clang, but with the same compiler flags as primary build. + This triggers a handful of false alarms, in which clang complains about + gcc builtins. + + Replace these with something innocuous. Ok since LSP stops + once parsing completes and does not generate code + **/ +#if __clang__ && __GNUG__ + +extern "C" { + /* never defined! must not ever generate code that relies on these */ + unsigned int fake_mm_getcsr(); + unsigned int fake_mm_setcsr(unsigned int a); +} + +#define _mm_getcsr(a) fake_mm_getcsr() +#define _mm_setcsr(a) fake_mm_setcsr(a) + +#endif + +/* end machdep.hpp */ From 20774158ad3cd2f5feadecf9b994972443538ef7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 1 Apr 2024 18:01:24 -0400 Subject: [PATCH 140/170] xo-indentlog: + XTAG() macro --- include/xo/indentlog/print/tag.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/xo/indentlog/print/tag.hpp b/include/xo/indentlog/print/tag.hpp index de6a9d75..0973506d 100644 --- a/include/xo/indentlog/print/tag.hpp +++ b/include/xo/indentlog/print/tag.hpp @@ -17,6 +17,9 @@ #define TAG(x) xo::make_tag(STRINGIFY(x), x) #define TAG2(x, y) xo::make_tag(x, y) +#define XTAG(x) xo::xtag(STRINGIFY(x), x) +//#define XTAG2(x, y) xo::xtag(x, y) + namespace xo { // associate a name with a value // From 8d81f4fb91b91c6debd5120a0ef56caf6484604d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 17 Apr 2024 18:23:22 -0400 Subject: [PATCH 141/170] xo-indentlog: build: print GUESSED_CMAKE_CMD --- cmake/xo-bootstrap-macros.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/xo-bootstrap-macros.cmake b/cmake/xo-bootstrap-macros.cmake index 96592216..3899fe86 100644 --- a/cmake/xo-bootstrap-macros.cmake +++ b/cmake/xo-bootstrap-macros.cmake @@ -4,6 +4,7 @@ if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "pr endif() if (NOT XO_SUBMODULE_BUILD) + message("-- GUESSED_CMAKE_CMD=cmake -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -B ${CMAKE_BINARY_DIR}") message("-- CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") message("-- CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") endif() From bdb39b82263b0bed5ee3c0fb6795e9d789f16bc4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 17 Apr 2024 18:23:39 -0400 Subject: [PATCH 142/170] xo-indentlog: + hex printer --- include/xo/indentlog/print/hex.hpp | 144 +++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 include/xo/indentlog/print/hex.hpp diff --git a/include/xo/indentlog/print/hex.hpp b/include/xo/indentlog/print/hex.hpp new file mode 100644 index 00000000..66a34084 --- /dev/null +++ b/include/xo/indentlog/print/hex.hpp @@ -0,0 +1,144 @@ +/** @file hex.hpp **/ + +#pragma once + +#include + +namespace xo { + /** + @class hex indentlog/print/hex.hpp + + @brief Container for a (1-byte) value to be printed in hexadecimal + + Example: + @code + #include "indentlog/print/hex.hpp" + + std::ostream os = ...; + os << hex(16 + 63); // output: 1f + os << hex(16 + 63, true); // output: 1f(O) + @endcode + **/ + struct hex { + /** @brief constructor; create stream-inserter instance */ + hex(std::uint8_t x, bool w_char = false) : x_{x}, with_char_{w_char} {} + + /** + @brief print hexadecimal byte-value on to stream. + @param os print on this stream. + + @tparam Stream typename for character stream. + **/ + template + void print(Stream & os) const { + std::uint8_t lo = x_ & 0xf; + std::uint8_t hi = x_ >> 4; + + char lo_ch = (lo < 10) ? '0' + lo : 'a' + lo - 10; + char hi_ch = (hi < 10) ? '0' + hi : 'a' + hi - 10; + + os << hi_ch << lo_ch; + + if (with_char_) { + os << "("; + if (std::isprint(x_)) + os << static_cast(x_); + else + os << "?"; + os << ")"; + } + } + + private: + /** @brief value to print (in hexadecimal) **/ + std::uint8_t x_; + /** @brief if true, follow with ascii character encoding **/ + bool with_char_; + }; + + /** + @brief stream inserter for an 8-bit quantity to be printed in hexadecimal. + + @param os print on this stream + @param ins package for value to insert + **/ + template + Stream & + operator<< (Stream & os, hex const & ins) { + ins.print(os); + return os; + } + + /** + @class hex_view indentlog/print/hex.hpp + + @brief Container for a range (unowned) of 1-byte values to be printed in hexadecimal + + Print a range of bytes on an arbitrary character stream. + Does not use @c iomanips, so will not alter stream formatting flags if used with @c iostream. + + Example: + @code + #include "indentlog/print/hex.hpp" + + std::ostream os = ...; + os << hex_view("hello", false); // output: [68 65 6c 6c 6f] + os << hex_view("hello", true); // output: [68(h) 65(e) 6c(l) 6c(l) 6f(o)] + @endcode + **/ + struct hex_view { + /** @brief constructor; create stream-inserter instance for a range of bytes **/ + hex_view(std::uint8_t const * lo, std::uint8_t const * hi, bool as_text) + : lo_{lo}, hi_{hi}, as_text_{as_text} {} + /** @brief constructor; create stream-inserter instance for a range of chars **/ + hex_view(char const * lo, char const * hi, bool as_text) + : lo_{reinterpret_cast(lo)}, + hi_{reinterpret_cast(hi)}, + as_text_{as_text} {} + + /** + @brief print hexadecimal byte range on stream. + @param os print on this stream + + @tparam Stream typename for character stream. + **/ + template + void print(Stream & os) const { + os << "["; + std::size_t i = 0; + for (std::uint8_t const * p = lo_; p < hi_; ++p) { + if (i > 0) + os << " "; + os << hex(*p, as_text_); + ++i; + } + os << "]"; + } + + private: + /** @brief print byte range starting at this address **/ + std::uint8_t const * lo_; + /** @brief print byte range up to (but not including) this address **/ + std::uint8_t const * hi_; + /** @brief if true also print ascii encoding (for printable codes), + * \c ? otherwise. @see hex::with_char + **/ + bool as_text_; + }; + + /** + @brief stream inserter for a range of 1-byte values to be printed in hexadecimal + + @param os print on this stream. + @param ins (container for) values to insert. + **/ + template + Stream & + operator<< (Stream & os, hex_view const & ins) { + ins.print(os); + return os; + } + +} /*namespace xo*/ + +/* end hex.hpp */ From 292a410f1f78f4b4b908c6dde3aab39bafe457ba Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 28 Apr 2024 14:45:31 -0400 Subject: [PATCH 143/170] xo-indentlog: hex() explicit kword to avoid ambiguity w/ templates --- include/xo/indentlog/print/hex.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/xo/indentlog/print/hex.hpp b/include/xo/indentlog/print/hex.hpp index 66a34084..8f5f6f35 100644 --- a/include/xo/indentlog/print/hex.hpp +++ b/include/xo/indentlog/print/hex.hpp @@ -3,6 +3,7 @@ #pragma once #include +#include namespace xo { /** @@ -21,7 +22,7 @@ namespace xo { **/ struct hex { /** @brief constructor; create stream-inserter instance */ - hex(std::uint8_t x, bool w_char = false) : x_{x}, with_char_{w_char} {} + explicit hex(std::uint8_t x, bool w_char = false) : x_{x}, with_char_{w_char} {} /** @brief print hexadecimal byte-value on to stream. @@ -62,9 +63,8 @@ namespace xo { @param os print on this stream @param ins package for value to insert **/ - template - Stream & - operator<< (Stream & os, hex const & ins) { + inline std::iostream & + operator<< (std::iostream & os, hex const & ins) { ins.print(os); return os; } From 86c6bbe8060e08c898af23a3fdfa9a77354266b1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 28 Apr 2024 14:46:34 -0400 Subject: [PATCH 144/170] xo-indentlog: bugfix: escaped special chars behaving unexpectedly --- include/xo/indentlog/print/quoted.hpp | 5 ++-- utest/quoted.test.cpp | 35 +++++++++++++++++++-------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/include/xo/indentlog/print/quoted.hpp b/include/xo/indentlog/print/quoted.hpp index 8629ac39..5b7621f4 100644 --- a/include/xo/indentlog/print/quoted.hpp +++ b/include/xo/indentlog/print/quoted.hpp @@ -74,11 +74,12 @@ namespace xo { break; case '\n': /* newline -> \n */ - os << "\\\n"; + /* somehow attempt to escape the newline triggers collapse */ + os << "\\n"; break; case '\r': /* cr -> \r */ - os << "\\\r"; + os << "\\r"; break; case '\\': /* \ => \\ (mind c++ requires we escape \) */ diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index e90c195b..c8d025ff 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -12,7 +12,7 @@ namespace ut { struct quoted_tcase { quoted_tcase() = default; quoted_tcase(std::string x, bool unq_flag, std::string s) - : x_{x}, unq_flag_{unq_flag}, s_{std::move(s)} {} + : x_{std::move(x)}, unq_flag_{unq_flag}, s_{std::move(s)} {} /* string to be printed-in-machine-readable-form */ std::string x_; @@ -33,30 +33,37 @@ namespace ut { quoted_tcase("foo", true, "foo"), quoted_tcase("foo", false, "\"foo\""), - quoted_tcase("foo\n", true, "\"foo\\\n\""), - quoted_tcase("foo\n", false, "\"foo\\\n\""), + quoted_tcase("foo\n", true, "\"foo\\n\""), + quoted_tcase("foo\n", false, "\"foo\n\""), /* writes "foo\n", but gets turned into newline somewhere */ quoted_tcase("two words", true, "\"two words\""), quoted_tcase("two words", false, "\"two words\""), - quoted_tcase("1st\n2nd", true, "\"1st\\\n2nd\""), - quoted_tcase("1st\n2nd", true, "\"1st\\\n2nd\""), + quoted_tcase("1st\n2nd", true, "\"1st\\n2nd\""), + quoted_tcase("1st\n2nd", false, "\"1st\n2nd\""), - quoted_tcase("misakte\rfix", true, "\"misakte\\\rfix\""), - quoted_tcase("misakte\rfix", true, "\"misakte\\\rfix\""), + quoted_tcase("misakte\rfix", true, "\"misakte\\rfix\""), + quoted_tcase("misakte\rfix", false, "\"misakte\rfix\""), quoted_tcase("\"oh!\", she said", true, "\"\\\"oh!\\\", she said\""), quoted_tcase("\"oh!\", she said", false, "\"\\\"oh!\\\", she said\""), quoted_tcase("", true, ""), - quoted_tcase("", false, ""), + quoted_tcase("", false, "\"\""), }); TEST_CASE("quoted", "[quoted]") { for (std::uint32_t i_tc = 0, z_tc = s_quoted_tcase_v.size(); i_tc < z_tc; ++i_tc) { quoted_tcase const & tc = s_quoted_tcase_v[i_tc]; - INFO(tostr(xtag("i_tc", i_tc), xtag("x", tc.x_), xtag("unq_flag", tc.unq_flag_))); + INFO(tostr("i_tc=", i_tc, " unq_flag=", tc.unq_flag_)); + INFO("tc.x_ ----------------"); + INFO(tostr("[", tc.x_, "]")); + INFO("tc.x_ ----------------"); + + bool special_char = (tc.x_.find_first_of(" \"\n\r\\") != std::string::npos); + + INFO(tostr("special_char=", special_char)); std::stringstream ss; if (tc.unq_flag_) @@ -64,9 +71,17 @@ namespace ut { else ss << quoted(tc.x_); - INFO(xtag("ss.str", ss.str())); + INFO("tc.s ----------------"); + INFO(tostr("[", tc.s_, "]")); + INFO("tc.s ----------------"); + INFO("ss.str ----------------"); + INFO(tostr("[", ss.str(), "]")); + INFO("ss.str ----------------"); REQUIRE(ss.str() == tc.s_); + + if (ss.str() != tc.s_) + break; } REQUIRE(s_quoted_tcase_v.size() > 1); From 74eda2bc75b3b1b9fa6edc25639147b384c22b33 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 28 Apr 2024 14:47:01 -0400 Subject: [PATCH 145/170] xo-indentlog: bugfix: + array size to satisfy compiler warning --- include/xo/indentlog/timeutil/timeutil.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/indentlog/timeutil/timeutil.hpp b/include/xo/indentlog/timeutil/timeutil.hpp index 5e57aeb0..f1b2a938 100644 --- a/include/xo/indentlog/timeutil/timeutil.hpp +++ b/include/xo/indentlog/timeutil/timeutil.hpp @@ -259,7 +259,7 @@ namespace xo { auto [t0_tm, t0_usec] = utc_split_tm(t0); /* no std::format in clang11 afaict */ - char usec_buf[7]; + char usec_buf[8]; snprintf(usec_buf, sizeof(usec_buf), "%06d", t0_usec); From 27dec697ede1deaaad8cb1e0ef93690d3c39582c Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 28 Apr 2024 14:47:29 -0400 Subject: [PATCH 146/170] xo-indentlog: explicit cstdint to satisfy compiler warning --- include/xo/indentlog/print/fixed.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/xo/indentlog/print/fixed.hpp b/include/xo/indentlog/print/fixed.hpp index bf1a5526..84b7e225 100644 --- a/include/xo/indentlog/print/fixed.hpp +++ b/include/xo/indentlog/print/fixed.hpp @@ -3,6 +3,7 @@ #pragma once #include +#include namespace xo { /* use: @@ -17,12 +18,12 @@ namespace xo { */ class fixed { public: - fixed(double x, uint16_t prec) : x_{x}, prec_{prec} {} + fixed(double x, std::uint16_t prec) : x_{x}, prec_{prec} {} /* print this value */ double x_; /* precision */ - uint16_t prec_ = 0; + std::uint16_t prec_ = 0; }; /*fixed*/ inline std::ostream & From 3d4821cc842fa841264903350d7d09c5eef84ee6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 28 Apr 2024 14:47:51 -0400 Subject: [PATCH 147/170] xo-indentlog: build: streamline using new xo-cmake macros --- CMakeLists.txt | 38 +++++++++++---------------------- cmake/xo-bootstrap-macros.cmake | 34 +++++++++++++++++++++++------ utest/CMakeLists.txt | 34 +++-------------------------- 3 files changed, 43 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43ded08e..c3afcca9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,29 +2,22 @@ cmake_minimum_required(VERSION 3.10) -project(indentlog VERSION 0.1) -enable_language(CXX) +project(indentlog VERSION 1.0) -# common XO cmake macros (see proj/xo-cmake) +include(GNUInstallDirs) include(cmake/xo-bootstrap-macros.cmake) -# ---------------------------------------------------------------- -# unit test setup - -enable_testing() -# activate code coverage for all executables + libraries (when -DCODE_COVERAGE=ON) -add_code_coverage() - -# 1. assuming that /nix/store/ prefixes .hpp files belonging to gcc, catch2 etc. -# we're not interested in code coverage for these sources. -# 2. exclude the utest/ subdir, we don't need coverage on the unit tests themselves; -# rather, want coverage on the code that the unit tests exercise. -# -add_code_coverage_all_targets(EXCLUDE /nix/store/* utest/*) +xo_cxx_toplevel_options2() # ---------------------------------------------------------------- +# cmake -DCMAKE_BUILD_TYPE=debug +xo_toplevel_debug_config2() -xo_toplevel_compile_options() +# ---------------------------------------------------------------- +# cmake -DCMAKE_BUILD_TYPE=coverage +xo_toplevel_coverage_config2() + +# ---------------------------------------------------------------- add_subdirectory(example) add_subdirectory(utest) @@ -32,14 +25,9 @@ add_subdirectory(utest) # header-only library. # see [[https://stackoverflow.com/questions/47718485/install-and-export-interface-only-library-cmake]] # -xo_add_headeronly_library(indentlog) - -# ---------------------------------------------------------------- -# standard install + provide find_package() support - -#xo_install_library2(indentlog) -#xo_install_include_tree() -xo_install_library4(indentlog ${PROJECT_NAME}Targets) +set(SELF_LIB indentlog) +xo_add_headeronly_library(${SELF_LIB}) +xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets) xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) # ---------------------------------------------------------------- diff --git a/cmake/xo-bootstrap-macros.cmake b/cmake/xo-bootstrap-macros.cmake index 3899fe86..aba31169 100644 --- a/cmake/xo-bootstrap-macros.cmake +++ b/cmake/xo-bootstrap-macros.cmake @@ -1,15 +1,35 @@ -if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "prefix")) - # default to typical install location for xo-project-macros - set(CMAKE_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/share/cmake) +# ---------------------------------------------------------------- +# for example: +# $ PREFIX=/usr/local # for example +# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build +# +# will get +# CMAKE_MODULE_PATH +# from xo-cmake-config --cmake-module-path +# +# and expect .cmake macros in +# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake +# ---------------------------------------------------------------- + +find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED) + +if ("${XO_CMAKE_CONFIG_EXECUTABLE}" STREQUAL "XO_CMAKE_CONFIG_EXECUTABLE-NOT_FOUND") + message(FATAL "could not find xo-cmake-config executable") endif() +message(STATUS "XO_CMAKE_CONFIG_EXECUTABLE=${XO_CMAKE_CONFIG_EXECUTABLE}") + if (NOT XO_SUBMODULE_BUILD) - message("-- GUESSED_CMAKE_CMD=cmake -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -B ${CMAKE_BINARY_DIR}") - message("-- CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}") - message("-- CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix)) + # default to typical install location for xo-project-macros + execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH) + message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + endif() endif() # needs to have been installed somewhere on CMAKE_MODULE_PATH, # (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) # -include(xo_macros/xo-project-macros) +include(xo_macros/xo_cxx) + +xo_cxx_bootstrap_message() diff --git a/utest/CMakeLists.txt b/utest/CMakeLists.txt index 1b92e999..ea4bb819 100644 --- a/utest/CMakeLists.txt +++ b/utest/CMakeLists.txt @@ -6,40 +6,12 @@ set(SELF_SOURCE_FILES filename.test.cpp code_location.test.cpp function.test.cpp indentlog_utest_main.cpp) -add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) -xo_include_options2(${SELF_EXECUTABLE_NAME}) - -add_test(NAME ${SELF_EXECUTABLE_NAME} COMMAND ${SELF_EXECUTABLE_NAME}) -target_code_coverage(${SELF_EXECUTABLE_NAME} AUTO ALL) +xo_add_utest_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES}) # ---------------------------------------------------------------- # 3rd party dependency: catch2 +xo_self_dependency(${SELF_EXECUTABLE_NAME} indentlog) xo_external_target_dependency(${SELF_EXECUTABLE_NAME} Catch2 Catch2::Catch2) -# 1. using target_link_libraries(.. Catch2) here doesn't work; -# build tries to link to a Catch2 library. -# perhaps Catch2 target not declared INTERFACE? -# 2. nix build doesn't need this; dependency on catch2 -# puts include directory in NIX_CFLAGS_COMPILE, so stuff 'just works' -# - -#find_package(Catch2 2 REQUIRED) -#target_link_libraries(${SELF_EXECUTABLE_NAME} Catch2::Catch2) - -#set(Catch2_INCLUDES "${Catch2_DIR}/../../../include") -#target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC ${Catch2_INCLUDES}) - -#xo_internal_dependency(${SELF_EXECUTABLE_NAME} Catch2) -#target_link_libraries(${SELF_EXECUTABLE_NAME} PUBLIC Catch2) - -# ---------------------------------------------------------------- -# make standard directories for std:: includes explicit -# so that -# (1) they appear in compile_commands.json. -# (2) clangd (run from emacs lsp-mode) can find them -# -if(CMAKE_EXPORT_COMPILE_COMMANDS) - set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES - ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) -endif() +# end CMakeLists.txt From 6b0acb1d7b77aefc0b506147da52229200b384a5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 29 Apr 2024 00:49:43 -0400 Subject: [PATCH 148/170] xo-indentlog: github: re-run tests on failure --- .github/workflows/cmake-single-platform.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 433a3f9f..ac19e807 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -58,3 +58,7 @@ jobs: # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} + + - name: Retest self (indentlog) + working-directory: ${{github.workspace}}/build + run: ctest -C ${{env.BUILD_TYPE}} --rerun-failed --output-on-failure From 9ef4f66ec34d39f6d7a3145aacffdaada7f665cb Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 29 Apr 2024 00:51:29 -0400 Subject: [PATCH 149/170] xo-indentlog: github: retry test --- .github/workflows/cmake-single-platform.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index ac19e807..9c268e74 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -57,8 +57,4 @@ jobs: working-directory: ${{github.workspace}}/build # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest -C ${{env.BUILD_TYPE}} - - - name: Retest self (indentlog) - working-directory: ${{github.workspace}}/build run: ctest -C ${{env.BUILD_TYPE}} --rerun-failed --output-on-failure From 453f8aa9e1f329bab050442b87230abd19c01c16 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 29 Apr 2024 10:39:33 -0400 Subject: [PATCH 150/170] xo-indentlog: bugfix: gcc version check on embedded newline test --- utest/quoted.test.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index c8d025ff..16c8a893 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -34,7 +34,12 @@ namespace ut { quoted_tcase("foo", false, "\"foo\""), quoted_tcase("foo\n", true, "\"foo\\n\""), - quoted_tcase("foo\n", false, "\"foo\n\""), /* writes "foo\n", but gets turned into newline somewhere */ +#if __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 + /* writes "foo\n", but gets turned into newline somewhere. only on very recent gcc. */ + quoted_tcase("foo\n", false, "\"foo\n\""), +#else + quoted_tcase("foo\n", false, "\"foo\\n\""), +#endif quoted_tcase("two words", true, "\"two words\""), quoted_tcase("two words", false, "\"two words\""), From 340deff5faae721fd24a7d8ba569c7894afa1517 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 29 Apr 2024 10:43:06 -0400 Subject: [PATCH 151/170] xo-indentlog: minor: comment --- utest/quoted.test.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index 16c8a893..dff5c751 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -35,7 +35,7 @@ namespace ut { quoted_tcase("foo\n", true, "\"foo\\n\""), #if __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 - /* writes "foo\n", but gets turned into newline somewhere. only on very recent gcc. */ + /* writes "foo\n", but gets turned into newline somewhere. only on very recent gcc. (not on 11.4.0) */ quoted_tcase("foo\n", false, "\"foo\n\""), #else quoted_tcase("foo\n", false, "\"foo\\n\""), @@ -45,7 +45,12 @@ namespace ut { quoted_tcase("two words", false, "\"two words\""), quoted_tcase("1st\n2nd", true, "\"1st\\n2nd\""), +#if __GNUC__ >= 13 && __GNUC_MINOR_ >= 2 + /* writes "1st\\nsecond", but still gets turned into newline somewhere. only on very recent gcc. (not on 11.4.0) */ quoted_tcase("1st\n2nd", false, "\"1st\n2nd\""), +#else + quoted_tcase("1st\n2nd", false, "\"1st\\n2nd\""), +#endif quoted_tcase("misakte\rfix", true, "\"misakte\\rfix\""), quoted_tcase("misakte\rfix", false, "\"misakte\rfix\""), From 787aba1e19ca5ce97cd8b597662f54b6dc7b19c3 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 29 Apr 2024 10:45:54 -0400 Subject: [PATCH 152/170] xo-indentlog: utest: ++ behavior tracking for gcc 13.2 --- utest/quoted.test.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index dff5c751..32e641bb 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -53,7 +53,11 @@ namespace ut { #endif quoted_tcase("misakte\rfix", true, "\"misakte\\rfix\""), +#if __GNUC__ >= 13 && __GNUC_MINOR >= 2 quoted_tcase("misakte\rfix", false, "\"misakte\rfix\""), +#else + quoted_tcase("misakte\rfix", false, "\"misakte\\rfix\""), +#endif quoted_tcase("\"oh!\", she said", true, "\"\\\"oh!\\\", she said\""), quoted_tcase("\"oh!\", she said", false, "\"\\\"oh!\\\", she said\""), @@ -66,6 +70,10 @@ namespace ut { for (std::uint32_t i_tc = 0, z_tc = s_quoted_tcase_v.size(); i_tc < z_tc; ++i_tc) { quoted_tcase const & tc = s_quoted_tcase_v[i_tc]; + /* NOTE: don't use tag()/xtag() here, + * since implementation relies on the inserter we are testing + */ + INFO(tostr("i_tc=", i_tc, " unq_flag=", tc.unq_flag_)); INFO("tc.x_ ----------------"); INFO(tostr("[", tc.x_, "]")); From 89fc563f009307193b281b9058d689d9ebf1c7d7 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 29 Apr 2024 10:56:18 -0400 Subject: [PATCH 153/170] xo-indentlog: utest: track gcc behavior change around 13.2 --- include/xo/indentlog/print/quoted.hpp | 2 +- utest/quoted.test.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/xo/indentlog/print/quoted.hpp b/include/xo/indentlog/print/quoted.hpp index 5b7621f4..4cc19594 100644 --- a/include/xo/indentlog/print/quoted.hpp +++ b/include/xo/indentlog/print/quoted.hpp @@ -97,7 +97,7 @@ namespace xo { private: /* .unq_flag: if true, omit surrounding " chars - * if printed value satisfies both: + * whenever printed value satisfies both: * - no escaped chars * - no spaces */ diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index 32e641bb..9f65ea33 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -45,7 +45,7 @@ namespace ut { quoted_tcase("two words", false, "\"two words\""), quoted_tcase("1st\n2nd", true, "\"1st\\n2nd\""), -#if __GNUC__ >= 13 && __GNUC_MINOR_ >= 2 +#if __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 /* writes "1st\\nsecond", but still gets turned into newline somewhere. only on very recent gcc. (not on 11.4.0) */ quoted_tcase("1st\n2nd", false, "\"1st\n2nd\""), #else @@ -53,7 +53,7 @@ namespace ut { #endif quoted_tcase("misakte\rfix", true, "\"misakte\\rfix\""), -#if __GNUC__ >= 13 && __GNUC_MINOR >= 2 +#if __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 quoted_tcase("misakte\rfix", false, "\"misakte\rfix\""), #else quoted_tcase("misakte\rfix", false, "\"misakte\\rfix\""), @@ -63,7 +63,11 @@ namespace ut { quoted_tcase("\"oh!\", she said", false, "\"\\\"oh!\\\", she said\""), quoted_tcase("", true, ""), +#if __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 quoted_tcase("", false, "\"\""), +#else + quoted_tcase("", false, "\"\""), +#endif }); TEST_CASE("quoted", "[quoted]") { @@ -93,6 +97,7 @@ namespace ut { INFO(tostr("[", tc.s_, "]")); INFO("tc.s ----------------"); INFO("ss.str ----------------"); + INFO(tostr("[", ss.view(), "]")); INFO(tostr("[", ss.str(), "]")); INFO("ss.str ----------------"); From da58be3f386d0f8526ffeba9ac4214465f2f8eac Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 29 Apr 2024 10:59:04 -0400 Subject: [PATCH 154/170] xo-indentlog: print hex view on failed quoted()/unq() utest --- utest/quoted.test.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index 9f65ea33..d26cc1d1 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -1,14 +1,15 @@ /* @file fixed.test.cpp */ #include "xo/indentlog/print/quoted.hpp" -#include "xo/indentlog/print/tag.hpp" +//#include "xo/indentlog/print/tag.hpp" +#include "xo/indentlog/print/hex.hpp" #include #include -using namespace xo; -using namespace xo::print; - namespace ut { + using namespace xo; + using namespace xo::print; + struct quoted_tcase { quoted_tcase() = default; quoted_tcase(std::string x, bool unq_flag, std::string s) @@ -97,7 +98,7 @@ namespace ut { INFO(tostr("[", tc.s_, "]")); INFO("tc.s ----------------"); INFO("ss.str ----------------"); - INFO(tostr("[", ss.view(), "]")); + INFO(tostr("[", hex_view(ss.view().begin(), ss.view().end(), true), "]")); INFO(tostr("[", ss.str(), "]")); INFO("ss.str ----------------"); From f47c5db86639c0485af465e9e8c1742edf3b0ac5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 29 Apr 2024 23:03:00 -0500 Subject: [PATCH 155/170] xo-indentlog: fix regression in utest for <..> printers --- utest/quoted.test.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index d26cc1d1..df827421 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -63,12 +63,9 @@ namespace ut { quoted_tcase("\"oh!\", she said", true, "\"\\\"oh!\\\", she said\""), quoted_tcase("\"oh!\", she said", false, "\"\\\"oh!\\\", she said\""), + // special carveout for strings bracketed by <..>; assume already well-formed quoted_tcase("", true, ""), -#if __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 - quoted_tcase("", false, "\"\""), -#else - quoted_tcase("", false, "\"\""), -#endif + quoted_tcase("", false, ""), }); TEST_CASE("quoted", "[quoted]") { From 9d3cae1deeb940e2c55f2ca31b8f5e832c7e918d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 1 May 2024 14:49:55 -0400 Subject: [PATCH 156/170] xo-indentlog: workaround unexpected ambiguity with hex() inserter --- include/xo/indentlog/print/hex.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/xo/indentlog/print/hex.hpp b/include/xo/indentlog/print/hex.hpp index 8f5f6f35..8a6517d5 100644 --- a/include/xo/indentlog/print/hex.hpp +++ b/include/xo/indentlog/print/hex.hpp @@ -109,7 +109,8 @@ namespace xo { for (std::uint8_t const * p = lo_; p < hi_; ++p) { if (i > 0) os << " "; - os << hex(*p, as_text_); + xo::hex(*p, as_text_).print(os); + //os << xo::hex(*p, as_text_); ++i; } os << "]"; From f3f7e144ebb368c0d6854adad6feacafcc25027b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 1 May 2024 14:51:55 -0400 Subject: [PATCH 157/170] xo-indentlog: tweaking utest to explore gcc 13 regression --- utest/quoted.test.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index d26cc1d1..12120e87 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -1,5 +1,6 @@ /* @file fixed.test.cpp */ +#include "xo/indentlog/scope.hpp" #include "xo/indentlog/print/quoted.hpp" //#include "xo/indentlog/print/tag.hpp" #include "xo/indentlog/print/hex.hpp" @@ -26,6 +27,85 @@ namespace ut { std::string s_; }; /*quoted_tcase*/ + TEST_CASE("sstream.1char", "[quoted]") { + constexpr bool c_debug_flag = true; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream")); + + /* testing unexpected sstream behavior */ + { + std::stringstream ss; + + log && log("empty stream"); + + ss << '\\'; + + log && log("after: lone escaped backslash"); + log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + + ss << 'n'; + + log && log("after: lone 'n' char"); + log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + + log && log("ss.str()=[", ss.str(), "]"); + log && log("quoted(\"\\n\")=[", quoted("\\n"), "]"); + } + + /* testing unexpected sstream behavior */ + { + std::stringstream ss; + + log && log("empty stream"); + + ss << "\\n"; + + log && log("after: '\\n' escaped backslash + n"); + log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + } + + /* testing unexpected sstream behavior */ + { + std::stringstream ss; + + log && log("empty stream"); + + ss << quoted("\n"); + + log && log("after: quoted('\\n')"); + log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + } + + /* testing unexpected sstream behavior */ + { + std::stringstream ss; + + log && log("empty stream"); + + ss << quoted("foo\n"); + + log && log("after: quoted(\"foo\n\")"); + log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + log && log("> ss.str ----------------"); + log && log(ss.str()); + log && log("< ss.str ----------------"); + } + + /* testing unexpected sstream behavior */ + { + std::stringstream ss; + + log && log("empty stream"); + + ss << unq("\n"); + + log && log("after: unq('\\n')"); + log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + } + + } /*TEST_CASE(sstream)*/ + + std::vector s_quoted_tcase_v( { quoted_tcase("", true, "\"\""), From 307f82daa2a4d6d85efad4dbab31384342a77a96 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 1 May 2024 14:52:35 -0400 Subject: [PATCH 158/170] xo-indentlog: temporarily revert gcc13 carveout --- utest/quoted.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index 12120e87..7c1a8e02 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -115,7 +115,7 @@ namespace ut { quoted_tcase("foo", false, "\"foo\""), quoted_tcase("foo\n", true, "\"foo\\n\""), -#if __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 +#if 0 && __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 /* writes "foo\n", but gets turned into newline somewhere. only on very recent gcc. (not on 11.4.0) */ quoted_tcase("foo\n", false, "\"foo\n\""), #else From 088fd9b32c9d56cd624ea64456dafe2e8213f75f Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 1 May 2024 22:20:53 -0400 Subject: [PATCH 159/170] xo-indentlog: refactor: move escaping feature to own function --- include/xo/indentlog/print/quoted.hpp | 44 +++++++++++++++------------ 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/include/xo/indentlog/print/quoted.hpp b/include/xo/indentlog/print/quoted.hpp index 4cc19594..94bcef73 100644 --- a/include/xo/indentlog/print/quoted.hpp +++ b/include/xo/indentlog/print/quoted.hpp @@ -35,24 +35,9 @@ namespace xo { bool unq_flag() const { return unq_flag_; } T const & value() const { return value_; } - void print(std::ostream & os) const { - std::string xs = xo::tostr(value_); - - if (xs.empty()) { - /* always print empty string as "" */ - os << "\"\""; - } else if ((xs.at(0) == '<') && (xs.at(xs.size() - 1) == '>')) { - /* assume string represents output of a well-formed object printer, - * and already self-escapes - */ - os << xs; - } else if (xs.find_first_of(" \"\n\r\\") == std::string::npos) { - /* no escapes needed, just print xs */ - if (unq_flag_) - os << xs; - else - os << "\"" << xs << "\""; - } else { + void print_with_escapes(const std::string & xs, + std::ostream & os) const + { /* printed value contains a space * and/or a must-be-escaped character. * in any case, need quotes @@ -82,7 +67,7 @@ namespace xo { os << "\\r"; break; case '\\': - /* \ => \\ (mind c++ requires we escape \) */ + /* \ => \\ (mind c++ requires we escape \) */ os << "\\\\"; break; default: @@ -93,6 +78,27 @@ namespace xo { os << "\""; } + + void print(std::ostream & os) const { + std::string xs = xo::tostr(value_); + + if (xs.empty()) { + /* always print empty string as "" */ + os << "\"\""; + } else if ((xs.at(0) == '<') && (xs.at(xs.size() - 1) == '>')) { + /* assume string represents output of a well-formed object printer, + * and already self-escapes + */ + os << xs; + } else if (xs.find_first_of(" \"\n\r\\") == std::string::npos) { + /* no escapes needed, just print xs */ + if (unq_flag_) + os << xs; + else + os << "\"" << xs << "\""; + } else { + this->print_with_escapes(xs, os); + } } /*print*/ private: From ea7d79f95cb57f18445a65972283ef95b1b520b2 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 1 May 2024 22:31:27 -0400 Subject: [PATCH 160/170] xo-indentlog: xo::print::quoted -> quot, avoiding std::quoted --- CMakeLists.txt | 4 + include/xo/indentlog/print/quoted.hpp | 4 +- utest/quoted.test.cpp | 238 ++++++++++++++++++++------ utest/tag.test.cpp | 10 +- 4 files changed, 197 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3afcca9..46f3bdbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,10 @@ xo_cxx_toplevel_options2() # cmake -DCMAKE_BUILD_TYPE=debug xo_toplevel_debug_config2() +# ---------------------------------------------------------------- +# cmake -DCMAKE_BUILD_TYPE=asan +xo_toplevel_asan_config2() + # ---------------------------------------------------------------- # cmake -DCMAKE_BUILD_TYPE=coverage xo_toplevel_coverage_config2() diff --git a/include/xo/indentlog/print/quoted.hpp b/include/xo/indentlog/print/quoted.hpp index 94bcef73..154f7702 100644 --- a/include/xo/indentlog/print/quoted.hpp +++ b/include/xo/indentlog/print/quoted.hpp @@ -135,12 +135,12 @@ namespace xo { * - std::string const & passed to quoted_impl ctor */ template - auto quoted(T && x) { + auto quot(T && x) { return quoted_impl(false /*unq_flag*/, std::forward(x)); } inline auto qcstr(char const * x) { - return quoted(x); + return quot(x); } /*qcstr*/ template diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index fa89ee05..8552bdbe 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -11,9 +11,9 @@ namespace ut { using namespace xo; using namespace xo::print; - struct quoted_tcase { - quoted_tcase() = default; - quoted_tcase(std::string x, bool unq_flag, std::string s) + struct quot_tcase { + quot_tcase() = default; + quot_tcase(std::string x, bool unq_flag, std::string s) : x_{std::move(x)}, unq_flag_{unq_flag}, s_{std::move(s)} {} /* string to be printed-in-machine-readable-form */ @@ -25,12 +25,24 @@ namespace ut { bool unq_flag_ = true; /* expected result */ std::string s_; - }; /*quoted_tcase*/ + }; /*quot_tcase*/ - TEST_CASE("sstream.1char", "[quoted]") { - constexpr bool c_debug_flag = true; + /* NOTE: spelled out tests here in aftermath + * of hard-to-diagnose regression in gcc 13.2; + * turned out to have something to originate in confusion + * between xo::print::quoted and std::quoted. + * + * Problem does not occur in gcc 12.3 and earlier, + * perhaps some alias for std::quoted appears somewhere in global + * namespace?? + * + * Resolved by renaming xo::print::quoted -> xo::print::quot + */ - scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream")); + TEST_CASE("sstream.1char", "[sstream]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream.1char")); /* testing unexpected sstream behavior */ { @@ -43,14 +55,45 @@ namespace ut { log && log("after: lone escaped backslash"); log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + REQUIRE(ss.view() == std::string_view("\\")); + ss << 'n'; log && log("after: lone 'n' char"); log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + REQUIRE(ss.view() == std::string_view("\\n")); + log && log("ss.str()=[", ss.str(), "]"); - log && log("quoted(\"\\n\")=[", quoted("\\n"), "]"); } + } /*TEST_CASE(sstream.1char)*/ + + TEST_CASE("sstream.2bslash", "[sstream]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream.2bslash")); + + /* testing unexpected sstream behavior */ + { + std::stringstream ss; + + log && log("empty stream"); + + ss << "\\\\"; + + log && log("after: 2x escaped backslash"); + log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + + REQUIRE(ss.view() == std::string_view("\\\\")); + + log && log("ss.str()=[", ss.str(), "]"); + } + } /*TEST_CASE(sstream.2bslash)*/ + + TEST_CASE("sstream.2char", "[sstream]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream.2char")); /* testing unexpected sstream behavior */ { @@ -63,6 +106,12 @@ namespace ut { log && log("after: '\\n' escaped backslash + n"); log && log(hex_view(ss.view().begin(), ss.view().end(), true)); } + } + + TEST_CASE("sstream.3char", "[sstream]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream.3char")); /* testing unexpected sstream behavior */ { @@ -70,9 +119,111 @@ namespace ut { log && log("empty stream"); - ss << quoted("\n"); + /* this is what quot("\\n") should wind up executing.. */ + ss << "\\\\"; + ss << 'n'; - log && log("after: quoted('\\n')"); + log && log("after: '\\\\n' 2x escaped backslash + n"); + log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + + REQUIRE(ss.view() == std::string_view("\\\\n")); + } + } + + TEST_CASE("sstream.quot.1bslash", "[quot]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream.quot.1bslash")); + + log && log("quot(\"\\\")=[", quot("\\"), "]"); + + std::stringstream ss2; + ss2 << quot("\\"); + + REQUIRE(ss2.view() == std::string_view("\"\\\\\"")); /* ["\\"] */ + } + + TEST_CASE("sstream.quot.newline", "[quot]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream.quot.newline")); + + log && log("quot(\"\\n\")=[", quot("\n"), "]"); + + std::stringstream ss2; + ss2 << quot("\n"); + + REQUIRE(ss2.view() == std::string_view("\"\\n\"")); /* ["\n"] */ + } + + TEST_CASE("sstream.quot.2bslash", "[quot]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.quot.2bslash")); + + log && log("quot(\"\\\\\")=[", quot("\\\\"), "]"); + + std::stringstream ss2; + ss2 << quot("\\\\"); /* quoting string with two backslashes need to give ["\\\\"] */ + + REQUIRE(ss2.view() == std::string_view("\"\\\\\\\\\"")); /* rhs is ["\\\\"] */ + } + + TEST_CASE("sstream.quot.2charnewline", "[quot]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream.quot.2charnewline")); + + log && log("quot(\"x\\n\")=[", quot("x\n"), "]"); + + std::stringstream ss2; + ss2 << quot("x\n"); + + REQUIRE(ss2.view() == std::string_view("\"x\\n\"")); /* ["\n"] */ + } + + TEST_CASE("sstream.quot.2char", "[quot]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.quot.2char")); + + log && log("quot(\"\\n\")=[", quot("\\n"), "]"); + + std::stringstream ss2; + ss2 << quot("\\n"); + + //std::cerr << quoted_debug::s_log_last_quoted.view() << std::endl; + + //log && log("debug_log=[", quoted_debug::s_log_last_quoted.view() , "]"); + + REQUIRE(ss2.view() == std::string_view("\"\\\\n\"")); + } + + TEST_CASE("sstream.quot.foonewline", "[quot]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream.quot.2charnewline")); + + std::stringstream ss2; + ss2 << quot("foo\n"); + + REQUIRE(ss2.view() == std::string_view("\"foo\\n\"")); /* ["\n"] */ + } + + TEST_CASE("sstream.rest", "[quot]") { + constexpr bool c_debug_flag = false; + + scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.sstream")); + + /* testing unexpected sstream behavior */ + { + std::stringstream ss; + + log && log("empty stream"); + + ss << quot("\n"); + + log && log("after: quot('\\n')"); log && log(hex_view(ss.view().begin(), ss.view().end(), true)); } @@ -82,9 +233,9 @@ namespace ut { log && log("empty stream"); - ss << quoted("foo\n"); + ss << quot("foo\n"); - log && log("after: quoted(\"foo\n\")"); + log && log("after: quot(\"foo\n\")"); log && log(hex_view(ss.view().begin(), ss.view().end(), true)); log && log("> ss.str ----------------"); log && log(ss.str()); @@ -105,52 +256,37 @@ namespace ut { } /*TEST_CASE(sstream)*/ - - std::vector s_quoted_tcase_v( + std::vector s_quot_tcase_v( { - quoted_tcase("", true, "\"\""), - quoted_tcase("", false, "\"\""), + quot_tcase("", true, "\"\""), + quot_tcase("", false, "\"\""), - quoted_tcase("foo", true, "foo"), - quoted_tcase("foo", false, "\"foo\""), + quot_tcase("foo", true, "foo"), + quot_tcase("foo", false, "\"foo\""), - quoted_tcase("foo\n", true, "\"foo\\n\""), -#if 0 && __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 - /* writes "foo\n", but gets turned into newline somewhere. only on very recent gcc. (not on 11.4.0) */ - quoted_tcase("foo\n", false, "\"foo\n\""), -#else - quoted_tcase("foo\n", false, "\"foo\\n\""), -#endif + quot_tcase("foo\n", true, "\"foo\\n\""), + quot_tcase("foo\n", false, "\"foo\\n\""), - quoted_tcase("two words", true, "\"two words\""), - quoted_tcase("two words", false, "\"two words\""), + quot_tcase("two words", true, "\"two words\""), + quot_tcase("two words", false, "\"two words\""), - quoted_tcase("1st\n2nd", true, "\"1st\\n2nd\""), -#if __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 - /* writes "1st\\nsecond", but still gets turned into newline somewhere. only on very recent gcc. (not on 11.4.0) */ - quoted_tcase("1st\n2nd", false, "\"1st\n2nd\""), -#else - quoted_tcase("1st\n2nd", false, "\"1st\\n2nd\""), -#endif + quot_tcase("1st\n2nd", true, "\"1st\\n2nd\""), + quot_tcase("1st\n2nd", false, "\"1st\\n2nd\""), - quoted_tcase("misakte\rfix", true, "\"misakte\\rfix\""), -#if __GNUC__ >= 13 && __GNUC_MINOR__ >= 2 - quoted_tcase("misakte\rfix", false, "\"misakte\rfix\""), -#else - quoted_tcase("misakte\rfix", false, "\"misakte\\rfix\""), -#endif + quot_tcase("misakte\rfix", true, "\"misakte\\rfix\""), + quot_tcase("misakte\rfix", false, "\"misakte\\rfix\""), - quoted_tcase("\"oh!\", she said", true, "\"\\\"oh!\\\", she said\""), - quoted_tcase("\"oh!\", she said", false, "\"\\\"oh!\\\", she said\""), + quot_tcase("\"oh!\", she said", true, "\"\\\"oh!\\\", she said\""), + quot_tcase("\"oh!\", she said", false, "\"\\\"oh!\\\", she said\""), // special carveout for strings bracketed by <..>; assume already well-formed - quoted_tcase("", true, ""), - quoted_tcase("", false, ""), + quot_tcase("", true, ""), + quot_tcase("", false, ""), }); - TEST_CASE("quoted", "[quoted]") { - for (std::uint32_t i_tc = 0, z_tc = s_quoted_tcase_v.size(); i_tc < z_tc; ++i_tc) { - quoted_tcase const & tc = s_quoted_tcase_v[i_tc]; + TEST_CASE("quot", "[quot]") { + for (std::uint32_t i_tc = 0, z_tc = s_quot_tcase_v.size(); i_tc < z_tc; ++i_tc) { + quot_tcase const & tc = s_quot_tcase_v[i_tc]; /* NOTE: don't use tag()/xtag() here, * since implementation relies on the inserter we are testing @@ -161,15 +297,11 @@ namespace ut { INFO(tostr("[", tc.x_, "]")); INFO("tc.x_ ----------------"); - bool special_char = (tc.x_.find_first_of(" \"\n\r\\") != std::string::npos); - - INFO(tostr("special_char=", special_char)); - std::stringstream ss; if (tc.unq_flag_) ss << unq(tc.x_); else - ss << quoted(tc.x_); + ss << quot(tc.x_); INFO("tc.s ----------------"); INFO(tostr("[", tc.s_, "]")); @@ -185,7 +317,7 @@ namespace ut { break; } - REQUIRE(s_quoted_tcase_v.size() > 1); + REQUIRE(s_quot_tcase_v.size() > 1); } } /*namespace ut*/ diff --git a/utest/tag.test.cpp b/utest/tag.test.cpp index 4b2d939e..72bba0f2 100644 --- a/utest/tag.test.cpp +++ b/utest/tag.test.cpp @@ -9,19 +9,21 @@ using namespace xo; namespace ut { + using xo::print::ccs; + TEST_CASE("tag", "[tag]") { tag_config::tag_color = color_spec_type::none(); { std::stringstream ss; - ss << tag("foo", "hello,world!"); + ss << tag("foo", ccs("hello,world!")); REQUIRE(ss.str() == ":foo hello,world!"); } { std::stringstream ss; - ss << tag("foo", "hello, world!"); + ss << tag("foo", ccs("hello, world!")); REQUIRE(ss.str() == ":foo \"hello, world!\""); } @@ -43,7 +45,7 @@ namespace ut { { std::stringstream ss; - ss << tag("foo", "hello") << xtag("bar", "there"); + ss << tag("foo", ccs("hello")) << xtag("bar", ccs("there")); REQUIRE(ss.str() == ":foo hello :bar there"); } @@ -52,7 +54,7 @@ namespace ut { { std::stringstream ss; - ss << tag("foo", "hello,world!"); + ss << tag("foo", ccs("hello,world!")); /* color on color off * <---------> <-----> From 96cca5e383b04b677d82fbe41fcfbcc0fbc81e46 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 1 May 2024 23:29:24 -0400 Subject: [PATCH 161/170] xo-indentlog: github: simplify ubuntu build --- .github/workflows/cmake-single-platform.yml | 80 +++++++++++++++------ 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/.github/workflows/cmake-single-platform.yml b/.github/workflows/cmake-single-platform.yml index 9c268e74..a80d88cb 100644 --- a/.github/workflows/cmake-single-platform.yml +++ b/.github/workflows/cmake-single-platform.yml @@ -20,11 +20,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: checkout source + uses: actions/checkout@v3 - - name: Install catch2 + - name: Install dependencies # install catch2. see [[https://stackoverflow.com/questions/57982945/how-to-apt-get-install-in-a-github-actions-workflow]] - run: sudo apt-get install -y catch2 + run: | + echo "::group::install catch2" + sudo apt-get install -y catch2 + echo "::endgroup" # ---------------------------------------------------------------- @@ -34,27 +38,61 @@ jobs: repository: Rconybea/xo-cmake path: repo/xo-cmake - - name: Configure xo-cmake - run: cmake -B ${{github.workspace}}/build_xo-cmake -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local repo/xo-cmake + - name: build xo-cmake + run: | + XONAME=xo-cmake + XOSRC=repo/${XONAME} + BUILDDIR=${{github.workspace}}/build_${XONAME} + PREFIX=${{github.workspace}}/local - - name: Build xo-cmake (trivial) - run: cmake --build ${{github.workspace}}/build_xo-cmake --config ${{env.BUILD_TYPE}} + echo "::group::configure ${XONAME}" + cmake -B ${BUILDDIR} -DCMAKE_INSTALL_PREFIX=${PREFIX} ${XOSRC} + echo "::endgroup" - - name: Install xo-cmake - run: cmake --install ${{github.workspace}}/build_xo-cmake + echo "::group::compile ${XONAME}" + cmake --build ${BUILDDIR} --config ${{env.BUILD_TYPE}} + echo "::endgroup" + + echo "::group::local install ${XONAME}" + cmake --install ${BUILDDIR} + echo "::endgroup" + + echo "::group::local dir tree" + tree ${PREFIX} + echo "::endgroup" # ---------------------------------------------------------------- - - name: Configure self (indentlog) - # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. - # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_MODULE_PATH=${{github.workspace}}/local/share/cmake -DCMAKE_PREFIX_PATH=${{github.workspace}}/local -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - - name: Build self (indentlog) - # Build your program with the given configuration - run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: build self (indentlog) + run: | + XONAME=xo-indentlog + BUILDDIR=${{github.workspace}}/build_${XONAME} + PREFIX=${{github.workspace}}/local - - name: Test self (indentlog) - working-directory: ${{github.workspace}}/build - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest -C ${{env.BUILD_TYPE}} --rerun-failed --output-on-failure + echo "::group::repo dir tree" + tree -L 2 repo + echo "::endgroup" + + echo "::group::configure ${XONAME}" + cmake -B ${BUILDDIR} -DCMAKE_MODULE_PATH=${PREFIX}/share/cmake -DCMAKE_PREFIX_PATH=${PREFIX} -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + echo "::endgroup" + + echo "::group::compile ${XONAME}" + cmake --build ${BUILDDIR} --config ${{env.BUILD_TYPE}} + echo "::endgroup" + + echo "::group::run unit tests ${XONAME}" + cmake --build ${BUILDDIR} -- test + echo "::endgroup" + + echo "::group::local install ${XONAME}" + cmake --install ${BUILDDIR} + echo "::endgroup" + + echo "::group::local dir tree" + tree -L 3 ${PREFIX} + echo "::endgroup" + + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + (cd ${BUILDDIR} && ctest -C ${{env.BUILD_TYPE}}) From 89fd44467f075033ee6da68e54a05a3be13491e9 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 1 May 2024 23:36:03 -0400 Subject: [PATCH 162/170] xo-indentlog: tidy: quoted_impl -> quot_impl --- include/xo/indentlog/log_streambuf.hpp | 2 +- include/xo/indentlog/print/quoted.hpp | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/xo/indentlog/log_streambuf.hpp b/include/xo/indentlog/log_streambuf.hpp index 0c4b3aae..1a761655 100644 --- a/include/xo/indentlog/log_streambuf.hpp +++ b/include/xo/indentlog/log_streambuf.hpp @@ -48,7 +48,7 @@ namespace xo { << ", buf_v.size=" << this->buf_v_.size() << std::endl; #endif - //std::cout << "xsputn: s=" << quoted(string_view(s, n)) << ", n=" << n << std::endl; + //std::cout << "xsputn: s=" << quot(string_view(s, n)) << ", n=" << n << std::endl; if (this->pptr() + n > this->hi()) { n = this->hi() - this->pptr(); diff --git a/include/xo/indentlog/print/quoted.hpp b/include/xo/indentlog/print/quoted.hpp index 154f7702..08919f5a 100644 --- a/include/xo/indentlog/print/quoted.hpp +++ b/include/xo/indentlog/print/quoted.hpp @@ -21,16 +21,16 @@ namespace xo { /* Printing cases: * 1. T&&: - * move into quoted_impl. T must be moveable! + * move into quot_impl. T must be moveable! * 2. T&: - * copy reference into quoted_impl. - * similarly for T const &, copy reference into quoted_impl + * copy reference into quot_impl. + * similarly for T const &, copy reference into quot_impl */ template - class quoted_impl { + class quot_impl { public: - quoted_impl(bool unq_flag, T x) : unq_flag_{unq_flag}, value_{std::move(x)} {} + quot_impl(bool unq_flag, T x) : unq_flag_{unq_flag}, value_{std::move(x)} {} bool unq_flag() const { return unq_flag_; } T const & value() const { return value_; } @@ -110,11 +110,11 @@ namespace xo { bool unq_flag_ = false; /* .value: value to be printed */ T value_; - }; /*quoted_impl*/ + }; /*quot_impl*/ template std::ostream & - operator<<(std::ostream & os, quoted_impl const & x) { + operator<<(std::ostream & os, quot_impl const & x) { x.print(os); return os; } /*operator*/ @@ -124,19 +124,19 @@ namespace xo { * 1. call quoted(x) with rvalue std::string x, then: * - T will be deduced to [std::string] * (in particular: _not_ std::string &, std::string const &, std::string &&) - * - rvalue std::string passed to quoted_impl ctor + * - rvalue std::string passed to quot_impl ctor * * 2a. call quoted(x) with std::string & x, then: * - T deduced to [std::string &] - * - std::string & passed to quoted_impl ctor + * - std::string & passed to quot_impl ctor * * 2b. call quoted(x) with std::string const & x, then: * - T deduced to [std::string const &] - * - std::string const & passed to quoted_impl ctor + * - std::string const & passed to quot_impl ctor */ template auto quot(T && x) { - return quoted_impl(false /*unq_flag*/, std::forward(x)); + return quot_impl(false /*unq_flag*/, std::forward(x)); } inline auto qcstr(char const * x) { @@ -145,7 +145,7 @@ namespace xo { template auto unq(T && x) { - return quoted_impl(true /*unq_flag*/, std::forward(x)); + return quot_impl(true /*unq_flag*/, std::forward(x)); } } /*namespace print*/ } /*namespace xo*/ From 25039f88e8b05b9ae3cbd7f7ebf54786ad42f09a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 30 May 2024 16:35:01 -0400 Subject: [PATCH 163/170] xo-indentlog: streamline build for examples --- .gitignore | 2 ++ CMakeLists.txt | 35 ++++++++++++++++++++--------------- example/ex1/CMakeLists.txt | 6 ++++-- example/ex2/CMakeLists.txt | 6 ++++-- example/ex3/CMakeLists.txt | 6 ++++-- example/ex4/CMakeLists.txt | 6 ++++-- example/hello/CMakeLists.txt | 6 ++++-- 7 files changed, 42 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 7ebf47c3..d809ed06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +# emacs projectile config +.projectile # symlink to ${my_build_directory}/compile_commands.json to make LSP work compile_commands.json # lsp keeps state here diff --git a/CMakeLists.txt b/CMakeLists.txt index 46f3bdbb..2a7ff773 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,19 +7,15 @@ project(indentlog VERSION 1.0) include(GNUInstallDirs) include(cmake/xo-bootstrap-macros.cmake) -xo_cxx_toplevel_options2() +xo_cxx_toplevel_options3() # ---------------------------------------------------------------- -# cmake -DCMAKE_BUILD_TYPE=debug -xo_toplevel_debug_config2() +# c++ settings -# ---------------------------------------------------------------- -# cmake -DCMAKE_BUILD_TYPE=asan -xo_toplevel_asan_config2() - -# ---------------------------------------------------------------- -# cmake -DCMAKE_BUILD_TYPE=coverage -xo_toplevel_coverage_config2() +# one-time project-specific c++ flags. usually empty +#set(PROJECT_CXX_FLAGS "-Wstringop-overread") +#set(PROJECT_CXX_FLAGS "-fconcepts-diagnostics-depth=2") +add_definitions(${PROJECT_CXX_FLAGS}) # ---------------------------------------------------------------- @@ -35,9 +31,18 @@ xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets) xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) # ---------------------------------------------------------------- +# docs targets depend on all the other library/utest targets +# +#add_subdirectory(docs) -install(TARGETS hello DESTINATION bin/indentlog/example) -install(TARGETS indentlog_ex1 DESTINATION bin/indentlog/example) -install(TARGETS indentlog_ex2 DESTINATION bin/indentlog/example) -install(TARGETS indentlog_ex3 DESTINATION bin/indentlog/example) -install(TARGETS indentlog_ex4 DESTINATION bin/indentlog/example) +# ---------------------------------------------------------------- + +if (XO_ENABLE_EXAMPLES) + install(TARGETS hello DESTINATION bin/indentlog/example) + install(TARGETS indentlog_ex1 DESTINATION bin/indentlog/example) + install(TARGETS indentlog_ex2 DESTINATION bin/indentlog/example) + install(TARGETS indentlog_ex3 DESTINATION bin/indentlog/example) + install(TARGETS indentlog_ex4 DESTINATION bin/indentlog/example) +endif() + +# end CMakeLists.txt diff --git a/example/ex1/CMakeLists.txt b/example/ex1/CMakeLists.txt index f42c56de..69f49e17 100644 --- a/example/ex1/CMakeLists.txt +++ b/example/ex1/CMakeLists.txt @@ -1,2 +1,4 @@ -add_executable(indentlog_ex1 ex1.cpp) -xo_include_options2(indentlog_ex1) +if (XO_ENABLE_EXAMPLES) + add_executable(indentlog_ex1 ex1.cpp) + xo_include_options2(indentlog_ex1) +endif() diff --git a/example/ex2/CMakeLists.txt b/example/ex2/CMakeLists.txt index 2dc39192..4b7f82de 100644 --- a/example/ex2/CMakeLists.txt +++ b/example/ex2/CMakeLists.txt @@ -1,4 +1,6 @@ # NOTE: need target names to be globally unique within the xo umbrella -add_executable(indentlog_ex2 ex2.cpp) -xo_include_options2(indentlog_ex2) +if (XO_ENABLE_EXAMPLES) + add_executable(indentlog_ex2 ex2.cpp) + xo_include_options2(indentlog_ex2) +endif() diff --git a/example/ex3/CMakeLists.txt b/example/ex3/CMakeLists.txt index bb5110ce..a15b03be 100644 --- a/example/ex3/CMakeLists.txt +++ b/example/ex3/CMakeLists.txt @@ -1,2 +1,4 @@ -add_executable(indentlog_ex3 ex3.cpp) -xo_include_options2(indentlog_ex3) +if (XO_ENABLE_EXAMPLES) + add_executable(indentlog_ex3 ex3.cpp) + xo_include_options2(indentlog_ex3) +endif() diff --git a/example/ex4/CMakeLists.txt b/example/ex4/CMakeLists.txt index 6ff720f7..9daba558 100644 --- a/example/ex4/CMakeLists.txt +++ b/example/ex4/CMakeLists.txt @@ -1,2 +1,4 @@ -add_executable(indentlog_ex4 ex4.cpp) -xo_include_options2(indentlog_ex4) +if (XO_ENABLE_EXAMPLES) + add_executable(indentlog_ex4 ex4.cpp) + xo_include_options2(indentlog_ex4) +endif() diff --git a/example/hello/CMakeLists.txt b/example/hello/CMakeLists.txt index 1ff23000..14806f7e 100644 --- a/example/hello/CMakeLists.txt +++ b/example/hello/CMakeLists.txt @@ -1,2 +1,4 @@ -add_executable(hello hello.cpp) -xo_include_options2(hello) +if (XO_ENABLE_EXAMPLES) + add_executable(hello hello.cpp) + xo_include_options2(hello) +endif() From db87d4f40da2b36b39140d6b888e8fddb44f56bf Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 15:14:35 -0400 Subject: [PATCH 164/170] indentlog: tweak fake mm_setcsr() in machdep.hpp --- include/xo/indentlog/machdep/machdep.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/xo/indentlog/machdep/machdep.hpp b/include/xo/indentlog/machdep/machdep.hpp index 11c2f3e9..df03099c 100644 --- a/include/xo/indentlog/machdep/machdep.hpp +++ b/include/xo/indentlog/machdep/machdep.hpp @@ -14,12 +14,15 @@ extern "C" { /* never defined! must not ever generate code that relies on these */ + unsigned int fake_rdtsc(); unsigned int fake_mm_getcsr(); - unsigned int fake_mm_setcsr(unsigned int a); + unsigned int fake_mm_setcsr(); } +/* __rdtsc: clang encounters this from , for example */ +#define __rdtsc() fake_rdtsc() #define _mm_getcsr(a) fake_mm_getcsr() -#define _mm_setcsr(a) fake_mm_setcsr(a) +#define _mm_setcsr(a) fake_mm_setcsr() #endif From 8f5a7dd59c49e6a24a555bbf4e35ad16584c8a47 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 15:14:56 -0400 Subject: [PATCH 165/170] xo-indentlog: docs: upgrade README to mention xo-build --- README.md | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 18c7c984..a79ff1a6 100644 --- a/README.md +++ b/README.md @@ -21,26 +21,36 @@ Indentlog is a lightweight header-only library for console logging. ### build + install `xo-cmake` dependency (cmake macros) see [github/Rconybea/xo-cmake](https://github.com/Rconybea/xo-cmake) -(almost trivial, installs a few `.cmake` files) + +Installs a few cmake ingredients, along with a build assistant for XO projects such as this one. ### copy repository locally +Using `xo-build` (provided by `xo-cmake`): ``` -$ git clone git@github.com:rconybea/indentlog.git -$ ls -d indentlog -indentlog +$ xo-build --clone xo-indentlog +``` + +or equivalently: +``` +$ cd ~/proj +$ git clone git@github.com:Rconybea/indentlog.git xo-indentlog ``` ### build & install +Using `xo-build`: ``` -$ cd indentlog -$ mkdir build -$ cd build +$ xo-build --configure --build --install xo-indentlog +``` + +or equivalently: +``` +$ mkdir xo-indentlog/.build $ PREFIX=/usr/local # for example -$ cmake -DCMAKE_MODULE_PATH=${PREFIX}/share/cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} .. -$ make -$ make install +$ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} -S xo-indentlog -B xo-indentlog/.build +$ cmake --build xo-indentlog/.build +$ cmake --install xo-indentlog/.build ``` For some more detail see [BUILD.md](BUILD.md) From 18feb2bfe7b0d0d49330ec46bf2db3d2a73662d4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 21 Jul 2024 13:52:48 +1000 Subject: [PATCH 166/170] xo-indentlog: account for more-concise clang output when printing fn --- include/xo/indentlog/print/function.hpp | 27 +++++++++++++++---------- utest/function.test.cpp | 1 + 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/include/xo/indentlog/print/function.hpp b/include/xo/indentlog/print/function.hpp index 3c0f97a6..095df5c7 100644 --- a/include/xo/indentlog/print/function.hpp +++ b/include/xo/indentlog/print/function.hpp @@ -7,20 +7,20 @@ namespace xo { enum class function_style : std::uint8_t { - /* literal: print supplied text, no alterations */ + /** literal: print supplied text, no alterations **/ literal, - /* pretty: print name, surrounded by [] + /** pretty: print name, surrounded by [] * [double Quadratic::operator()(double) const] - */ + **/ pretty, - /* streamlined: remove extraneous detail, - * try to print something like class::method - * Quadratic::operator() - */ + /** streamlined: remove extraneous detail, + * try to print something like class::method + * Quadratic::operator() + **/ streamlined, - /* simple: remove everything except function/method name - * operator() - */ + /** simple: remove everything except function/method name + * operator() + **/ simple }; @@ -99,7 +99,7 @@ namespace xo { //std::cerr << "print_streamlined: s=[" << s << "]" << std::endl; //std::cerr << "print_streamlined: s2=[" << s2 << "] (excluded [with ..] suffix)" << std::endl; - //std::cerr << "print_streamlined: s3=[" << s3 << "], p=" << p << " (excluded const suffix)" << std::endl; + //std::cerr << "print_streamlined: s3=[" << s3 << "] (excluded const suffix)" << std::endl; //std::cerr << "print_streamlined: s4=[" << s4 << "], q=" << q << " (excluded return type)" << std::endl; //std::cerr << "print_streamlined: s5=[" << s5 << "], r=" << r << " (excluded ns qualifier)" << std::endl; @@ -143,7 +143,12 @@ namespace xo { * - left-to-right * - exclude ' [with '... to end of string */ +#if __clang__ + /* clang footnote like [CharT = char] instead of [with CharT = char] */ + std::size_t p = s.find(" ["); +#else std::size_t p = s.find(" [with "); +#endif return s.substr(0, p); } /*exclude_template_footnote_suffix*/ diff --git a/utest/function.test.cpp b/utest/function.test.cpp index 42d3c9b6..84b49515 100644 --- a/utest/function.test.cpp +++ b/utest/function.test.cpp @@ -38,6 +38,7 @@ namespace ut { function_tcase(function_style::pretty, color_spec_type::blue(), "void xo::class::foo() const", "[\033[31;34mvoid xo::class::foo() const\033[0m]"), function_tcase(function_style::streamlined, color_spec_type::none(), "void xo::reactor::FifoQueue::notify_ev(const T&) [with T = std::pair > >, long unsigned int>; EvTimeFn = xo::reactor::EventTimeFn > >, long unsigned int> >]", "FifoQueue::notify_ev"), + function_tcase(function_style::streamlined, color_spec_type::none(), "token_type xo::tok::tokenizer::assemble_token(const span_type &) const [CharT = char]", "tokenizer::assemble_token"), }); TEST_CASE("function", "[function]") { From 0fef9b03e32882f1ee2b2ed5fadca7eec3b2ac51 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 5 Aug 2024 14:26:09 -0400 Subject: [PATCH 167/170] xo-indentlog: fix: print_with_escapes() static to appease osx build --- include/xo/indentlog/print/quoted.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xo/indentlog/print/quoted.hpp b/include/xo/indentlog/print/quoted.hpp index 08919f5a..16e66267 100644 --- a/include/xo/indentlog/print/quoted.hpp +++ b/include/xo/indentlog/print/quoted.hpp @@ -35,8 +35,8 @@ namespace xo { bool unq_flag() const { return unq_flag_; } T const & value() const { return value_; } - void print_with_escapes(const std::string & xs, - std::ostream & os) const + static void print_with_escapes(const std::string & xs, + std::ostream & os) { /* printed value contains a space * and/or a must-be-escaped character. @@ -97,7 +97,7 @@ namespace xo { else os << "\"" << xs << "\""; } else { - this->print_with_escapes(xs, os); + print_with_escapes(xs, os); } } /*print*/ From bdfe08a51478114908fd9f085c73ab0c44de2656 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Sep 2024 19:55:35 -0500 Subject: [PATCH 168/170] xo-indentlog: bugfix: increase buf size to exclude possible overrun --- include/xo/indentlog/timeutil/timeutil.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xo/indentlog/timeutil/timeutil.hpp b/include/xo/indentlog/timeutil/timeutil.hpp index f1b2a938..1a2a0240 100644 --- a/include/xo/indentlog/timeutil/timeutil.hpp +++ b/include/xo/indentlog/timeutil/timeutil.hpp @@ -259,7 +259,7 @@ namespace xo { auto [t0_tm, t0_usec] = utc_split_tm(t0); /* no std::format in clang11 afaict */ - char usec_buf[8]; + char usec_buf[15]; snprintf(usec_buf, sizeof(usec_buf), "%06d", t0_usec); From dfccfc56c1c676c70e95aa6ae8cc10412899b974 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 13 Sep 2024 22:40:54 -0500 Subject: [PATCH 169/170] xo-indentlog: handle gcc 13.3 --- include/xo/indentlog/print/function.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/xo/indentlog/print/function.hpp b/include/xo/indentlog/print/function.hpp index 095df5c7..9a6e56ee 100644 --- a/include/xo/indentlog/print/function.hpp +++ b/include/xo/indentlog/print/function.hpp @@ -147,7 +147,12 @@ namespace xo { /* clang footnote like [CharT = char] instead of [with CharT = char] */ std::size_t p = s.find(" ["); #else +# if (__GNUC__ > 13) || ((__GNUC__ == 13) && (__GNUC_MINOR__ >= 3)) + /* gcc footnote like [CharT = char] instead of [with CharT = char] starting w/ gcc 13.3 (approximately ?)*/ + std::size_t p = s.find(" ["); +# else std::size_t p = s.find(" [with "); +# endif #endif return s.substr(0, p); From 2241afd6f917bb3fa52bacfc570702e48288063d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 2 May 2025 18:25:12 -0500 Subject: [PATCH 170/170] bugfix: indentlog: recover clang16 build --- utest/quoted.test.cpp | 78 ++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/utest/quoted.test.cpp b/utest/quoted.test.cpp index 8552bdbe..0b00ba9a 100644 --- a/utest/quoted.test.cpp +++ b/utest/quoted.test.cpp @@ -52,19 +52,25 @@ namespace ut { ss << '\\'; - log && log("after: lone escaped backslash"); - log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + std::string str = ss.str(); - REQUIRE(ss.view() == std::string_view("\\")); + log && log("after: lone escaped backslash"); + log && log(hex_view(str.data(), str.data() + str.size(), true)); + + //REQUIRE(ss.view() == std::string_view("\\")); // n/avail on osx + REQUIRE(str == std::string("\\")); ss << 'n'; + std::string str2 = ss.str(); + log && log("after: lone 'n' char"); - log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + log && log(hex_view(str2.data(), str2.data() + str2.size(), true)); - REQUIRE(ss.view() == std::string_view("\\n")); + // REQUIRE(ss.view() == std::string_view("\\n")); // n/avail on osx + REQUIRE(str2 == std::string("\\n")); - log && log("ss.str()=[", ss.str(), "]"); + log && log("ss.str()=[", str2, "]"); } } /*TEST_CASE(sstream.1char)*/ @@ -81,10 +87,12 @@ namespace ut { ss << "\\\\"; - log && log("after: 2x escaped backslash"); - log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + std::string str = ss.str(); - REQUIRE(ss.view() == std::string_view("\\\\")); + log && log("after: 2x escaped backslash"); + log && log(hex_view(str.data(), str.data() + str.size(), true)); + + REQUIRE(str == std::string("\\\\")); log && log("ss.str()=[", ss.str(), "]"); } @@ -103,8 +111,10 @@ namespace ut { ss << "\\n"; + std::string str = ss.str(); + log && log("after: '\\n' escaped backslash + n"); - log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + log && log(hex_view(str.data(), str.data() + str.size(), true)); } } @@ -123,10 +133,12 @@ namespace ut { ss << "\\\\"; ss << 'n'; - log && log("after: '\\\\n' 2x escaped backslash + n"); - log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + std::string str = ss.str(); - REQUIRE(ss.view() == std::string_view("\\\\n")); + log && log("after: '\\\\n' 2x escaped backslash + n"); + log && log(hex_view(str.data(), str.data() + str.size(), true)); + + REQUIRE(str == std::string("\\\\n")); } } @@ -140,7 +152,9 @@ namespace ut { std::stringstream ss2; ss2 << quot("\\"); - REQUIRE(ss2.view() == std::string_view("\"\\\\\"")); /* ["\\"] */ + std::string str = ss2.str(); + + REQUIRE(str == std::string("\"\\\\\"")); /* ["\\"] */ } TEST_CASE("sstream.quot.newline", "[quot]") { @@ -153,7 +167,9 @@ namespace ut { std::stringstream ss2; ss2 << quot("\n"); - REQUIRE(ss2.view() == std::string_view("\"\\n\"")); /* ["\n"] */ + std::string str = ss2.str(); + + REQUIRE(str == std::string("\"\\n\"")); /* ["\n"] */ } TEST_CASE("sstream.quot.2bslash", "[quot]") { @@ -166,7 +182,9 @@ namespace ut { std::stringstream ss2; ss2 << quot("\\\\"); /* quoting string with two backslashes need to give ["\\\\"] */ - REQUIRE(ss2.view() == std::string_view("\"\\\\\\\\\"")); /* rhs is ["\\\\"] */ + std::string str = ss2.str(); + + REQUIRE(str == std::string("\"\\\\\\\\\"")); /* rhs is ["\\\\"] */ } TEST_CASE("sstream.quot.2charnewline", "[quot]") { @@ -179,7 +197,9 @@ namespace ut { std::stringstream ss2; ss2 << quot("x\n"); - REQUIRE(ss2.view() == std::string_view("\"x\\n\"")); /* ["\n"] */ + std::string str = ss2.str(); + + REQUIRE(str == std::string("\"x\\n\"")); /* ["\n"] */ } TEST_CASE("sstream.quot.2char", "[quot]") { @@ -192,11 +212,13 @@ namespace ut { std::stringstream ss2; ss2 << quot("\\n"); + std::string str = ss2.str(); + //std::cerr << quoted_debug::s_log_last_quoted.view() << std::endl; //log && log("debug_log=[", quoted_debug::s_log_last_quoted.view() , "]"); - REQUIRE(ss2.view() == std::string_view("\"\\\\n\"")); + REQUIRE(str == std::string("\"\\\\n\"")); } TEST_CASE("sstream.quot.foonewline", "[quot]") { @@ -207,7 +229,9 @@ namespace ut { std::stringstream ss2; ss2 << quot("foo\n"); - REQUIRE(ss2.view() == std::string_view("\"foo\\n\"")); /* ["\n"] */ + std::string str = ss2.str(); + + REQUIRE(str == std::string("\"foo\\n\"")); /* ["\n"] */ } TEST_CASE("sstream.rest", "[quot]") { @@ -223,8 +247,10 @@ namespace ut { ss << quot("\n"); + std::string str = ss.str(); + log && log("after: quot('\\n')"); - log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + log && log(hex_view(str.data(), str.data() + str.size(), true)); } /* testing unexpected sstream behavior */ @@ -235,8 +261,10 @@ namespace ut { ss << quot("foo\n"); + std::string str = ss.str(); + log && log("after: quot(\"foo\n\")"); - log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + log && log(hex_view(str.data(), str.data() + str.size(), true)); log && log("> ss.str ----------------"); log && log(ss.str()); log && log("< ss.str ----------------"); @@ -250,8 +278,10 @@ namespace ut { ss << unq("\n"); + std::string str = ss.str(); + log && log("after: unq('\\n')"); - log && log(hex_view(ss.view().begin(), ss.view().end(), true)); + log && log(hex_view(str.data(), str.data() + str.size(), true)); } } /*TEST_CASE(sstream)*/ @@ -303,11 +333,13 @@ namespace ut { else ss << quot(tc.x_); + std::string str = ss.str(); + INFO("tc.s ----------------"); INFO(tostr("[", tc.s_, "]")); INFO("tc.s ----------------"); INFO("ss.str ----------------"); - INFO(tostr("[", hex_view(ss.view().begin(), ss.view().end(), true), "]")); + INFO(tostr("[", hex_view(str.data(), str.data() + str.size(), true), "]")); INFO(tostr("[", ss.str(), "]")); INFO("ss.str ----------------");