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 5, 2019
2 parents 3716491 + c264e64 commit 55da271
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 74 deletions.
4 changes: 3 additions & 1 deletion doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ The following user-defined literals are defined in ``fmt/format.h``.
Utilities
---------

.. doxygenclass:: fmt::is_char

.. doxygentypedef:: fmt::char_t

.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...)
Expand All @@ -208,7 +210,7 @@ Utilities

.. doxygenfunction:: fmt::to_wstring(const T&)

.. doxygenfunction:: fmt::to_string_view(basic_string_view<Char>)
.. doxygenfunction:: fmt::to_string_view(const Char *)

.. doxygenfunction:: fmt::join(const Range&, string_view)

Expand Down
2 changes: 1 addition & 1 deletion doc/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def build_docs(version='dev', **kwargs):
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
"FMT_END_NAMESPACE=}}" \
"FMT_STRING_ALIAS=1" \
"FMT_ENABLE_IF_T(B)="
"FMT_ENABLE_IF(B)="
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
'''.format(include_dir, doxyxml_dir).encode('UTF-8'))
if p.returncode != 0:
Expand Down
6 changes: 3 additions & 3 deletions include/fmt/chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -496,9 +496,9 @@ struct chrono_formatter {
OutputIt out;
int precision;
// rep is unsigned to avoid overflow.
using rep = typename std::conditional<
std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int), unsigned,
typename make_unsigned_or_unchanged<Rep>::type>::type;
using rep =
conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
unsigned, typename make_unsigned_or_unchanged<Rep>::type>;
rep val;
typedef std::chrono::duration<rep> seconds;
seconds s;
Expand Down
7 changes: 0 additions & 7 deletions include/fmt/color.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,13 +518,6 @@ inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
buffer.append(begin, end);
}

// The following specialization disables using std::FILE as a character type,
// which is needed because or else
// fmt::print(stderr, fmt::emphasis::bold, "");
// would take stderr (a std::FILE *) as the format string.
template <> struct is_string<std::FILE*> : std::false_type {};
template <> struct is_string<const std::FILE*> : std::false_type {};

template <typename Char>
std::basic_string<Char> vformat(const text_style& ts,
basic_string_view<Char> format_str,
Expand Down
72 changes: 36 additions & 36 deletions include/fmt/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,16 @@

FMT_BEGIN_NAMESPACE

// An implementation of enable_if_t for pre-C++14 systems.
// Implementations of enable_if_t and other types for pre-C++14 systems.
template <bool B, class T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template <bool B, class T, class F>
using conditional_t = typename std::conditional<B, T, F>::type;

// An enable_if helper to be used in template parameters which results in much
// shorter symbols: https://godbolt.org/z/sWw4vP.
#define FMT_ENABLE_IF(...) enable_if_t<__VA_ARGS__, int> = 0
// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
// to workaround a bug in MSVC 2019 (see #1140 and #1186).
#define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0

namespace internal {

Expand Down Expand Up @@ -441,30 +444,31 @@ template <typename Char> class basic_string_view {
using string_view = basic_string_view<char>;
using wstring_view = basic_string_view<wchar_t>;

/** Specifies if ``T`` is a character type. Can be specialized by users. */
template <typename T> struct is_char : std::false_type {};
template <> struct is_char<char> : std::true_type {};
template <> struct is_char<wchar_t> : std::true_type {};
template <> struct is_char<char16_t> : std::true_type {};
template <> struct is_char<char32_t> : std::true_type {};

/**
\rst
The function ``to_string_view`` adapts non-intrusively any kind of string or
string-like type if the user provides a (possibly templated) overload of
``to_string_view`` which takes an instance of the string class
``StringType<Char>`` and returns a ``fmt::basic_string_view<Char>``.
The conversion function must live in the very same namespace as
``StringType<Char>`` to be picked up by ADL. Non-templated string types
like f.e. QString must return a ``basic_string_view`` with a fixed matching
char type.
Returns a string view of `s`. In order to add custom string type support to
{fmt} provide an overload of `to_string_view` for it in the same namespace as
the type for the argument-dependent lookup to work.
**Example**::
namespace my_ns {
inline string_view to_string_view(const my_string &s) {
inline string_view to_string_view(const my_string& s) {
return {s.data(), s.length()};
}
}
std::string message = fmt::format(my_string("The answer is {}"), 42);
\endrst
*/
template <typename Char>
inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
inline basic_string_view<Char> to_string_view(const Char* s) {
return s;
}

Expand All @@ -475,7 +479,7 @@ inline basic_string_view<Char> to_string_view(
}

template <typename Char>
inline basic_string_view<Char> to_string_view(const Char* s) {
inline basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
return s;
}

Expand Down Expand Up @@ -589,17 +593,15 @@ dummy_string_view to_string_view(...);
using fmt::v5::to_string_view;

// Specifies whether S is a string type convertible to fmt::basic_string_view.
// It should be a constexpr function but MSVC 2017 fails to compile it in
// enable_if.
template <typename S>
struct is_string
: std::integral_constant<
bool,
!std::is_same<dummy_string_view,
decltype(to_string_view(std::declval<S>()))>::value> {};

// Forward declare FILE* specialization defined in color.h
template <> struct is_string<std::FILE*>;
template <> struct is_string<const std::FILE*>;

template <typename S> struct char_t_impl {
typedef decltype(to_string_view(std::declval<S>())) result;
typedef typename result::char_type type;
Expand Down Expand Up @@ -646,10 +648,9 @@ template <typename Char> struct string_value {
};

template <typename Context> struct custom_value {
using parse_context = basic_parse_context<typename Context::char_type>;
const void* value;
void (*format)(const void* arg,
basic_parse_context<typename Context::char_type>& parse_ctx,
Context& ctx);
void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx);
};

template <typename T, typename Context>
Expand Down Expand Up @@ -704,10 +705,9 @@ template <typename Context> class value {
// have different extension points, e.g. `formatter<T>` for `format` and
// `printf_formatter<T>` for `printf`.
custom.format = &format_custom_arg<
T, typename std::conditional<
is_formattable<T, Context>::value,
typename Context::template formatter_type<T>,
internal::fallback_formatter<T, char_type>>::type>;
T, conditional_t<is_formattable<T, Context>::value,
typename Context::template formatter_type<T>,
internal::fallback_formatter<T, char_type>>>;
}

const named_arg_base<char_type>& as_named_arg() {
Expand Down Expand Up @@ -758,12 +758,11 @@ FMT_MAKE_VALUE_SAME(uint_type, unsigned)

// To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size.
using long_type =
std::conditional<sizeof(long) == sizeof(int), int, long long>::type;
using long_type = conditional_t<sizeof(long) == sizeof(int), int, long long>;
FMT_MAKE_VALUE((sizeof(long) == sizeof(int) ? int_type : long_long_type), long,
long_type)
using ulong_type = std::conditional<sizeof(unsigned long) == sizeof(unsigned),
unsigned, unsigned long long>::type;
using ulong_type = conditional_t<sizeof(unsigned long) == sizeof(unsigned),
unsigned, unsigned long long>;
FMT_MAKE_VALUE((sizeof(unsigned long) == sizeof(unsigned) ? uint_type
: ulong_long_type),
unsigned long, ulong_type)
Expand All @@ -777,7 +776,7 @@ FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
template <typename C, typename Char,
FMT_ENABLE_IF(std::is_same<typename C::char_type, Char>::value)>
FMT_CONSTEXPR init<C, int, char_type> make_value(Char val) {
return val;
return {val};
}

template <typename C,
Expand Down Expand Up @@ -1129,9 +1128,8 @@ template <typename Context, typename... Args> class format_arg_store {
// Packed is a macro on MinGW so use IS_PACKED instead.
static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args;

using value_type =
typename std::conditional<IS_PACKED, internal::value<Context>,
basic_format_arg<Context>>::type;
using value_type = conditional_t<IS_PACKED, internal::value<Context>,
basic_format_arg<Context>>;

// If the arguments are not packed, add one more element to mark the end.
static const size_t DATA_SIZE =
Expand Down Expand Up @@ -1274,7 +1272,7 @@ template <typename Context> class basic_format_args {
};

/** An alias to ``basic_format_args<context>``. */
// It is a separate type rather than a typedef to make symbols readable.
// It is a separate type rather than an alias to make symbols readable.
struct format_args : basic_format_args<format_context> {
template <typename... Args>
format_args(Args&&... arg)
Expand Down Expand Up @@ -1385,6 +1383,8 @@ struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
: is_contiguous<Container> {};

/** Formats a string and writes the output to ``out``. */
// GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with
// vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead.
template <typename OutputIt, typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(is_contiguous_back_insert_iterator<OutputIt>::value)>
OutputIt vformat_to(OutputIt out, const S& format_str,
Expand Down
3 changes: 2 additions & 1 deletion include/fmt/format-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,8 @@ template <int GRISU_VERSION> struct grisu_shortest_handler {
}
};

template <typename Double, enable_if_t<sizeof(Double) == sizeof(uint64_t), int>>
template <typename Double,
enable_if_t<(sizeof(Double) == sizeof(uint64_t)), int>>
FMT_API bool grisu_format(Double value, buffer<char>& buf, int precision,
unsigned options, int& exp) {
FMT_ASSERT(value >= 0, "value is negative");
Expand Down
21 changes: 12 additions & 9 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ void buffer<T>::append(const U* begin, const U* end) {
// A UTF-8 code unit type.
enum char8_t : unsigned char {};
#endif
template <> struct is_char<char8_t> : std::true_type {};

// A UTF-8 string view.
class u8string_view : public basic_string_view<char8_t> {
Expand Down Expand Up @@ -702,8 +703,8 @@ FMT_CONSTEXPR bool is_negative(T) {
template <typename T> struct int_traits {
// Smallest of uint32_t and uint64_t that is large enough to represent
// all values of T.
typedef typename std::conditional<std::numeric_limits<T>::digits <= 32,
uint32_t, uint64_t>::type main_type;
using main_type =
conditional_t<std::numeric_limits<T>::digits <= 32, uint32_t, uint64_t>;
};

// Static data is placed in this class template to allow header-only
Expand Down Expand Up @@ -2036,7 +2037,7 @@ template <typename Char, typename Handler>
FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end,
Handler&& handler) {
++begin;
auto c = begin != end ? *begin : 0;
auto c = begin != end ? *begin : Char();
if ('0' <= c && c <= '9') {
handler.on_precision(parse_nonnegative_int(begin, end, handler));
} else if (c == '{') {
Expand Down Expand Up @@ -2191,9 +2192,10 @@ FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs(
ParseContext& ctx) {
// GCC 7.2 requires initializer.
typedef typename ParseContext::char_type char_type;
typename std::conditional<is_formattable<T, format_context>::value,
formatter<T, char_type>,
internal::fallback_formatter<T, char_type>>::type f;
conditional_t<is_formattable<T, format_context>::value,
formatter<T, char_type>,
internal::fallback_formatter<T, char_type>>
f;
return f.parse(ctx);
}

Expand Down Expand Up @@ -2257,7 +2259,7 @@ FMT_CONSTEXPR bool do_check_format_string(basic_string_view<Char> s,
}

template <typename... Args, typename S,
enable_if_t<is_compile_string<S>::value, int>>
enable_if_t<(is_compile_string<S>::value), int>>
void check_format_string(S format_str) {
typedef typename S::char_type char_t;
FMT_CONSTEXPR_DECL bool invalid_format =
Expand Down Expand Up @@ -2774,8 +2776,9 @@ template <typename Range> class basic_writer {
auto&& it = reserve(1);
*it++ = value;
}
void write(wchar_t value) {
static_assert(std::is_same<char_type, wchar_t>::value, "");

template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char_type>::value)>
void write(Char value) {
auto&& it = reserve(1);
*it++ = value;
}
Expand Down
10 changes: 4 additions & 6 deletions include/fmt/prepare.h
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,8 @@ template <typename Format> class compiletime_prepared_parts_type_provider {
typedef format_part<char_type> value_type;
};

typedef typename std::conditional<static_cast<bool>(number_of_format_parts),
format_parts_array<number_of_format_parts>,
empty>::type type;
using type = conditional_t<static_cast<bool>(number_of_format_parts),
format_parts_array<number_of_format_parts>, empty>;
};

template <typename Parts> class compiletime_prepared_parts_collector {
Expand Down Expand Up @@ -674,9 +673,8 @@ struct compiletime_format_tag {};
struct runtime_format_tag {};

template <typename Format> struct format_tag {
typedef typename std::conditional<is_compile_string<Format>::value,
compiletime_format_tag,
runtime_format_tag>::type type;
using type = conditional_t<is_compile_string<Format>::value,
compiletime_format_tag, runtime_format_tag>;
};

#if FMT_USE_CONSTEXPR
Expand Down
9 changes: 4 additions & 5 deletions include/fmt/printf.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,14 @@ class arg_converter : public function<void> {
template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)>
void operator()(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
typedef typename std::conditional<std::is_same<T, void>::value, U, T>::type
TargetType;
if (const_check(sizeof(TargetType) <= sizeof(int))) {
using target_type = conditional_t<std::is_same<T, void>::value, U, T>;
if (const_check(sizeof(target_type) <= sizeof(int))) {
// Extra casts are used to silence warnings.
if (is_signed) {
arg_ = internal::make_arg<Context>(
static_cast<int>(static_cast<TargetType>(value)));
static_cast<int>(static_cast<target_type>(value)));
} else {
typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
typedef typename make_unsigned_or_bool<target_type>::type Unsigned;
arg_ = internal::make_arg<Context>(
static_cast<unsigned>(static_cast<Unsigned>(value)));
}
Expand Down
10 changes: 5 additions & 5 deletions include/fmt/ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ template <typename T, typename _ = void> struct is_range_ : std::false_type {};

#if !FMT_MSC_VER || FMT_MSC_VER > 1800
template <typename T>
struct is_range_<T, typename std::conditional<
false,
conditional_helper<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>,
void>::type> : std::true_type {};
struct is_range_<
T, conditional_t<false,
conditional_helper<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end())>,
void>> : std::true_type {};
#endif

/// tuple_size and tuple_element check.
Expand Down
18 changes: 18 additions & 0 deletions test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2492,3 +2492,21 @@ TEST(FormatTest, CharTraitsIsNotAmbiguous) {
(void)lval;
#endif
}

struct mychar {
int value;
mychar() = default;
mychar(char val) : value(val) {}
operator int() const { return value; }
};

FMT_BEGIN_NAMESPACE
template <> struct is_char<mychar> : std::true_type {};
FMT_END_NAMESPACE

TEST(FormatTest, FormatCustomChar) {
const mychar format[] = {'{', '}', 0};
auto result = fmt::format(format, mychar('x'));
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0], mychar('x'));
}

0 comments on commit 55da271

Please sign in to comment.