Skip to content

Latest commit

 

History

History
185 lines (140 loc) · 6.11 KB

186.md

File metadata and controls

185 lines (140 loc) · 6.11 KB
Info

Example

template<auto Size>
struct fixed_string {
  char data[Size + 1]{};
  static constexpr auto size = Size;
  constexpr explicit(false) fixed_string(char const* str) { std::copy_n(str, Size + 1, data); }
  constexpr explicit(false) operator std::string_view() const { return {data, Size}; }
};
template<auto Size> fixed_string(char const (&)[Size]) -> fixed_string<Size - 1>;

template<fixed_string Str> constexpr auto operator""_s() { return Str; }

static_assert(sizeof("Quantlab") == sizeof("Quantlab"_s));
static_assert("Quantlab"sv == std::string_view{"Quantlab"_s});

https://godbolt.org/z/zaqjMG

Puzzle

  • Can you implement fixed_format subroutine which produces minimal size compile-time fixed_string?
constexpr auto fixed_format(auto format, auto... args); /* TODO */

static_assert(fixed_format(""_fmt) == ""sv);
static_assert(sizeof("") == sizeof(fixed_format(""_fmt)));

static_assert(fixed_format("{}"_fmt, "Quantlab"_s) == "Quantlab"sv);
static_assert(sizeof("Quantlab") == sizeof(fixed_format("{}"_fmt, "Quantlab"_s)));

static_assert(fixed_format("|{}|{}|"_fmt, "Quant"_s, "lab"_s) == "|Quant|lab|"sv);
static_assert(sizeof("|Quant|lab|") == sizeof(fixed_format("|{}|{}|"_fmt, "Quant"_s, "lab"_s)));

static_assert(fixed_format("{}+{}={}"_fmt, "1"_s, "2"_s, "3"_s) == "1+2=3"sv);
static_assert(sizeof("1+2=3") == sizeof(fixed_format("{}+{}={}"_fmt, "1"_s, "2"_s, "3"_s)));

https://godbolt.org/z/h1d5Wh

Solutions

constexpr const std::string_view field{"{}"};

constexpr void fixed_format_arg(auto& first, const auto& last, auto& d_first, const auto arg) {
  constexpr const auto size = decltype(arg)::size;
  const auto next = std::search(first, last, field.cbegin(), field.cend());
  const auto dist = std::distance(first, next);

  std::copy(first, next, d_first);
  std::copy_n(arg.data, size, d_first + dist);
  std::advance(first, dist + field.size());
  std::advance(d_first, dist + size);
}

constexpr auto fixed_format(const auto fmt, const auto... args) {
  fixed_string<(decltype(fmt)::size + ... + (decltype(args)::size - field.size()))> out;
  auto first = fmt.data;
  const auto last = first + sizeof fmt.data;
  auto d_first = out.data;

  (fixed_format_arg(first, last, d_first, args), ...);
  std::copy(first, last, d_first);

  return out;
}

https://godbolt.org/z/xer4fc

constexpr auto fixed_format(auto format, auto... args) {
    constexpr auto spec = "{}"sv;
    constexpr auto spec_size = std::size(spec);
    constexpr auto formatted_size = std::size(format) - sizeof...(args)*spec_size + (std::size(args) + ... + 0);

    fixed_string<formatted_size> ret{};
    auto write_ptr = std::data(ret);
    std::string_view s = format;

    ([&] (const auto& arg) {
      const auto arg_pos = s.find(spec);
      write_ptr = std::copy_n(std::data(s), arg_pos, write_ptr);
      write_ptr = std::copy_n(std::data(arg), std::size(arg), write_ptr);
      s.remove_prefix(arg_pos + spec_size);
    }(args), ...);
    std::copy_n(std::data(s), std::size(s), write_ptr);

    return ret;
}

https://godbolt.org/z/jsY7xv

constexpr auto fixed_format(auto format, auto... args) {
    constexpr auto len = format.size - 2*sizeof...(args) + (args.size + ... + 0);
    std::array<char, len+1> fstr{};
    std::array<std::string_view, sizeof...(args)> argView{ std::string_view(args)...};

    char* in_it = format.data;
    char* out_it = fstr.data();
    uint argIdx = 0;
    while(in_it < format.data+format.size)
        if (*in_it != '{')
            *out_it++ = *in_it++;
        else {
            std::copy_n(argView[argIdx].data(), argView[argIdx].size(), out_it);
            out_it += argView[argIdx].size();
            in_it += 2;
            argIdx++;
        }
    return fixed_string<len>(fstr.data());
}

https://godbolt.org/z/r93rh5

constexpr auto fixed_format(auto format, auto... args) {
    constexpr auto to_replace = "{}"sv;
    constexpr auto replace_len = std::size(to_replace) * sizeof...(args);
    constexpr auto args_sum_len = (std::size(args) + ... + 0);
    constexpr auto output_len = std::size(format) - replace_len + args_sum_len;

    auto ret = fixed_string<output_len>{};
    auto loc = std::begin(ret);

    auto s = std::string_view(format);

    ([] (auto& s, auto& loc, const auto& to_replace, const auto& arg) {
      const auto pos = s.find(to_replace);
      loc = std::copy(std::begin(s), std::begin(s) + pos, loc);
      loc = std::copy(std::begin(arg), std::begin(arg) + std::size(arg), loc);
      s.remove_prefix(pos + std::size(to_replace));
    }(s, loc, to_replace, args), ...);

    std::copy(std::begin(s), std::begin(s) + std::size(s), loc);

    return ret;
}

https://godbolt.org/z/Yjr4x6

constexpr auto replace_unnamed_arg(const auto format, const auto replacement) {
  constexpr std::string_view unnamed_arg_str = "{}";
  constexpr auto new_size =
      format.size - std::size(unnamed_arg_str) + replacement.size;

  auto replace_start = std::distance(
      std::begin(format.data),
      std::find(std::begin(format.data), std::end(format.data), '{'));
  auto replace_end = replace_start + std::size(unnamed_arg_str);

  fixed_str<new_size> output{};
  auto write_loc = std::copy_n(format.data, replace_start, output.data);
  write_loc = std::copy_n(replacement.data, replacement.size, write_loc);
  std::copy_n(format.data + replace_end, format.size - replace_end, write_loc);
  return output;
}

constexpr auto apply_formatting(const auto format) { return format; }
constexpr auto apply_formatting(const auto format, const auto arg, auto... args) {
  return apply_formatting(replace_unnamed_arg(format, arg), args...);
}

constexpr auto fixed_format(auto format, auto... args) {
  return apply_formatting(format, args...);
}

https://godbolt.org/z/bTcY6r