Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into fuzz
Browse files Browse the repository at this point in the history
  • Loading branch information
pauldreik committed Jun 11, 2019
2 parents e9fabac + 87fbc6f commit 8feb8a3
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 49 deletions.
76 changes: 34 additions & 42 deletions include/fmt/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ template <bool B, class T, class F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <bool B> using bool_constant = std::integral_constant<bool, B>;

struct monostate {};

// An enable_if helper to be used in template parameters which results in much
// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
// to workaround a bug in MSVC 2019 (see #1140 and #1186).
Expand All @@ -213,17 +215,6 @@ using std_string_view = std::experimental::basic_string_view<Char>;
template <typename T> struct std_string_view {};
#endif

#if (__cplusplus >= 201703L || \
(defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)) && \
__cpp_lib_is_invocable >= 201703L
template <typename F, typename... Args>
using invoke_result_t = std::invoke_result_t<F, Args...>;
#else
// An implementation of invoke_result for pre-C++17.
template <typename F, typename... Args>
using invoke_result_t = typename std::result_of<F(Args...)>::type;
#endif

// Casts nonnegative integer to unsigned.
template <typename Int>
FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
Expand Down Expand Up @@ -670,7 +661,7 @@ FMT_CONSTEXPR bool is_arithmetic(type t) {
}

template <typename Char> struct string_value {
const Char* value;
const Char* data;
std::size_t size;
};

Expand All @@ -690,6 +681,8 @@ template <typename Context> class value {
unsigned uint_value;
long long long_long_value;
unsigned long long ulong_long_value;
bool bool_value;
char_type char_value;
double double_value;
long double long_double_value;
const void* pointer;
Expand All @@ -704,11 +697,11 @@ template <typename Context> class value {
value(unsigned long long val) : ulong_long_value(val) {}
value(double val) : double_value(val) {}
value(long double val) : long_double_value(val) {}
value(bool val) : int_value(val) {}
value(char_type val) : int_value(val) {}
value(const char_type* val) { string.value = val; }
value(bool val) : bool_value(val) {}
value(char_type val) : char_value(val) {}
value(const char_type* val) { string.data = val; }
value(basic_string_view<char_type> val) {
string.value = val.data();
string.data = val.data();
string.size = val.size();
}
value(const void* val) : pointer(val) {}
Expand Down Expand Up @@ -764,7 +757,7 @@ template <typename Context> struct arg_mapper {
FMT_CONSTEXPR bool map(bool val) { return val; }

template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
FMT_CONSTEXPR char_type map(const T& val) {
FMT_CONSTEXPR char_type map(T val) {
static_assert(
std::is_same<T, char>::value || std::is_same<T, char_type>::value,
"mixing character types is disallowed");
Expand Down Expand Up @@ -834,6 +827,12 @@ template <typename Context> struct arg_mapper {
}
};

// A type constant after applying arg_mapper<Context>.
template <typename T, typename Context>
using mapped_type_constant =
type_constant<decltype(arg_mapper<Context>().map(std::declval<T>())),
typename Context::char_type>;

// Maximum number of arguments with packed types.
enum { max_packed_args = 15 };
enum : unsigned long long { is_unpacked_bit = 1ull << 63 };
Expand All @@ -853,8 +852,9 @@ template <typename Context> class basic_format_arg {
const T& value);

template <typename Visitor, typename Ctx>
friend FMT_CONSTEXPR internal::invoke_result_t<Visitor, int> visit_format_arg(
Visitor&& vis, const basic_format_arg<Ctx>& arg);
friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
const basic_format_arg<Ctx>& arg)
-> decltype(vis(0));

friend class basic_format_args<Context>;
friend class internal::arg_map<Context>;
Expand Down Expand Up @@ -886,8 +886,6 @@ template <typename Context> class basic_format_arg {
bool is_arithmetic() const { return internal::is_arithmetic(type_); }
};

struct monostate {};

/**
\rst
Visits an argument dispatching to the appropriate visit method based on
Expand All @@ -896,8 +894,9 @@ struct monostate {};
\endrst
*/
template <typename Visitor, typename Context>
FMT_CONSTEXPR internal::invoke_result_t<Visitor, int> visit_format_arg(
Visitor&& vis, const basic_format_arg<Context>& arg) {
FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
const basic_format_arg<Context>& arg)
-> decltype(vis(0)) {
using char_type = typename Context::char_type;
switch (arg.type_) {
case internal::none_type:
Expand All @@ -914,17 +913,17 @@ FMT_CONSTEXPR internal::invoke_result_t<Visitor, int> visit_format_arg(
case internal::ulong_long_type:
return vis(arg.value_.ulong_long_value);
case internal::bool_type:
return vis(arg.value_.int_value != 0);
return vis(arg.value_.bool_value);
case internal::char_type:
return vis(static_cast<char_type>(arg.value_.int_value));
return vis(arg.value_.char_value);
case internal::double_type:
return vis(arg.value_.double_value);
case internal::long_double_type:
return vis(arg.value_.long_double_value);
case internal::cstring_type:
return vis(arg.value_.string.value);
return vis(arg.value_.string.data);
case internal::string_type:
return vis(basic_string_view<char_type>(arg.value_.string.value,
return vis(basic_string_view<char_type>(arg.value_.string.data,
arg.value_.string.size));
case internal::pointer_type:
return vis(arg.value_.pointer);
Expand All @@ -935,8 +934,9 @@ FMT_CONSTEXPR internal::invoke_result_t<Visitor, int> visit_format_arg(
}

template <typename Visitor, typename Context>
FMT_DEPRECATED FMT_CONSTEXPR internal::invoke_result_t<Visitor, int> visit(
Visitor&& vis, const basic_format_arg<Context>& arg) {
FMT_DEPRECATED FMT_CONSTEXPR auto visit(Visitor&& vis,
const basic_format_arg<Context>& arg)
-> decltype(vis(0)) {
return visit_format_arg(std::forward<Visitor>(vis), arg);
}

Expand All @@ -959,7 +959,7 @@ template <typename Context> class arg_map {

void push_back(value<Context> val) {
const auto& named = *val.named_arg;
map_[size_] = entry{named.name, named.template deserialize<Context>()};
map_[size_] = {named.name, named.template deserialize<Context>()};
++size_;
}

Expand Down Expand Up @@ -989,26 +989,18 @@ class locale_ref {
template <typename Locale> Locale get() const;
};

template <typename Context, typename T> struct get_type {
static const type value = type_constant<
decltype(arg_mapper<Context>().map(
std::declval<typename std::remove_volatile<T>::type>())),
typename Context::char_type>::value;
};

template <typename Context> constexpr unsigned long long get_types() {
return 0;
}
template <typename> constexpr unsigned long long get_types() { return 0; }

template <typename Context, typename Arg, typename... Args>
constexpr unsigned long long get_types() {
return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4);
return mapped_type_constant<Arg, Context>::value |
(get_types<Context, Args...>() << 4);
}

template <typename Context, typename T>
FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) {
basic_format_arg<Context> arg;
arg.type_ = get_type<Context, T>::value;
arg.type_ = mapped_type_constant<T, Context>::value;
arg.value_ = arg_mapper<Context>().map(value);
return arg;
}
Expand Down
3 changes: 2 additions & 1 deletion include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3176,7 +3176,8 @@ template <typename Char = char> class dynamic_formatter {
auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
handle_specs(ctx);
internal::specs_checker<null_handler> checker(
null_handler(), internal::get_type<FormatContext, T>::value);
null_handler(),
internal::mapped_type_constant<T, FormatContext>::value);
checker.on_align(specs_.align());
if (specs_.flags == 0)
; // Do nothing.
Expand Down
13 changes: 8 additions & 5 deletions test/core-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -567,15 +567,18 @@ TEST(CoreTest, ToStringViewForeignStrings) {
EXPECT_EQ(to_string_view(my_string<wchar_t>(L"42")), L"42");
EXPECT_EQ(to_string_view(QString(L"42")), L"42");
fmt::internal::type type =
fmt::internal::get_type<fmt::format_context, my_string<char>>::value;
fmt::internal::mapped_type_constant<my_string<char>,
fmt::format_context>::value;
EXPECT_EQ(type, fmt::internal::string_type);
type =
fmt::internal::get_type<fmt::wformat_context, my_string<wchar_t>>::value;
type = fmt::internal::mapped_type_constant<my_string<wchar_t>,
fmt::wformat_context>::value;
EXPECT_EQ(type, fmt::internal::string_type);
type = fmt::internal::get_type<fmt::wformat_context, QString>::value;
type =
fmt::internal::mapped_type_constant<QString, fmt::wformat_context>::value;
EXPECT_EQ(type, fmt::internal::string_type);
// Does not compile: only wide format contexts are compatible with QString!
// type = fmt::internal::get_type<fmt::format_context, QString>::value;
// type = fmt::internal::mapped_type_constant<QString,
// fmt::format_context>::value;
}

TEST(CoreTest, FormatForeignStrings) {
Expand Down
2 changes: 1 addition & 1 deletion test/format
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ struct formatter {
FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) {
namespace internal = fmt::internal;
typedef internal::dynamic_specs_handler<ParseContext> handler_type;
auto type = internal::get_type<fmt::buffer_context<Char>, T>::value;
auto type = internal::mapped_type_constant<T, fmt::buffer_context<Char>>::value;
internal::specs_checker<handler_type> handler(handler_type(specs_, ctx),
type);
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
Expand Down

0 comments on commit 8feb8a3

Please sign in to comment.