Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions include/log/catalog/arguments.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#pragma once

#include <stdx/type_traits.hpp>

#include <concepts>
#include <cstdint>
#include <type_traits>

template <typename> struct encode_32;
template <typename> struct encode_64;
template <typename> struct encode_u32;
template <typename> struct encode_u64;

namespace logging {
template <typename T>
concept signed_packable = std::signed_integral<stdx::underlying_type_t<T>> and
sizeof(T) <= sizeof(std::int64_t);

template <typename T>
concept unsigned_packable =
std::unsigned_integral<stdx::underlying_type_t<T>> and
sizeof(T) <= sizeof(std::int64_t);

template <typename T>
concept float_packable = std::floating_point<stdx::underlying_type_t<T>> and
sizeof(T) <= sizeof(std::int64_t);

template <typename T>
concept packable =
signed_packable<T> or unsigned_packable<T> or float_packable<T>;

template <typename T> struct encoding;

template <signed_packable T> struct encoding<T> {
using encode_t = stdx::conditional_t<sizeof(T) <= sizeof(std::int32_t),
encode_32<T>, encode_64<T>>;
using pack_t = stdx::conditional_t<sizeof(T) <= sizeof(std::int32_t),
std::int32_t, std::int64_t>;
};

template <unsigned_packable T> struct encoding<T> {
using encode_t = stdx::conditional_t<sizeof(T) <= sizeof(std::uint32_t),
encode_u32<T>, encode_u64<T>>;
using pack_t = stdx::conditional_t<sizeof(T) <= sizeof(std::uint32_t),
std::uint32_t, std::uint64_t>;
};

template <float_packable T> struct encoding<T> {
using encode_t = stdx::conditional_t<sizeof(T) <= sizeof(std::uint32_t),
encode_u32<T>, encode_u64<T>>;
using pack_t = stdx::conditional_t<sizeof(T) <= sizeof(std::uint32_t),
std::uint32_t, std::uint64_t>;
};

struct default_arg_packer {
template <packable T> using pack_as_t = typename encoding<T>::pack_t;
template <packable T> using encode_as_t = typename encoding<T>::encode_t;
};
} // namespace logging
2 changes: 1 addition & 1 deletion include/log/catalog/builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace logging::binary {
}

CONSTEVAL auto operator()(auto &&) const {
return logging::mipi::default_builder{};
return logging::mipi::default_builder<>{};
}
} get_builder;
} // namespace logging::binary
5 changes: 0 additions & 5 deletions include/log/catalog/catalog.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,3 @@ using module_id = std::uint32_t;

template <typename> extern auto catalog() -> string_id;
template <typename> extern auto module() -> module_id;

template <typename> struct encode_32;
template <typename> struct encode_64;
template <typename> struct encode_u32;
template <typename> struct encode_u64;
1 change: 1 addition & 0 deletions include/log/catalog/encoder.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <log/catalog/arguments.hpp>
#include <log/catalog/builder.hpp>
#include <log/catalog/catalog.hpp>
#include <log/log.hpp>
Expand Down
87 changes: 36 additions & 51 deletions include/log/catalog/mipi_builder.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#pragma once

#include <log/catalog/arguments.hpp>
#include <log/catalog/catalog.hpp>
#include <log/catalog/mipi_messages.hpp>

#include <stdx/bit.hpp>
#include <stdx/compiler.hpp>
#include <stdx/type_traits.hpp>
#include <stdx/utility.hpp>
Expand All @@ -16,46 +18,19 @@

namespace logging::mipi {
template <typename T>
concept signed_packable = std::signed_integral<stdx::underlying_type_t<T>> and
sizeof(T) <= sizeof(std::int64_t);
concept packer = std::integral<typename T::template pack_as_t<int>> and
requires { typename T::template encode_as_t<int>; };

template <typename T>
concept unsigned_packable =
std::unsigned_integral<stdx::underlying_type_t<T>> and
sizeof(T) <= sizeof(std::int64_t);

template <typename T>
concept packable = signed_packable<T> or unsigned_packable<T>;

template <typename T> struct encoding;

template <signed_packable T> struct encoding<T> {
using encode_t = stdx::conditional_t<sizeof(T) <= sizeof(std::int32_t),
encode_32<T>, encode_64<T>>;
using pack_t = stdx::conditional_t<sizeof(T) <= sizeof(std::int32_t),
std::int32_t, std::int64_t>;
};
template <typename, packer> struct builder;

template <unsigned_packable T> struct encoding<T> {
using encode_t = stdx::conditional_t<sizeof(T) <= sizeof(std::int32_t),
encode_u32<T>, encode_u64<T>>;
using pack_t = stdx::conditional_t<sizeof(T) <= sizeof(std::uint32_t),
std::uint32_t, std::uint64_t>;
};

template <packable T> using pack_as_t = typename encoding<T>::pack_t;
template <packable T> using encode_as_t = typename encoding<T>::encode_t;

template <typename> struct builder;

template <> struct builder<defn::short32_msg_t> {
template <packer P> struct builder<defn::short32_msg_t, P> {
template <auto Level> static auto build(string_id id, module_id) {
using namespace msg;
return owning<defn::short32_msg_t>{"payload"_field = id};
}
};

template <typename Storage> struct catalog_builder {
template <typename Storage, packer P> struct catalog_builder {
template <auto Level, packable... Ts>
static auto build(string_id id, module_id m, Ts... args) {
using namespace msg;
Expand All @@ -66,8 +41,16 @@ template <typename Storage> struct catalog_builder {
constexpr auto header_size = defn::catalog_msg_t::size<V>::value;

auto const pack_arg = []<typename T>(V *p, T arg) -> V * {
auto const packed = stdx::to_le(stdx::as_unsigned(
static_cast<pack_as_t<T>>(stdx::to_underlying(arg))));
typename P::template pack_as_t<T> converted{};
if constexpr (sizeof(stdx::to_underlying(arg)) ==
sizeof(converted)) {
converted = stdx::bit_cast<decltype(converted)>(
stdx::to_underlying(arg));
} else {
converted =
static_cast<decltype(converted)>(stdx::to_underlying(arg));
}
auto const packed = stdx::to_le(stdx::as_unsigned(converted));
std::memcpy(p, &packed, sizeof(packed));
return p + stdx::sized8{sizeof(packed)}.in<V>();
};
Expand All @@ -80,48 +63,49 @@ template <typename Storage> struct catalog_builder {
}
};

template <> struct builder<defn::catalog_msg_t> {
template <packer P> struct builder<defn::catalog_msg_t, P> {
template <auto Level, typename... Ts>
static auto build(string_id id, module_id m, Ts... args) {
using namespace msg;
if constexpr ((0 + ... + sizeof(Ts)) <= sizeof(std::uint32_t) * 2) {
constexpr auto header_size =
defn::catalog_msg_t::size<std::uint32_t>::value;
constexpr auto payload_size =
stdx::sized8{(sizeof(id) + ... + sizeof(pack_as_t<Ts>))}
stdx::sized8{(sizeof(id) + ... +
sizeof(typename P::template pack_as_t<Ts>))}
.in<std::uint32_t>();
using storage_t =
std::array<std::uint32_t, header_size + payload_size>;
return catalog_builder<storage_t>{}.template build<Level>(id, m,
args...);
return catalog_builder<storage_t, P>{}.template build<Level>(
id, m, args...);
} else {
constexpr auto header_size =
defn::catalog_msg_t::size<std::uint8_t>::value;
constexpr auto payload_size =
(sizeof(id) + ... + sizeof(pack_as_t<Ts>));
(sizeof(id) + ... + sizeof(typename P::template pack_as_t<Ts>));
using storage_t =
std::array<std::uint8_t, header_size + payload_size>;
return catalog_builder<storage_t>{}.template build<Level>(id, m,
args...);
return catalog_builder<storage_t, P>{}.template build<Level>(
id, m, args...);
}
}
};

template <> struct builder<defn::compact32_build_msg_t> {
template <packer P> struct builder<defn::compact32_build_msg_t, P> {
template <auto Version> static auto build() {
using namespace msg;
return owning<defn::compact32_build_msg_t>{"build_id"_field = Version};
}
};

template <> struct builder<defn::compact64_build_msg_t> {
template <packer P> struct builder<defn::compact64_build_msg_t, P> {
template <auto Version> static auto build() {
using namespace msg;
return owning<defn::compact64_build_msg_t>{"build_id"_field = Version};
}
};

template <> struct builder<defn::normal_build_msg_t> {
template <packer P> struct builder<defn::normal_build_msg_t, P> {
template <auto Version, stdx::ct_string S> static auto build() {
using namespace msg;
constexpr auto header_size =
Expand All @@ -141,32 +125,33 @@ template <> struct builder<defn::normal_build_msg_t> {
}
};

struct default_builder {
template <packer P = logging::default_arg_packer> struct default_builder {
template <auto Level, packable... Ts>
static auto build(string_id id, module_id m, Ts... args) {
if constexpr (sizeof...(Ts) == 0u) {
return builder<defn::short32_msg_t>{}.template build<Level>(id, m);
return builder<defn::short32_msg_t, P>{}.template build<Level>(id,
m);
} else {
return builder<defn::catalog_msg_t>{}.template build<Level>(
return builder<defn::catalog_msg_t, P>{}.template build<Level>(
id, m, args...);
}
}

template <auto Version, stdx::ct_string S = ""> auto build_version() {
using namespace msg;
if constexpr (S.empty() and stdx::bit_width(Version) <= 22) {
return builder<defn::compact32_build_msg_t>{}
return builder<defn::compact32_build_msg_t, P>{}
.template build<Version>();
} else if constexpr (S.empty() and stdx::bit_width(Version) <= 54) {
return builder<defn::compact64_build_msg_t>{}
return builder<defn::compact64_build_msg_t, P>{}
.template build<Version>();
} else {
return builder<defn::normal_build_msg_t>{}
return builder<defn::normal_build_msg_t, P>{}
.template build<Version, S>();
}
}

template <template <typename...> typename F, typename... Args>
using convert_args = F<encode_as_t<Args>...>;
using convert_args = F<typename P::template encode_as_t<Args>...>;
};
} // namespace logging::mipi
16 changes: 16 additions & 0 deletions test/log/catalog2b_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,26 @@ using log_env2b = stdx::make_env_t<logging::get_level, logging::level::TRACE>;
} // namespace

auto log_rt_enum_arg() -> void;
auto log_rt_float_arg() -> void;
auto log_rt_double_arg() -> void;

auto log_rt_enum_arg() -> void {
auto cfg = logging::binary::config{test_log_args_destination{}};
using namespace ns;
cfg.logger.log_msg<log_env2b>(
stdx::ct_format<"E string with {} placeholder">(E::value));
}

auto log_rt_float_arg() -> void {
auto cfg = logging::binary::config{test_log_args_destination{}};
using namespace ns;
cfg.logger.log_msg<log_env2b>(
stdx::ct_format<"Float string with {} placeholder">(3.14f));
}

auto log_rt_double_arg() -> void {
auto cfg = logging::binary::config{test_log_args_destination{}};
using namespace ns;
cfg.logger.log_msg<log_env2b>(
stdx::ct_format<"Double string with {} placeholder">(3.14));
}
18 changes: 18 additions & 0 deletions test/log/catalog_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ extern auto log_with_non_default_module() -> void;
extern auto log_with_fixed_module() -> void;
extern auto log_with_fixed_string_id() -> void;
extern auto log_with_fixed_module_id() -> void;
extern auto log_rt_float_arg() -> void;
extern auto log_rt_double_arg() -> void;

TEST_CASE("log zero arguments", "[catalog]") {
test_critical_section::count = 0;
Expand Down Expand Up @@ -58,6 +60,22 @@ TEST_CASE("log one 64-bit runtime argument", "[catalog]") {
CHECK(log_calls == 1);
}

TEST_CASE("log one float runtime argument", "[catalog]") {
log_calls = 0;
test_critical_section::count = 0;
log_rt_float_arg();
CHECK(test_critical_section::count == 2);
CHECK(log_calls == 1);
}

TEST_CASE("log one double runtime argument", "[catalog]") {
log_calls = 0;
test_critical_section::count = 0;
log_rt_double_arg();
CHECK(test_critical_section::count == 2);
CHECK(log_calls == 1);
}

TEST_CASE("log one formatted runtime argument", "[catalog]") {
log_calls = 0;
test_critical_section::count = 0;
Expand Down
Loading
Loading