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