Skip to content

Commit

Permalink
Added logger implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
akukh committed Apr 28, 2024
1 parent 8d19887 commit 04a6f7c
Show file tree
Hide file tree
Showing 17 changed files with 620 additions and 18 deletions.
1 change: 1 addition & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ comment:

ignore:
- "**/*-test.cpp" # ignore test harness code
- "**/utility"
- "**/detail"
- "flux-config"
- "flux-meta"
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ if(FLUX_ENABLE_COVERAGE)

message(STATUS "Code coverage: ON")
else()
message(ERROR "Code coverage for compiler ${CMAKE_CXX_COMPILER_ID} is unsupported")
message(FATAL_ERROR "Code coverage is not supported by the ${CMAKE_CXX_COMPILER_ID} compiler.")
endif()
endif()

Expand All @@ -27,6 +27,7 @@ endif()
#-----------------------------------------------------------------------------------------------------------------------

add_subdirectory("flux-config")
add_subdirectory("flux-foundation")
add_subdirectory("flux-io")
add_subdirectory("flux-meta")

Expand Down
8 changes: 8 additions & 0 deletions flux-foundation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
flux_static_library(foundation
COMMON
SOURCE
"flux/foundation/dummy.cpp"
LINK
flux::io)

# code: language="CMake" insertSpaces=true tabSize=4
3 changes: 3 additions & 0 deletions flux-foundation/flux/foundation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

#include <flux/foundation/utility.hpp>
Empty file.
6 changes: 6 additions & 0 deletions flux-foundation/flux/foundation/utility.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include <flux/foundation/utility/addressof.hpp>
#include <flux/foundation/utility/launder.hpp>
#include <flux/foundation/utility/logger.hpp>
#include <flux/foundation/utility/unreachable.hpp>
18 changes: 18 additions & 0 deletions flux-foundation/flux/foundation/utility/addressof.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

namespace flux::fou {

// clang-format off
template <typename T>
#if __has_cpp_attribute(clang::always_inline)
[[clang::always_inline]]
#endif
[[nodiscard]] inline constexpr T* addressof(T& arg) noexcept {
return __builtin_addressof(arg);
}

template <typename T>
T const* addressof(T const&&) = delete;
// clang-format on

} // namespace flux::fou
219 changes: 219 additions & 0 deletions flux-foundation/flux/foundation/utility/detail/logger_impl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
// NOTE:
// This header is such a mess, it will need to be revisited in the future and probably refactored.
// Maybe add multithreading support as well. But at this stage, let it be as it is.
// TODO:
// Revisit it.
#pragma once

#include <flux/foundation/utility/detail/strip_path.hpp>
#include <flux/foundation/utility/source_location.hpp>

#include <cstddef>
#include <string_view>

namespace fast_io {

struct flux_source_location_scatter {
basic_io_scatter_t<char> file_name;
basic_io_scatter_t<char> function_name;
std::uint_least32_t line;
std::uint_least32_t column;
};

namespace details {

inline constexpr std::size_t
print_reserve_size_source_location_impl(flux_source_location_scatter location) noexcept {
constexpr auto reserve_size = print_reserve_size(io_reserve_type<char, std::uint_least32_t>);
constexpr auto total_size = (reserve_size * 2 + 3);
return intrinsics::add_or_overflow_die_chain(location.file_name.len, location.function_name.len,
total_size);
}

inline constexpr char*
print_reserve_define_source_location_impl(char* it,
flux_source_location_scatter location) noexcept {
constexpr auto io_reserve = io_reserve_type<char, std::uint_least32_t>;
*(it = non_overlapped_copy_n(location.file_name.base, location.file_name.len, it)) = ':';
*(it = print_reserve_define(io_reserve, ++it, location.line)) = ':';
*(it = print_reserve_define(io_reserve, ++it, location.column)) = ':';
return non_overlapped_copy_n(location.function_name.base, location.function_name.len, ++it);
}

inline constexpr flux_source_location_scatter
print_alias_define_source_location_impl(flux::fou::source_location location) noexcept {
using flux::fou::detail::strip_path;
return {{strip_path(location.file_name()), cstr_len(strip_path(location.file_name()))},
{location.function_name(), cstr_len(location.function_name())},
location.line(),
location.column()};
}

} // namespace details

inline constexpr std::size_t
print_reserve_size(io_reserve_type_t<char, flux_source_location_scatter>,
flux_source_location_scatter location) noexcept {
return details::print_reserve_size_source_location_impl(location);
}

inline constexpr char* print_reserve_define(io_reserve_type_t<char, flux_source_location_scatter>,
char* iter,
flux_source_location_scatter location) noexcept {
return details::print_reserve_define_source_location_impl(iter, location);
}

inline constexpr flux_source_location_scatter
print_alias_define(io_alias_t, flux::fou::source_location location) noexcept {
return details::print_alias_define_source_location_impl(location);
}

namespace manipulators {
inline constexpr auto
cur_src_loc(flux::fou::source_location location = flux::fou::source_location::current()) noexcept {
return location;
}
} // namespace manipulators
} // namespace fast_io

namespace flux::fou {

struct [[nodiscard]] to_file final {};
struct [[nodiscard]] to_console final {};

struct [[nodiscard]] ansi_color final {
std::uint8_t r = 255;
std::uint8_t g = 255;
std::uint8_t b = 255;
std::uint8_t a = 255; // << Unused, exists only for alignment.

struct [[nodiscard]] escape_code final {
static constexpr std::string_view begin() noexcept {
return "\033[38;2;";
}
static constexpr std::string_view end() noexcept {
return "\033[0;00m";
}
};
};

constexpr auto print_reserve_size(fast_io::io_reserve_type_t<char, ansi_color>) noexcept {
using namespace fast_io;
constexpr auto reserve_size = print_reserve_size(io_reserve_type<char, std::uint8_t>);
constexpr auto total_size = reserve_size * 3;
return total_size;
}

constexpr auto print_reserve_define(fast_io::io_reserve_type_t<char, ansi_color>, char* it,
ansi_color color) noexcept {
using namespace fast_io;
// clang-format off
*(it = print_reserve_define(io_reserve_type<char, std::uint8_t>, it, color.r)) = ';';
*(it = print_reserve_define(io_reserve_type<char, std::uint8_t>, ++it, color.g)) = ';';
*(it = print_reserve_define(io_reserve_type<char, std::uint8_t>, ++it, color.b)) = 'm';
// clang-format on
return ++it;
}
static_assert(fast_io::reserve_printable<char, ansi_color>);

template <typename T, typename... Args>
constexpr void println(ansi_color color, T&& device, Args&&... args) noexcept {
io::println(std::forward<T>(device), ansi_color::escape_code::begin(), color,
std::forward<Args>(args)..., ansi_color::escape_code::end());
}

namespace detail {

// clang-format off
template <typename Output>
struct [[maybe_unused]] dummy_logger;
// clang-format on

} // namespace detail

// clang-format off
template <typename Output>
detail::dummy_logger<Output>& logger() noexcept;
// clang-format on

namespace detail {

inline auto get_local_time() noexcept {
[[maybe_unused]] static bool once = ([] { fast_io::posix_tzset(); }(), true);
return local(fast_io::posix_clock_gettime(fast_io::posix_clock_id::realtime));
}

#define FLUX_PRINT_LOGGER_HEADER_TO(output_file) \
io::println(output_file, left("+", 36, '-'), left("+", 63, '-'), left("+", 13, '-'), \
left("+", 32, '-')); \
io::println(output_file, "| ", left("Date / Time", 33), " | ", left("Location", 60), " | ", \
left("Level", 10), " | Message"); \
io::println(output_file, left("+", 36, '-'), left("+", 63, '-'), left("+", 13, '-'), \
left("+", 32, '-'));

// clang-format off
template <>
struct [[maybe_unused]] dummy_logger<to_file> final {
constexpr dummy_logger(dummy_logger const&) = delete;
constexpr dummy_logger(dummy_logger&&) = delete;
constexpr dummy_logger& operator=(dummy_logger const&) = delete;
constexpr dummy_logger& operator=(dummy_logger&&) = delete;

template <typename... Args>
constexpr void log(ansi_color color, std::string_view prefix, meta::tuple<Args&&...> tuple,
source_location location) noexcept {
using namespace io;
[[maybe_unused]] io_flush_guard guard{output_file_};
meta::apply(
[&](auto&&... args) {
println(color, output_file_, " ", left(get_local_time(), 36),
left(location, 63), left(prefix, 13), std::forward<Args>(args)...);
},
tuple);
}

template <typename Output>
friend dummy_logger<Output>& flux::fou::logger() noexcept;

private:
constexpr dummy_logger() noexcept : output_file_{"log.ansi", io::open_mode::app} {
using namespace io;
FLUX_PRINT_LOGGER_HEADER_TO(output_file_)
}
constexpr ~dummy_logger() = default;

io::obuf_file output_file_;
};

template <>
struct [[maybe_unused]] dummy_logger<to_console> final {
constexpr dummy_logger(dummy_logger const&) = delete;
constexpr dummy_logger(dummy_logger&&) = delete;
constexpr dummy_logger& operator=(dummy_logger const&) = delete;
constexpr dummy_logger& operator=(dummy_logger&&) = delete;

template <typename... Args>
constexpr void log(ansi_color color, std::string_view prefix, meta::tuple<Args&&...> tuple,
source_location location) noexcept {
using namespace io;
meta::apply(
[&](auto&&... args) noexcept {
println(color, out(), left(get_local_time(), 34), location, " ", prefix, " ",
std::forward<Args>(args)...);
},
tuple);
}

template <typename Output>
friend dummy_logger<Output>& flux::fou::logger() noexcept;

private:
constexpr dummy_logger() noexcept = default;
constexpr ~dummy_logger() = default;
};
// clang-format on

#undef FLUX_PRINT_LOGGER_HEADER_TO

} // namespace detail
} // namespace flux::fou
27 changes: 27 additions & 0 deletions flux-foundation/flux/foundation/utility/detail/strip_path.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

namespace flux::fou::detail {

constexpr bool is_path_sep(char c) noexcept {
return c == '/' || c == '\\';
}

constexpr char const* strip_path(char const* path) noexcept {
auto last_name = path;
for (auto p = path; *p; ++p) {
if (is_path_sep(*p) && *(p + 1))
last_name = p + 1;
}
return last_name;
}

constexpr char const* last_dot_of(char const* p) noexcept {
char const* last_dot = nullptr;
for (; *p; ++p) {
if (*p == '.')
last_dot = p;
}
return last_dot ? last_dot : p;
}

} // namespace flux::fou::detail
15 changes: 15 additions & 0 deletions flux-foundation/flux/foundation/utility/launder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

namespace flux::fou {

// clang-format off
template <typename T>
#if __has_cpp_attribute(clang::always_inline)
[[clang::always_inline]]
#endif
[[nodiscard]] inline constexpr T* launder(T* p) noexcept {
return __builtin_launder(p);
}
// clang-format on

} // namespace flux::fou
Loading

0 comments on commit 04a6f7c

Please sign in to comment.