[ox/std] Add oxTracef

This commit is contained in:
Gary Talent 2021-03-10 20:14:31 -06:00
parent ef6673067b
commit 55a4f2451e
9 changed files with 283 additions and 99 deletions

View File

@ -60,6 +60,7 @@ install(
byteswap.hpp
defines.hpp
error.hpp
fmt.hpp
hardware.hpp
hashmap.hpp
heapmgr.hpp

View File

@ -45,6 +45,8 @@ class BString {
constexpr char &operator[](std::size_t i) noexcept;
void append(const char *str, std::size_t sz) noexcept;
constexpr char *data() noexcept;
constexpr const char *c_str() const noexcept;
@ -153,6 +155,17 @@ constexpr char &BString<buffLen>::operator[](std::size_t i) noexcept {
return m_buff[i];
}
template<std::size_t buffLen>
void BString<buffLen>::append(const char *str, std::size_t strLen) noexcept {
auto currentLen = len();
if (cap() < currentLen + strLen + 1) {
strLen = cap() - currentLen;
}
ox_memcpy(m_buff + currentLen, str, strLen);
// make sure last element is a null terminator
m_buff[currentLen + strLen] = 0;
}
template<std::size_t buffLen>
constexpr char *BString<buffLen>::data() noexcept {
return static_cast<char*>(m_buff);

View File

@ -175,12 +175,16 @@ class OX_PACKED ByteSwapInteger {
return newVal;
}
[[nodiscard]] constexpr auto get() const noexcept -> T {
return static_cast<T>(*this);
}
/**
* Returns the integer as it is stored. If it is stored as little endian,
* a little endian integer is returned regardless of the endianness of
* the system.
*/
constexpr auto raw() noexcept -> T {
[[nodiscard]] constexpr auto raw() const noexcept -> T {
return m_value;
}

184
deps/ox/src/ox/std/fmt.hpp vendored Normal file
View File

@ -0,0 +1,184 @@
/*
* Copyright 2015 - 2021 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/strops.hpp>
#include <ox/std/types.hpp>
#include <ox/std/typetraits.hpp>
namespace ox::detail {
class FmtArg {
private:
char dataStr[10] = {};
public:
const char *out = nullptr;
template<typename T>
constexpr FmtArg(T v) noexcept {
if constexpr(is_bool_v<T>) {
out = v ? "true" : "false";
} else if constexpr(is_integral_v<T>) {
out = ox_itoa(v, dataStr);
} else {
out = v;
}
}
};
[[nodiscard]]
constexpr uint64_t argCount(const char *str) noexcept {
uint64_t cnt = 0;
const auto prev = [str](std::size_t i) -> char {
if (i > 0) {
return str[i - 1];
} else {
return '\0';
}
};
const auto next = [str](std::size_t i) -> char {
if (i < ox_strlen(str) - 1) {
return str[i + 1];
} else {
return '\0';
}
};
for (std::size_t i = 0; i < ox_strlen(str); ++i) {
if (str[i] == '{' && prev(i) != '\\' && next(i) == '}') {
++cnt;
}
}
return cnt;
}
static_assert(argCount("{}") == 1);
static_assert(argCount("{}{}") == 2);
static_assert(argCount("thing1: {}, thing2: {}") == 2);
static_assert(argCount("thing1: {}, thing2: {}{}") == 3);
struct FmtSegment {
const char *str = nullptr;
unsigned length = 0;
constexpr bool operator==(const FmtSegment &o) const noexcept {
return length == o.length && ox_strncmp(str, o.str, length) == 0;
}
constexpr bool operator!=(const FmtSegment &o) const noexcept {
return length != o.length || ox_strncmp(str, o.str, length) != 0;
}
};
template<std::size_t sz>
struct Fmt {
static constexpr std::size_t size = sz;
FmtSegment segments[sz];
constexpr bool operator==(const Fmt<sz> &o) const noexcept {
for (std::size_t i = 0; i < sz; ++i) {
if (segments[i] != o.segments[i]) {
return false;
}
}
return true;
}
};
template<std::size_t segementCnt>
[[nodiscard]]
constexpr Fmt<segementCnt> fmtSegments(const char *fmt) noexcept {
Fmt<segementCnt> out;
const auto prev = [fmt](std::size_t i) -> char {
if (i > 0) {
return fmt[i - 1];
} else {
return '\0';
}
};
const auto next = [fmt](std::size_t i) -> char {
if (i < ox_strlen(fmt) - 1) {
return fmt[i + 1];
} else {
return '\0';
}
};
auto current = &out.segments[0];
current->str = fmt;
for (std::size_t i = 0; i < ox_strlen(fmt); ++i) {
if (fmt[i] == '{' && prev(i) != '\\' && next(i) == '}') {
++current;
current->str = fmt + i + 2;
current->length = 0;
i += 1;
} else {
++current->length;
}
}
return out;
}
static_assert([] {
constexpr auto fmt = "{}";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<2>{
{
{"", 0},
{"", 0},
}
};
}()
);
static_assert([] {
constexpr auto fmt = "thing: {}";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<2>{
{
{"thing: ", 7},
{"", 0},
}
};
}()
);
static_assert([] {
constexpr auto fmt = "thing: {}, thing2: {}";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<3>{
{
{"thing: ", 7},
{", thing2: ", 10},
{"", 0},
}
};
}()
);
static_assert([] {
constexpr auto fmt = "thing: {}, thing2: {}s";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<3>{
{
{"thing: ", 7},
{", thing2: ", 10},
{"s", 1},
}
};
}()
);
static_assert([] {
constexpr auto fmt = "loadTexture: section: {}, w: {}, h: {}";
return fmtSegments<argCount(fmt) + 1>(fmt) == Fmt<4>{
{
{"loadTexture: section: ", 22},
{", w: ", 5},
{", h: ", 5},
}
};
}()
);
}

View File

@ -14,6 +14,7 @@
#include "byteswap.hpp"
#include "defines.hpp"
#include "error.hpp"
#include "fmt.hpp"
#include "hardware.hpp"
#include "hashmap.hpp"
#include "heapmgr.hpp"

View File

@ -6,60 +6,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#if defined(OX_USE_STDLIB)
#include <iomanip>
#include <iostream>
#endif
#include "trace.hpp"
extern "C" {
void oxTraceInitHook();
void oxTraceHook(const char *file, int line, const char *ch, const char *msg);
}
namespace ox::trace {
#if defined(OX_USE_STDLIB)
static const auto OxPrintTrace = std::getenv("OXTRACE");
#else
constexpr auto OxPrintTrace = false;
#endif
OutStream::OutStream(const char *file, int line, const char *ch, const char *msg) {
m_msg.file = file;
m_msg.line = line;
m_msg.ch = ch;
m_msg.msg = msg;
}
OutStream::~OutStream() {
oxTraceHook(m_msg.file.c_str(), m_msg.line, m_msg.ch.c_str(), m_msg.msg.c_str());
}
StdOutStream::StdOutStream(const char *file, int line, const char *ch, const char *msg) {
m_msg.file = file;
m_msg.line = line;
m_msg.ch = ch;
m_msg.msg = msg;
}
StdOutStream::~StdOutStream() {
oxTraceHook(m_msg.file.c_str(), m_msg.line, m_msg.ch.c_str(), m_msg.msg.c_str());
#if defined(OX_USE_STDLIB)
if (OxPrintTrace) {
std::cout << std::setw(53) << std::left << m_msg.ch.c_str() << '|';
std::cout << std::setw(65) << std::left << m_msg.msg.c_str() << '|';
std::cout << " " << m_msg.file.c_str() << ':' << m_msg.line << "\n";
}
#endif
}
void logError(const char *file, int line, Error err) {
if (err) {
TraceStream trc(file, line, "ox::error");

View File

@ -8,15 +8,25 @@
#pragma once
#include <ox/std/std.hpp>
#include "bstring.hpp"
#include "fmt.hpp"
#include "hashmap.hpp"
extern "C" {
void oxTraceInitHook();
void oxTraceHook(const char *file, int line, const char *ch, const char *msg);
}
namespace ox::trace {
struct TraceMsg {
ox::BString<255> file = "";
const char *file = "";
int line = 0;
uint64_t time = 0;
ox::BString<75> ch = "";
const char *ch = "";
ox::BString<100> msg;
};
@ -33,26 +43,51 @@ Error model(T *io, ox::trace::TraceMsg *obj) {
class OutStream {
private:
protected:
const char *m_delimiter = " ";
TraceMsg m_msg;
public:
OutStream() = default;
constexpr OutStream(const char *file, int line, const char *ch, const char *msg = "") {
m_msg.file = file;
m_msg.line = line;
m_msg.ch = ch;
m_msg.msg = msg;
}
OutStream(const char *file, int line, const char *ch, const char *msg = "");
template<std::size_t fmtSegmentCnt, typename ...Args>
constexpr OutStream(const char *file, int line, const char *ch, detail::Fmt<fmtSegmentCnt> fmtSegments, Args... args) {
static_assert(sizeof...(args) == fmtSegmentCnt - 1, "Wrong number of trace arguments for format.");
m_msg.file = file;
m_msg.line = line;
m_msg.ch = ch;
const auto &firstSegment = fmtSegments.segments[0];
m_msg.msg.append(firstSegment.str, firstSegment.length);
const detail::FmtArg elements[sizeof...(args)] = {args...};
for (auto i = 0u; i < fmtSegments.size - 1; ++i) {
m_msg.msg += elements[i].out;
const auto &s = fmtSegments.segments[i + 1];
m_msg.msg.append(s.str, s.length);
}
}
~OutStream();
inline ~OutStream() {
oxTraceHook(m_msg.file, m_msg.line, m_msg.ch, m_msg.msg.c_str());
}
template<typename T>
inline OutStream &operator<<(const T &v) {
m_msg.msg += m_delimiter;
constexpr OutStream &operator<<(const T &v) {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
return *this;
}
inline OutStream &operator<<(Error err) {
m_msg.msg += m_delimiter;
constexpr OutStream &operator<<(Error err) {
if (m_msg.msg.len()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += static_cast<int64_t>(err);
return *this;
}
@ -60,38 +95,7 @@ class OutStream {
/**
* del sets the delimiter between log segments.
*/
inline OutStream &del(const char *delimiter) {
m_delimiter = delimiter;
return *this;
}
};
class StdOutStream {
private:
const char *m_delimiter = " ";
TraceMsg m_msg;
public:
StdOutStream() = default;
StdOutStream(const char *file, int line, const char *ch, const char *msg = "");
~StdOutStream();
template<typename T>
constexpr inline StdOutStream &operator<<(const T &v) {
m_msg.msg += m_delimiter;
m_msg.msg += v;
return *this;
}
/**
* del sets the delimiter between log segments.
*/
inline StdOutStream &del(const char *delimiter) {
constexpr OutStream &del(const char *delimiter) {
m_delimiter = delimiter;
return *this;
}
@ -102,19 +106,19 @@ class StdOutStream {
class NullStream {
public:
constexpr NullStream() = default;
constexpr NullStream(const char*, int, const char*, const char* = "") {
}
~NullStream() = default;
template<std::size_t fmtSegmentCnt, typename ...Args>
constexpr NullStream(const char*, int, const char*, detail::Fmt<fmtSegmentCnt>, Args...) {
}
template<typename T>
constexpr inline NullStream &operator<<(const T&) {
constexpr NullStream &operator<<(const T&) {
return *this;
}
inline NullStream &del(const char*) {
constexpr NullStream &del(const char*) {
return *this;
}
@ -135,3 +139,5 @@ void init();
#define oxLogError(err) ox::trace::logError(__FILE__, __LINE__, err)
#define oxTrace(ch) ox::trace::TraceStream(__FILE__, __LINE__, ch)
#define oxTracef(ch, fmt, ...) ox::trace::TraceStream(__FILE__, __LINE__, ch, ox::detail::fmtSegments<ox::detail::argCount(fmt)+1>(fmt), ##__VA_ARGS__)

View File

@ -6,6 +6,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#if defined(OX_USE_STDLIB)
#include <iomanip>
#include <iostream>
static const auto OxPrintTrace = std::getenv("OXTRACE") != nullptr;
#else
constexpr auto OxPrintTrace = false;
#endif
extern "C" {
void oxTraceInitHook() {
@ -13,6 +22,13 @@ void oxTraceInitHook() {
void oxTraceHook([[maybe_unused]] const char *file, [[maybe_unused]] int line,
[[maybe_unused]] const char *ch, [[maybe_unused]] const char *msg) {
#if defined(OX_USE_STDLIB)
if (OxPrintTrace) {
std::cout << std::setw(53) << std::left << ch << "| ";
std::cout << std::setw(65) << std::left << msg << '|';
std::cout << " " << file << ':' << line << "\n";
}
#endif
}
}

View File

@ -63,6 +63,15 @@ template<> struct is_integral<uint32_t>: ox::true_type {};
template<> struct is_integral<int64_t> : ox::true_type {};
template<> struct is_integral<uint64_t>: ox::true_type {};
template<typename T>
constexpr bool is_integral_v = ox::is_integral<T>::value;
template<typename T> struct is_bool: ox::false_type {};
template<> struct is_bool<bool> : ox::true_type {};
template<typename T>
constexpr bool is_bool_v = ox::is_bool<T>::value;
template<typename T> struct is_union: ox::integral_constant<bool, std::is_union_v<T>> {};
template<typename T>