Skip to content
Draft
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
14 changes: 0 additions & 14 deletions include/sparrow/types/data_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -955,18 +955,4 @@ namespace sparrow
}
}

template <>
struct std::formatter<std::byte>
{
constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin(); // Simple implementation
}

auto format(const std::byte& b, std::format_context& ctx) const
{
return std::format_to(ctx.out(), "{}", static_cast<int>(b));
}
};

#endif
151 changes: 150 additions & 1 deletion include/sparrow/utils/format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,122 @@

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <format>
#include <numeric>
#include <ranges>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>

#include "sparrow/utils/contracts.hpp"

namespace sparrow::detail
{
struct sequence_format_spec
{
char fill = ' ';
char align = '>'; // '<', '>', '^'
std::size_t width = 0;

// Parse: [[fill]align] [width]
// Grammar subset: (fill? align?) width?
template <class It>
constexpr It parse(It it, It end)
{
if (it == end || *it == '}')
{
return it;
}

// Detect [fill][align] or [align]
auto next = it;
if (next != end)
{
++next;
if (next != end && (*next == '<' || *next == '>' || *next == '^') && *it != '<' && *it != '>'
&& *it != '^')
{
fill = *it;
align = *next;
it = ++next;
}
else if (*it == '<' || *it == '>' || *it == '^')
{
align = *it;
++it;
}
}

// Parse width
std::size_t w = 0;
bool has_w = false;
while (it != end && *it >= '0' && *it <= '9')
{
has_w = true;
w = w * 10 + static_cast<unsigned>(*it - '0');
++it;
}
if (has_w)
{
width = w;
}

// Ignore (silently) everything until '}' (keeps constexpr friendliness)
while (it != end && *it != '}')
{
++it;
}

return it;
}

std::string apply_alignment(std::string inner) const
{
if (width <= inner.size())
{
return inner;
}

const std::size_t pad = width - inner.size();
switch (align)
{
case '<':
return inner + std::string(pad, fill);
case '^':
{
std::size_t left = pad / 2;
std::size_t right = pad - left;
return std::string(left, fill) + inner + std::string(right, fill);
}
case '>':
default:
return std::string(pad, fill) + inner;
}
}

template <class Seq>
std::string build_core(const Seq& seq) const
{
std::string core;
core.push_back('<');
bool first = true;
for (auto&& elem : seq)
{
if (!first)
{
core.append(", ");
}
std::format_to(std::back_inserter(core), "{}", elem);
first = false;
}
core.push_back('>');
return core;
}
};
} // namespace sparrow::detail

namespace std
{
template <class... T>
Expand Down Expand Up @@ -56,6 +163,25 @@ namespace std

std::string m_format_string = "{:";
};

template <>
struct formatter<std::byte>
{
constexpr auto parse(format_parse_context& ctx)
{
return m_underlying_formatter.parse(ctx);
}

auto format(std::byte b, std::format_context& ctx) const
{
return std::format_to(ctx.out(), "{:#04x}", std::to_integer<unsigned>(b));
}

private:

// Store the parsed format specification
std::formatter<unsigned> m_underlying_formatter;
};
}

namespace sparrow
Expand All @@ -69,12 +195,35 @@ namespace sparrow
template <typename T>
concept RangeOfFormats = std::ranges::range<T> && Format<std::ranges::range_value_t<T>>;

constexpr size_t size_of_utf8(const std::string_view str)
{
size_t size = 0;
for (const char c : str)
{
if ((c & 0xC0) != 0x80)
{
++size;
}
}
return size;
}

constexpr size_t max_width(const std::ranges::input_range auto& data)
{
size_t max_width = 0;
for (const auto& value : data)
{
max_width = std::max(max_width, std::format("{}", value).size());
if constexpr (std::is_same_v<std::remove_cvref_t<std::decay_t<decltype(value)>>, std::string>
|| std::is_same_v<std::remove_cvref_t<std::decay_t<decltype(value)>>, std::string_view>
|| std::is_same_v<std::remove_cvref_t<std::decay_t<decltype(value)>>, const char*>
|| std::is_same_v<std::remove_cvref_t<std::decay_t<decltype(value)>>, char*>)
{
max_width = std::max(max_width, size_of_utf8(value));
}
else
{
max_width = std::max(max_width, std::format("{}", value).size());
}
}
return max_width;
}
Expand Down
2 changes: 1 addition & 1 deletion include/sparrow/utils/nullable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,7 @@ struct std::formatter<sparrow::nullable_variant<T...>>
}
else
{
return std::format_to(ctx.out(), "{}", "null");
return std::vformat_to(ctx.out(), m_format_string, std::make_format_args("null"));
}
}

Expand Down
74 changes: 23 additions & 51 deletions include/sparrow/utils/ranges.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#if defined(__cpp_lib_format)
# include <format>

# include "sparrow/utils/format.hpp"
#endif

#include "sparrow/utils/mp_utils.hpp"
Expand Down Expand Up @@ -135,89 +137,59 @@ struct std::formatter<std::array<T, N>>
{
constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin(); // Simple implementation
return m_spec.parse(ctx.begin(), ctx.end());
}

auto format(const std::array<T, N>& array, std::format_context& ctx) const
{
auto out = ctx.out();
*out++ = '<';
std::string core = m_spec.build_core(array);
std::string out_str = m_spec.apply_alignment(std::move(core));
return std::ranges::copy(out_str, ctx.out()).out;
}

bool first = true;
for (const auto& elem : array)
{
if (!first)
{
*out++ = ',';
*out++ = ' ';
}
out = std::format_to(out, "{}", elem);
first = false;
}
private:

*out++ = '>';
return out;
}
sparrow::detail::sequence_format_spec m_spec;
};

template <typename T>
struct std::formatter<std::vector<T>>
{
constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin(); // Simple implementation
return m_spec.parse(ctx.begin(), ctx.end());
}

auto format(const std::vector<T>& vector, std::format_context& ctx) const
{
auto out = ctx.out();
*out++ = '<';
std::string core = m_spec.build_core(vector);
std::string out_str = m_spec.apply_alignment(std::move(core));
return std::ranges::copy(out_str, ctx.out()).out;
}

bool first = true;
for (const auto& elem : vector)
{
if (!first)
{
*out++ = ',';
*out++ = ' ';
}
out = std::format_to(out, "{}", elem);
first = false;
}
private:

*out++ = '>';
return out;
}
sparrow::detail::sequence_format_spec m_spec;
};

template <std::size_t T>
struct std::formatter<std::bitset<T>>
{
constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin(); // Simple implementation
return m_spec.parse(ctx.begin(), ctx.end());
}

auto format(const std::bitset<T>& vector, std::format_context& ctx) const
{
auto out = ctx.out();
*out++ = '<';
std::string core = m_spec.build_core(vector);
std::string out_str = m_spec.apply_alignment(std::move(core));
return std::ranges::copy(out_str, ctx.out()).out;
}

bool first = true;
for (const auto& elem : vector)
{
if (!first)
{
*out++ = ',';
*out++ = ' ';
}
out = std::format_to(out, "{}", elem);
first = false;
}
private:

*out++ = '>';
return out;
}
sparrow::detail::sequence_format_spec m_spec;
};

#endif
20 changes: 9 additions & 11 deletions include/sparrow/utils/sequence_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#include <vector>

#if defined(__cpp_lib_format)
# include <format>
# include "sparrow/utils/format.hpp"
#endif

#include "sparrow/utils/mp_utils.hpp"
Expand Down Expand Up @@ -132,21 +132,19 @@ struct std::formatter<sparrow::sequence_view<T, E>>
{
constexpr auto parse(std::format_parse_context& ctx)
{
return ctx.begin(); // Simple implementation
return m_spec.parse(ctx.begin(), ctx.end());
}

auto format(const sparrow::sequence_view<T, E>& vec, std::format_context& ctx) const
{
std::format_to(ctx.out(), "<");
if (!vec.empty())
{
for (std::size_t i = 0; i < vec.size() - 1; ++i)
{
std::format_to(ctx.out(), "{}, ", vec[i]);
}
}
return std::format_to(ctx.out(), "{}>", vec.back());
std::string core = m_spec.build_core(vec);
std::string out_str = m_spec.apply_alignment(std::move(core));
return std::ranges::copy(out_str, ctx.out()).out;
}

private:

sparrow::detail::sequence_format_spec m_spec;
};

namespace sparrow
Expand Down
Loading
Loading