before this change, we rely on `using namespace seastar` to use
`seastar::format()` without qualifying the `format()` with its
namespace. this works fine until we changed the parameter type
of format string `seastar::format()` from `const char*` to
`fmt::format_string<...>`. this change practically invited
`seastar::format()` to the club of `std::format()` and `fmt::format()`,
where all members accept a templated parameter as its `fmt`
parameter. and `seastar::format()` is not the best candidate anymore.
despite that argument-dependent lookup (ADT for short) favors the
function which is in the same namespace as its parameter, but
`using namespace` makes `seastar::format()` more competitive,
so both `std::format()` and `seastar::format()` are considered
as the condidates.
that is what is happening scylladb in quite a few caller sites of
`format()`, hence ADT is not able to tell which function the winner
in the name lookup:
```
/__w/scylladb/scylladb/mutation/mutation_fragment_stream_validator.cc:265:12: error: call to 'format' is ambiguous
265 | return format("{} ({}.{} {})", _name_view, s.ks_name(), s.cf_name(), s.id());
| ^~~~~~
/usr/bin/../lib/gcc/x86_64-redhat-linux/14/../../../../include/c++/14/format:4290:5: note: candidate function [with _Args = <const std::basic_string_view<char> &, const seastar::basic_sstring<char, unsigned int, 15> &, const seastar::basic_sstring<char, unsigned int, 15> &, const utils::tagged_uuid<table_id_tag> &>]
4290 | format(format_string<_Args...> __fmt, _Args&&... __args)
| ^
/__w/scylladb/scylladb/seastar/include/seastar/core/print.hh:143:1: note: candidate function [with A = <const std::basic_string_view<char> &, const seastar::basic_sstring<char, unsigned int, 15> &, const seastar::basic_sstring<char, unsigned int, 15> &, const utils::tagged_uuid<table_id_tag> &>]
143 | format(fmt::format_string<A...> fmt, A&&... a) {
| ^
```
in this change, we
change all `format()` to either `fmt::format()` or `seastar::format()`
with following rules:
- if the caller expects an `sstring` or `std::string_view`, change to
`seastar::format()`
- if the caller expects an `std::string`, change to `fmt::format()`.
because, `sstring::operator std::basic_string` would incur a deep
copy.
we will need another change to enable scylladb to compile with the
latest seastar. namely, to pass the format string as a templated
parameter down to helper functions which format their parameters.
to miminize the scope of this change, let's include that change when
bumping up the seastar submodule. as that change will depend on
the seastar change.
Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>
98 lines
2.4 KiB
C++
98 lines
2.4 KiB
C++
/*
|
|
* Copyright (C) 2014-present ScyllaDB
|
|
*
|
|
* Modified by ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "function.hh"
|
|
#include "types/types.hh"
|
|
#include "cql3/cql3_type.hh"
|
|
#include "cql3/functions/function_name.hh"
|
|
#include <vector>
|
|
#include <boost/functional/hash.hpp>
|
|
#include <fmt/core.h>
|
|
|
|
|
|
template <> struct fmt::formatter<std::vector<data_type>> : fmt::formatter<string_view> {
|
|
auto format(const std::vector<data_type>& arg_types, fmt::format_context& ctx) const -> decltype(ctx.out());
|
|
};
|
|
|
|
namespace cql3 {
|
|
|
|
namespace functions {
|
|
|
|
/**
|
|
* Base class for our native/hardcoded functions.
|
|
*/
|
|
class abstract_function : public virtual function {
|
|
protected:
|
|
function_name _name;
|
|
std::vector<data_type> _arg_types;
|
|
data_type _return_type;
|
|
|
|
abstract_function(function_name name, std::vector<data_type> arg_types, data_type return_type)
|
|
: _name(std::move(name)), _arg_types(std::move(arg_types)), _return_type(std::move(return_type)) {
|
|
}
|
|
|
|
public:
|
|
|
|
virtual bool requires_thread() const override;
|
|
|
|
virtual const function_name& name() const override {
|
|
return _name;
|
|
}
|
|
|
|
virtual const std::vector<data_type>& arg_types() const override {
|
|
return _arg_types;
|
|
}
|
|
|
|
virtual const data_type& return_type() const override {
|
|
return _return_type;
|
|
}
|
|
|
|
bool operator==(const abstract_function& x) const {
|
|
return _name == x._name
|
|
&& _arg_types == x._arg_types
|
|
&& _return_type == x._return_type;
|
|
}
|
|
|
|
virtual sstring column_name(const std::vector<sstring>& column_names) const override {
|
|
return seastar::format("{}({})", _name, fmt::join(column_names, ", "));
|
|
}
|
|
|
|
virtual void print(std::ostream& os) const override;
|
|
};
|
|
|
|
inline
|
|
void
|
|
abstract_function::print(std::ostream& os) const {
|
|
fmt::print(os, "{} : ({}) -> {}",
|
|
_name, _arg_types, _return_type->as_cql3_type().to_string());
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
namespace std {
|
|
|
|
template <>
|
|
struct hash<cql3::functions::abstract_function> {
|
|
size_t operator()(const cql3::functions::abstract_function& f) const {
|
|
using namespace cql3::functions;
|
|
size_t v = 0;
|
|
boost::hash_combine(v, std::hash<function_name>()(f.name()));
|
|
boost::hash_combine(v, boost::hash_value(f.arg_types()));
|
|
// FIXME: type hash
|
|
//boost::hash_combine(v, std::hash<shared_ptr<abstract_type>>()(f.return_type()));
|
|
return v;
|
|
}
|
|
};
|
|
|
|
}
|