xo-indentlog xo-arena: improve verify_ok logging workflow

+ scope.retroactively_enable()
This commit is contained in:
Roland Conybeare 2026-01-07 17:56:38 -05:00
commit 67552d90bd
3 changed files with 105 additions and 25 deletions

View file

@ -6,12 +6,50 @@
#pragma once
#include "DArenaVector.hpp"
#include <xo/indentlog/scope.hpp>
#include <algorithm>
#include <array>
#include <utility>
#include <cstring>
namespace xo {
struct verify_policy {
static verify_policy log_only() {
return verify_policy{.flags_ = 0x01};
}
static verify_policy throw_only() {
return verify_policy{.flags_ = 0x02};
}
static verify_policy chatty() {
return verify_policy{.flags_ = 0x03};
}
bool is_silent() const noexcept { return flags_ == 0; }
bool log_flag() const noexcept { return flags_ & 0x01; }
bool throw_flag() const noexcept { return flags_ & 0x02; }
template<typename... Tn>
bool report_error(scope & log, Tn&&... args)
{
if (!this->is_silent()) {
// TODO: consider global arena here for string
std::string msg = tostr(std::forward<Tn>(args)...);
if (this->log_flag()) {
log.retroactively_enable();
log(msg);
}
if (this->throw_flag()) {
throw std::runtime_error(msg);
}
}
return false;
}
const char * c_self_ = "anonymous";
uint8_t flags_;
};
namespace mm {
#ifdef NOT_YET
enum class insert_error : int32_t {
@ -169,7 +207,7 @@ namespace xo {
**/
std::pair<value_type *, bool> try_insert(const std::pair<const Key, Value> & kv_pair);
bool verify_ok(bool /*throw_flag_not_implemented*/ = true) const;
bool verify_ok(verify_policy p = verify_policy::throw_only()) const;
private:
/** load group abstraction from control bytes starting at @p ix **/
@ -382,8 +420,23 @@ namespace xo {
**/
template <typename Key, typename Value, typename Hash, typename Equal>
bool
DArenaHashMap<Key, Value, Hash, Equal>::verify_ok(bool /*throw_flag_not_implemented*/) const
DArenaHashMap<Key, Value, Hash, Equal>::verify_ok(verify_policy policy) const
{
using xo::scope;
using xo::tostr;
using xo::xtag;
constexpr const char * c_self = "DArenaHashMap::verify_ok";
scope log(XO_DEBUG(debug_flag_), xtag("size", size_));
/* SM1.1: size_ <= n_slot_ */
if (size_ > n_slot_) {
return policy.report_error(log,
c_self, ": expect .size < .n_slot",
xtag("size", size_),
xtag("n_slot", n_slot_));
}
return true;
}
}

View file

@ -197,7 +197,9 @@ namespace utest {
xo::scope log(XO_DEBUG(catch_flag), xtag("lo", lo), xtag("hi", hi), xtag("k", k));
REQUIRE_ORFAIL(ok_flag, catch_flag, p_map->verify_ok(catch_flag));
auto policy = xo::verify_policy::chatty();
REQUIRE_ORFAIL(ok_flag, catch_flag, p_map->verify_ok(policy));
if ((hi <= lo) || (k == 0))
return true;
@ -223,7 +225,7 @@ namespace utest {
*/
auto insert_result = p_map->try_insert(typename HashMap::value_type(x, 10 * x));
REQUIRE_ORFAIL(ok_flag, catch_flag, p_map->verify_ok(catch_flag));
REQUIRE_ORFAIL(ok_flag, catch_flag, p_map->verify_ok(policy));
REQUIRE_ORFAIL(ok_flag, catch_flag, insert_result.second);

View file

@ -171,10 +171,27 @@ namespace xo {
return true;
} /*log*/
/** re-enable + log (args...).
* No-op if scope already enabled.
* Useful in verify_ok() methods, to conditionally enable
* logging only when a test fails
**/
template<typename... Tn>
void retroactively_enable(Tn&&... args) {
if (finalized_) {
this->finalized_ = false;
this->begin_scope(std::forward<Tn>(args)...);
}
}
/** Log argument in pack @p args **/
template<typename... Tn>
bool operator()(Tn&&... args) { return this->log(std::forward<Tn>(args)...); }
/** If enabled, writes initial banner **/
template<typename... Tn>
void begin_scope(Tn&&... args);
/** Optionally, call once to end scope before dtor.
* Logs arguments in pack @p args
**/
@ -231,27 +248,7 @@ namespace xo {
line_{setup.line_},
finalized_{!(setup.is_enabled())}
{
if(setup.is_enabled()) {
state_impl_type * logstate = basic_scope::require_thread_local_state();
std::ostream & os = logstate2stream(logstate);
logstate->preamble(this->style_, this->name1_, this->name2_);
tosn(os, " ", std::forward<Tn>(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());
///* next call to scope::log() can reset to beginning of buffer space */
//logstate->ss().seekp(0);
logstate->incr_nesting();
}
this->begin_scope(std::forward<Tn>(args)...);
} /*ctor*/
template <typename CharT, typename Traits>
@ -314,6 +311,34 @@ namespace xo {
logstate->flush2sbuf(this->dest_sbuf_);
} /*flush2sbuf*/
template <typename CharT, typename Traits>
template <typename... Tn>
void
basic_scope<CharT, Traits>::begin_scope(Tn&&... args)
{
if(this->enabled()) {
state_impl_type * logstate = basic_scope::require_thread_local_state();
std::ostream & os = logstate2stream(logstate);
logstate->preamble(this->style_, this->name1_, this->name2_);
tosn(os, " ", std::forward<Tn>(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());
///* next call to scope::log() can reset to beginning of buffer space */
//logstate->ss().seekp(0);
logstate->incr_nesting();
}
}
template <typename CharT, typename Traits>
template <typename... Tn>
void