initial commit
This commit is contained in:
commit
2719942c9e
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.cache/
|
||||||
|
target/
|
||||||
|
compile_commands.json
|
14
Alloy.toml
Normal file
14
Alloy.toml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "journal"
|
||||||
|
authors = []
|
||||||
|
standard = "c++20"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "libjournal"
|
||||||
|
cc-flags = ["-DJOURNAL_ALL"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "journal"
|
||||||
|
cc-flags = ["-DJOURNAL_ALL", "-gcodeview", "-g"]
|
||||||
|
ld-flags = ["-g", "-gcodeview"]
|
93
include/journal.hpp
Normal file
93
include/journal.hpp
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace journal {
|
||||||
|
|
||||||
|
namespace __detail {
|
||||||
|
|
||||||
|
enum LogVerbosity {
|
||||||
|
Trace,
|
||||||
|
Debug,
|
||||||
|
Info,
|
||||||
|
Warn,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr auto to_string(const LogVerbosity& verbosity) -> std::string;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto log(const LogVerbosity &verbosity, std::string_view fmt,
|
||||||
|
Args... args) -> void {
|
||||||
|
const auto msg = std::vformat(fmt, std::make_format_args( args...));
|
||||||
|
log_internal(verbosity, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto log_internal(const LogVerbosity &verbosity,
|
||||||
|
const std::string &msg) -> void;
|
||||||
|
} // namespace __detail
|
||||||
|
|
||||||
|
using __detail::LogVerbosity;
|
||||||
|
|
||||||
|
auto init_stdout(const LogVerbosity& min = LogVerbosity::Info) -> void;
|
||||||
|
|
||||||
|
#ifdef JOURNAL_ALL
|
||||||
|
#define JOURNAL_TRACE
|
||||||
|
#define JOURNAL_DEBUG
|
||||||
|
#define JOURNAL_INFO
|
||||||
|
#define JOURNAL_WARN
|
||||||
|
#define JOURNAL_ERROR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOURNAL_TRACE
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto trace(std::string_view fmt, Args... args) -> void {
|
||||||
|
__detail::log(__detail::LogVerbosity::Trace, fmt, args...);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto trace(std::string_view fmt, Args... args) -> void {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOURNAL_DEBUG
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto debug(std::string_view fmt, Args... args) -> void {
|
||||||
|
__detail::log(__detail::LogVerbosity::Debug, fmt, args...);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto debug(std::string_view fmt, Args... args) -> void {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOURNAL_INFO
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto info(std::string_view fmt, Args... args) -> void {
|
||||||
|
__detail::log(__detail::LogVerbosity::Info, fmt, args...);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto info(std::string_view fmt, Args... args) -> void {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOURNAL_WARN
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto warn(std::string_view fmt, Args... args) -> void {
|
||||||
|
__detail::log(__detail::LogVerbosity::Warn, fmt, args...);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto warn(std::string_view fmt, Args... args) -> void {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JOURNAL_ERROR
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto error(std::string_view fmt, Args... args) -> void {
|
||||||
|
__detail::log(__detail::LogVerbosity::Error, fmt, args...);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template <typename... Args>
|
||||||
|
inline constexpr auto error(std::string_view fmt, Args... args) -> void {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace journal
|
157
src/journal.cc
Normal file
157
src/journal.cc
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
#include "journal.hpp"
|
||||||
|
|
||||||
|
#include <compare>
|
||||||
|
#include <concepts>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <string_view>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace journal {
|
||||||
|
namespace mutex {
|
||||||
|
class Lock {
|
||||||
|
std::mutex &mutex;
|
||||||
|
bool moved = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Lock(Lock &rhs) = delete;
|
||||||
|
Lock(std::mutex &mutex) : mutex(mutex) { mutex.lock();
|
||||||
|
};
|
||||||
|
Lock(Lock &&rhs) : mutex(rhs.mutex) { rhs.moved = true;
|
||||||
|
};
|
||||||
|
auto operator=(Lock &rhs) = delete;
|
||||||
|
~Lock() {
|
||||||
|
if (!moved) {
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class Mutex {
|
||||||
|
std::mutex mutex;
|
||||||
|
T inner;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename U>
|
||||||
|
Mutex(U &&value) requires(std::assignable_from<U, T>)
|
||||||
|
: inner(std::move(value)) {}
|
||||||
|
Mutex() requires(std::default_initializable<T>) : inner(T{}) {}
|
||||||
|
|
||||||
|
auto ref() -> std::pair<Lock, const T &> {
|
||||||
|
return {std::move(scoped_lock()), inner};
|
||||||
|
}
|
||||||
|
auto mut() -> std::pair<Lock, T &> {
|
||||||
|
return {std::move(scoped_lock()), inner};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator->() -> T& {
|
||||||
|
return inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto scoped_lock() -> Lock { return Lock(mutex); }
|
||||||
|
|
||||||
|
auto unique_lock() -> std::unique_lock<std::mutex> {
|
||||||
|
return std::unique_lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock() -> void { mutex.lock(); }
|
||||||
|
|
||||||
|
auto try_lock() -> bool { return mutex.try_lock(); }
|
||||||
|
|
||||||
|
auto unlock() -> void { mutex.unlock(); }
|
||||||
|
};
|
||||||
|
} // namespace mutex
|
||||||
|
|
||||||
|
namespace __detail {
|
||||||
|
|
||||||
|
constexpr auto to_string(const LogVerbosity& verbosity) -> std::string {
|
||||||
|
switch (verbosity) {
|
||||||
|
case LogVerbosity::Trace:
|
||||||
|
return "Trace";
|
||||||
|
case LogVerbosity::Debug:
|
||||||
|
return "Debug";
|
||||||
|
case LogVerbosity::Info:
|
||||||
|
return "Info";
|
||||||
|
case LogVerbosity::Warn:
|
||||||
|
return "Warn";
|
||||||
|
case LogVerbosity::Error:
|
||||||
|
return "Error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Verbosity {
|
||||||
|
journal::__detail::LogVerbosity inner;
|
||||||
|
|
||||||
|
Verbosity(journal::__detail::LogVerbosity &&value) : inner(value) {}
|
||||||
|
Verbosity(const journal::__detail::LogVerbosity &value) : inner(value) {}
|
||||||
|
|
||||||
|
auto operator<=>(const Verbosity &rhs) -> std::strong_ordering {
|
||||||
|
return static_cast<std::underlying_type_t<decltype(inner)>>(inner) <=>
|
||||||
|
static_cast<std::underlying_type_t<decltype(rhs.inner)>>(rhs.inner);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sink {
|
||||||
|
std::shared_ptr<std::ostream> stream;
|
||||||
|
Verbosity min_verbosity;
|
||||||
|
Verbosity max_verbosity;
|
||||||
|
|
||||||
|
Sink(std::shared_ptr<std::ostream>&& stream)
|
||||||
|
: stream(std::move(stream)), min_verbosity(journal::__detail::LogVerbosity::Trace),
|
||||||
|
max_verbosity(journal::__detail::LogVerbosity::Error) {}
|
||||||
|
Sink(std::shared_ptr<std::ostream>&& stream, const Verbosity &min,
|
||||||
|
const Verbosity &max)
|
||||||
|
: stream(std::move(stream)),min_verbosity(min), max_verbosity(max) {}
|
||||||
|
Sink(std::shared_ptr<std::ostream>&& stream, const Verbosity &min)
|
||||||
|
: stream(std::move(stream)),min_verbosity(min), max_verbosity(journal::__detail::Error) {}
|
||||||
|
|
||||||
|
auto operator<<(std::string_view msg) { (*stream) << msg; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Journal {
|
||||||
|
std::vector<Sink> sinks;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Journal() {}
|
||||||
|
auto log(const Verbosity &verbosity, std::string_view msg) {
|
||||||
|
for (auto &&sink : sinks) {
|
||||||
|
if (verbosity >= sink.min_verbosity && verbosity <= sink.max_verbosity) {
|
||||||
|
sink << std::format("[{: <5}] {}\n", to_string(verbosity.inner), msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
add_std_out(const Verbosity &min = journal::__detail::LogVerbosity::Info) {
|
||||||
|
auto out = std::shared_ptr<std::ostream>(&std::cout, [](auto&& _) {});
|
||||||
|
sinks.emplace_back(std::move(out));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static mutex::Mutex<std::unique_ptr<Journal>> global_journal;
|
||||||
|
|
||||||
|
auto log_internal(const LogVerbosity &verbosity,
|
||||||
|
const std::string &msg)
|
||||||
|
-> void {
|
||||||
|
auto &&[lock, ref] = global_journal.ref();
|
||||||
|
|
||||||
|
ref->log(verbosity, msg);
|
||||||
|
}
|
||||||
|
} // namespace __detail
|
||||||
|
|
||||||
|
auto init() {
|
||||||
|
auto &&[lock, ref] = __detail::global_journal.mut();
|
||||||
|
if (!ref.get()) {
|
||||||
|
ref = std::make_unique<__detail::Journal>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto init_stdout(const LogVerbosity &min) -> void {
|
||||||
|
init();
|
||||||
|
auto &&[lock, ref] = __detail::global_journal.mut();
|
||||||
|
ref->add_std_out();
|
||||||
|
}
|
||||||
|
} // namespace journal
|
13
src/main.cc
Normal file
13
src/main.cc
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "journal.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
std::cin.get();
|
||||||
|
journal::init_stdout();
|
||||||
|
printf("Hello, Alloy!\n");
|
||||||
|
journal::info("some info!");
|
||||||
|
journal::error("something went wrong!");
|
||||||
|
journal::trace("just some very verbose stuff here");
|
||||||
|
return 1;
|
||||||
|
}
|
Loading…
Reference in a new issue