Skip to content

Latest commit

 

History

History
270 lines (211 loc) · 7.18 KB

185.md

File metadata and controls

270 lines (211 loc) · 7.18 KB
Info

Example

int main() {
  fmt::print(FMT_STRING("{}"), 42);
  fmt::print(FMT_STRING("{}, {}"), 42); // Compilation Error
}

https://godbolt.org/z/xdsbvr

Puzzle

  • Can you implement a subroutine has_valid_args which verifies that named arguments match the format?
constexpr auto has_valid_args(auto fmt, auto... args) {
  return /*TODO*/ false;
}

static_assert(not has_valid_args(""_fmt, "arg1"_arg = 42));
static_assert(not has_valid_args(""_fmt, "arg1"_arg = 42, "arg2"_arg = "Quantlab"));
static_assert(not has_valid_args("{}"_fmt, "arg1"_arg = 42));
static_assert(not has_valid_args("{arg2}"_fmt, "arg1"_arg = 42));

static_assert(not has_valid_args("{arg1}"_fmt, "arg1"_arg = 42, "arg2"_arg = "Quantlab"));
static_assert(not has_valid_args("{arg1}"_fmt, "arg1"_arg = 42, "ARG2"_arg = "Quantlab"));

static_assert(has_valid_args("{arg1}, {arg2}"_fmt, "arg1"_arg = 42, "arg2"_arg = "Quantlab"));
static_assert(has_valid_args("{arg2}, {arg1}"_fmt, "arg1"_arg = 42, "arg2"_arg = "Quantlab"));
static_assert(has_valid_args("{arg1}, {arg2}"_fmt, "arg2"_arg = "Quantlab", "arg1"_arg = 42));
static_assert(has_valid_args("{arg2}, {arg1}"_fmt, "arg2"_arg = "Quantlab", "arg1"_arg = 42));

https://godbolt.org/z/dr5zK5

Solutions

constexpr std::string_view operator "" _fmt(char const * str, std::size_t n)
{
    return std::string_view{str, n};
}

struct arg_type
{
    template <typename T>
    constexpr arg_type operator=(T const & val)
    {
        return *this;
    }

    std::string_view name;
};

constexpr arg_type operator "" _arg(char const * str, std::size_t n)
{
    return arg_type{ { str, n } };
}

constexpr auto has_valid_args(auto fmt, auto... args)
{
    auto begin = std::begin(fmt);
    auto end = std::end(fmt);

    int named_args_count = 0;
    bool result = true;

    auto p = begin;
    while(p != end) {
        auto c = *p++;
        if(c == '{') {
            auto c = *p;
            if(c != '}') {
                auto it = p;
                do {
                    ++it;
                    c = *it;
                }
                while(it != end && (( 'a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')));

                // p -> it = fmt_arg_name
                ++named_args_count;
                auto fmt_arg_name = std::string_view{ p, it };
                result = result && ((fmt_arg_name == args.name) || ... );

                p = it;
            }

            ++p;
        }
    }

    return sizeof...(args) == named_args_count && result;
}

https://godbolt.org/z/MsY914

constexpr auto contains_arg(const auto& fmt, const auto& arg_name) {
    auto it = std::cbegin(fmt);
    while (it != std::cend(fmt)) {
      it = std::search(it, std::cend(fmt),
                       std::cbegin(arg_name), std::cend(arg_name));
      if (it == std::cend(fmt)) {
        break;
      }
      const auto close_brace_it = std::next(it, std::size(arg_name));
      if (it != std::cbegin(fmt) and close_brace_it != std::cend(fmt)
          and *std::prev(it) == '{' and *close_brace_it == '}') {
        return true;
      }
      it = close_brace_it;
    }
    return false;
}

constexpr auto operator""_fmt(const char* ptr, std::size_t sz) {
  return std::string_view{ptr, ptr + sz};
}

struct arg {
  constexpr auto& operator=(const auto&) { return *this; }
  std::string_view name;
};

constexpr auto operator""_arg(const char* ptr, std::size_t sz) {
  return arg{.name = {ptr, sz}};
}

constexpr auto has_valid_args(auto fmt, auto... args) {
  return (contains_arg(fmt, args.name) and ...);
}

https://godbolt.org/z/Kn7zcx

struct udl_arg {
  const std::string_view name;

  constexpr auto operator=(const auto&) {
    return name;
  }
};

constexpr std::string_view operator""_fmt(const char* str, std::size_t len) {
  return {str, len};
}

constexpr udl_arg operator""_arg(const char* str, std::size_t len) {
  const std::string_view sv{str, len};
  return {sv};
}

constexpr auto has_valid_args(const auto& fmt, const auto&&... args) {
  const std::array<std::string_view, sizeof...(args)> a{args...};
  std::array<bool, sizeof...(args)> b{};

  for (const auto& [m, name] : ctre::range<"\\{([A-Z_a-z][A-Z_a-z0-9]*)\\}">(fmt)) {
    const auto it = std::find(std::cbegin(a), std::cend(a), name);
    if (it == std::cend(a)) return false;
    b[std::distance(std::cbegin(a), it)] = true;
  }

  return std::reduce(std::cbegin(b), std::cend(b), true, std::logical_and<>());
}

https://godbolt.org/z/WvP7Yh

constexpr bool contains(auto fmt, auto arg) {
    for(int i=0; i<fmt.arr.size(); i++) {
        if( fmt.arr[i] == arg.first.arr[0] ) {
            int j = 0;
            for(; j<arg.first.arr.size(); j++)
                if( fmt.arr[i+j] != arg.first.arr[j])
                    break;
            if(j == arg.first.arr.size())
                return true;
        }
    }
    return false;
}

constexpr auto has_valid_args(auto fmt, auto... args) {
  return   (contains(fmt, args) & ... & true);
}

template<char...s> struct arg {
    template<typename T>
    std::pair<arg<s...>, T> constexpr operator=(T value) {
        return {{}, value};
    }
    std::array<char, sizeof...(s)> arr{s...};
};

template<typename charT, charT...s>
arg<s...> constexpr operator"" _arg() { return {}; }

template<char...s> struct fmt {
    std::array<char, sizeof...(s)> arr{s...};
};

template<typename charT, charT...s>
fmt<s...> constexpr operator"" _fmt() { return{}; }

https://godbolt.org/z/cEc6Ee

constexpr auto operator""_fmt(const char* first_char, const std::size_t length) {
    return std::string_view{first_char, first_char + length};
}

struct arg : std::string_view {
    constexpr auto operator=(const auto&) { return *this; }
};

constexpr auto operator""_arg (const char* first_char, const std::size_t length) {
    return arg(std::string_view{first_char, first_char + length});
}

consteval auto all_args_in_string(const auto &fmt) {
    return true;
}

consteval auto all_args_in_string(const auto &fmt, const auto arg, const auto... args) {
    const bool arg_in_string = fmt.find(arg) != std::string_view::npos;
    return arg_in_string and all_args_in_string(fmt, args...);
}

consteval auto has_valid_args(const auto fmt, const auto... args) {
    return all_args_in_string(fmt, args...);

https://godbolt.org/z/MWEW6Y

struct arg {
  constexpr auto& operator=(const auto&) { return *this; }
  constexpr operator auto() const { return name; }
  std::string_view name;
};

constexpr auto operator""_arg(const char* name, std::size_t size) {
  return arg{.name = {name, size}};
}

constexpr auto operator""_fmt(const char* name, std::size_t size) {
  return std::string_view{name, size};
}

constexpr auto has_valid_args(auto fmt, auto... args) {
  return ((fmt.find(args) != std::string_view::npos) and ...);
}

https://godbolt.org/z/85boK9