[ox/std] Add oxTracef
This commit is contained in:
parent
ef6673067b
commit
55a4f2451e
1
deps/ox/src/ox/std/CMakeLists.txt
vendored
1
deps/ox/src/ox/std/CMakeLists.txt
vendored
@ -60,6 +60,7 @@ install(
|
||||
byteswap.hpp
|
||||
defines.hpp
|
||||
error.hpp
|
||||
fmt.hpp
|
||||
hardware.hpp
|
||||
hashmap.hpp
|
||||
heapmgr.hpp
|
||||
|
13
deps/ox/src/ox/std/bstring.hpp
vendored
13
deps/ox/src/ox/std/bstring.hpp
vendored
@ -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);
|
||||
|
6
deps/ox/src/ox/std/byteswap.hpp
vendored
6
deps/ox/src/ox/std/byteswap.hpp
vendored
@ -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
184
deps/ox/src/ox/std/fmt.hpp
vendored
Normal 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},
|
||||
}
|
||||
};
|
||||
}()
|
||||
);
|
||||
|
||||
|
||||
}
|
1
deps/ox/src/ox/std/std.hpp
vendored
1
deps/ox/src/ox/std/std.hpp
vendored
@ -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"
|
||||
|
50
deps/ox/src/ox/std/trace.cpp
vendored
50
deps/ox/src/ox/std/trace.cpp
vendored
@ -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");
|
||||
|
102
deps/ox/src/ox/std/trace.hpp
vendored
102
deps/ox/src/ox/std/trace.hpp
vendored
@ -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__)
|
||||
|
16
deps/ox/src/ox/std/tracehook.cpp
vendored
16
deps/ox/src/ox/std/tracehook.cpp
vendored
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
9
deps/ox/src/ox/std/typetraits.hpp
vendored
9
deps/ox/src/ox/std/typetraits.hpp
vendored
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user