Skip to content

Commit

Permalink
Merge branch 'fmtlib:master' into zig-pkg
Browse files Browse the repository at this point in the history
  • Loading branch information
kassane committed Apr 16, 2024
2 parents 2ed0fd0 + aa52eb7 commit e1c9dd1
Show file tree
Hide file tree
Showing 29 changed files with 751 additions and 342 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cifuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
dry-run: false
language: c++
- name: Upload Crash
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: SARIF file
path: results.sarif
retention-days: 5

# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2
uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
with:
sarif_file: results.sarif
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ math(EXPR CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
math(EXPR CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
join(FMT_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.
${CPACK_PACKAGE_VERSION_PATCH})
message(STATUS "Version: ${FMT_VERSION}")
message(STATUS "{fmt} version: ${FMT_VERSION}")

message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")

Expand Down
4 changes: 2 additions & 2 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,15 @@ without implementing them yourself. For example::
// parse is inherited from formatter<string_view>.

auto format(color c, format_context& ctx) const
-> format_parse_context::iterator;
-> format_context::iterator;
};

// color.cc:
#include "color.h"
#include <fmt/format.h>

auto fmt::formatter<color>::format(color c, format_context& ctx) const
-> format_parse_context::iterator {
-> format_context::iterator {
string_view name = "unknown";
switch (c) {
case color::red: name = "red"; break;
Expand Down
37 changes: 31 additions & 6 deletions doc/syntax.rst
Original file line number Diff line number Diff line change
Expand Up @@ -491,14 +491,33 @@ Range Format Specifications
Format specifications for range types have the following syntax:

.. productionlist:: sf
range_format_spec: [":" [`underlying_spec`]]
range_format_spec: ["n"][`range_type`][`range_underlying_spec`]

The `underlying_spec` is parsed based on the formatter of the range's
reference type.
The ``'n'`` option formats the range without the opening and closing brackets.

By default, a range of characters or strings is printed escaped and quoted. But
if any `underlying_spec` is provided (even if it is empty), then the characters
or strings are printed according to the provided specification.
The available presentation types for `range_type` are:

+---------+----------------------------------------------------------+
| Type | Meaning |
+=========+==========================================================+
| none | Default format. |
+---------+----------------------------------------------------------+
| ``'s'`` | String format. The range is formatted as a string. |
+---------+----------------------------------------------------------+
| ``'?s'``| Debug format. The range is formatted as an escaped |
| | string. |
+---------+----------------------------------------------------------+

If `range_type` is ``'s'`` or ``'?s'``, the range element type must be a
character type. The ``'n'`` option and `range_underlying_spec` are mutually
exclusive with ``'s'`` and ``'?s'``.

The `range_underlying_spec` is parsed based on the formatter of the range's
element type.

By default, a range of characters or strings is printed escaped and quoted.
But if any `range_underlying_spec` is provided (even if it is empty), then
the characters or strings are printed according to the provided specification.

Examples::

Expand All @@ -508,6 +527,12 @@ Examples::
// Result: [0xa, 0x14, 0x1e]
fmt::format("{}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: ['h', 'e', 'l', 'l', 'o']
fmt::format("{:n}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: 'h', 'e', 'l', 'l', 'o'
fmt::format("{:s}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: "hello"
fmt::format("{:?s}", vector{'h', 'e', 'l', 'l', 'o', '\n'});
// Result: "hello\n"
fmt::format("{::}", vector{'h', 'e', 'l', 'l', 'o'});
// Result: [h, e, l, l, o]
fmt::format("{::d}", vector{'h', 'e', 'l', 'l', 'o'});
Expand Down
4 changes: 2 additions & 2 deletions doc/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ On Mac OS X with Xcode installed, an :file:`.xcodeproj` file will be generated.
To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to
``TRUE``::

cmake -DBUILD_SHARED_LIBS=TRUE ...
cmake -DBUILD_SHARED_LIBS=TRUE ..

__ https://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries

Expand All @@ -57,7 +57,7 @@ To build a `static library` with position independent code (required if the main
consumer of the fmt library is a shared library i.e. a Python extension) set the
``CMAKE_POSITION_INDEPENDENT_CODE`` CMake variable to ``TRUE``::

cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ...
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ..


Installing the Library
Expand Down
8 changes: 5 additions & 3 deletions include/fmt/args.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
#ifndef FMT_ARGS_H_
#define FMT_ARGS_H_

#include <functional> // std::reference_wrapper
#include <memory> // std::unique_ptr
#include <vector>
#ifndef FMT_IMPORT_STD
# include <functional> // std::reference_wrapper
# include <memory> // std::unique_ptr
# include <vector>
#endif

#include "format.h" // std_string_view

Expand Down
99 changes: 64 additions & 35 deletions include/fmt/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
#include <stdio.h> // FILE
#include <string.h> // strlen

#ifndef FMT_IMPORT_STD
// <cstddef> is also included transitively from <type_traits>.
#include <cstddef> // std::byte
#include <type_traits> // std::enable_if
# include <cstddef> // std::byte
# include <type_traits> // std::enable_if
#else
import std;
#endif

// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 100202
Expand Down Expand Up @@ -175,8 +179,7 @@
#endif

// Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings.
#if FMT_HAS_CPP_ATTRIBUTE(noreturn) && FMT_EXCEPTIONS && !FMT_MSC_VERSION && \
!defined(__NVCC__)
#if FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && !defined(__NVCC__)
# define FMT_NORETURN [[noreturn]]
#else
# define FMT_NORETURN
Expand Down Expand Up @@ -1162,6 +1165,20 @@ using appender = basic_appender<char>;

namespace detail {

template <typename T, typename Enable = void>
struct locking : std::true_type {};
template <typename T>
struct locking<T, void_t<typename formatter<remove_cvref_t<T>>::nonlocking>>
: std::false_type {};

template <typename T = int> FMT_CONSTEXPR inline auto is_locking() -> bool {
return locking<T>::value;
}
template <typename T1, typename T2, typename... Tail>
FMT_CONSTEXPR inline auto is_locking() -> bool {
return locking<T1>::value || is_locking<T2, Tail...>();
}

// An optimized version of std::copy with the output value type (T).
template <typename T, typename InputIt>
auto copy(InputIt begin, InputIt end, appender out) -> appender {
Expand Down Expand Up @@ -1491,12 +1508,14 @@ template <typename Context> struct arg_mapper {
return {};
}

// is_fundamental is used to allow formatters for extended FP types.
template <typename T, typename U = remove_const_t<T>,
FMT_ENABLE_IF((std::is_class<U>::value || std::is_enum<U>::value ||
std::is_union<U>::value) &&
!has_to_string_view<U>::value && !is_char<U>::value &&
!is_named_arg<U>::value &&
!std::is_arithmetic<format_as_t<U>>::value)>
FMT_ENABLE_IF(
(std::is_class<U>::value || std::is_enum<U>::value ||
std::is_union<U>::value || std::is_fundamental<U>::value) &&
!has_to_string_view<U>::value && !is_char<U>::value &&
!is_named_arg<U>::value && !std::is_integral<U>::value &&
!std::is_arithmetic<format_as_t<U>>::value)>
FMT_MAP_API auto map(T& val) -> decltype(FMT_DECLTYPE_THIS do_map(val)) {
return do_map(val);
}
Expand Down Expand Up @@ -2738,7 +2757,9 @@ template <typename Char, typename... Args> class format_string_checker {
return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin;
}

FMT_CONSTEXPR void on_error(const char* message) { report_error(message); }
FMT_NORETURN FMT_CONSTEXPR void on_error(const char* message) {
report_error(message);
}
};

// A base class for compile-time strings.
Expand Down Expand Up @@ -2783,33 +2804,25 @@ FMT_API void vprint_mojibake(FILE*, string_view, format_args, bool = false);
#ifndef _WIN32
inline void vprint_mojibake(FILE*, string_view, format_args, bool) {}
#endif
} // namespace detail

FMT_BEGIN_EXPORT

// A formatter specialization for natively supported types.
template <typename T, typename Char>
struct formatter<T, Char,
enable_if_t<detail::type_constant<T, Char>::value !=
detail::type::custom_type>> {
template <typename T, typename Char, type TYPE> struct native_formatter {
private:
detail::dynamic_format_specs<Char> specs_;
dynamic_format_specs<Char> specs_;

public:
using nonlocking = void;

template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* {
if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin();
auto type = detail::type_constant<T, Char>::value;
auto end =
detail::parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, type);
if (type == detail::type::char_type) detail::check_char_specs(specs_);
auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, TYPE);
if (const_check(TYPE == type::char_type)) check_char_specs(specs_);
return end;
}

template <detail::type U = detail::type_constant<T, Char>::value,
FMT_ENABLE_IF(U == detail::type::string_type ||
U == detail::type::cstring_type ||
U == detail::type::char_type)>
template <type U = TYPE,
FMT_ENABLE_IF(U == type::string_type || U == type::cstring_type ||
U == type::char_type)>
FMT_CONSTEXPR void set_debug_format(bool set = true) {
specs_.type = set ? presentation_type::debug : presentation_type::none;
}
Expand All @@ -2818,6 +2831,17 @@ struct formatter<T, Char,
FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const
-> decltype(ctx.out());
};
} // namespace detail

FMT_BEGIN_EXPORT

// A formatter specialization for natively supported types.
template <typename T, typename Char>
struct formatter<T, Char,
enable_if_t<detail::type_constant<T, Char>::value !=
detail::type::custom_type>>
: detail::native_formatter<T, Char, detail::type_constant<T, Char>::value> {
};

template <typename Char = char> struct runtime_format_string {
basic_string_view<Char> str;
Expand Down Expand Up @@ -2945,8 +2969,8 @@ template <typename OutputIt, typename Sentinel = OutputIt>
struct format_to_result {
/** Iterator pointing to just after the last successful write in the range. */
OutputIt out;
/** Sentinel indicating the end of the output range. */
Sentinel out_last;
/** Specifies if the output was truncated. */
bool truncated;

FMT_CONSTEXPR operator OutputIt&() & noexcept { return out; }
FMT_CONSTEXPR operator const OutputIt&() const& noexcept { return out; }
Expand All @@ -2958,13 +2982,15 @@ struct format_to_result {
template <size_t N>
auto vformat_to(char (&out)[N], string_view fmt, format_args args)
-> format_to_result<char*> {
return {vformat_to_n(out, N, fmt, args).out, out + N};
auto result = vformat_to_n(out, N, fmt, args);
return {result.out, result.size > N};
}

template <size_t N, typename... T>
FMT_INLINE auto format_to(char (&out)[N], format_string<T...> fmt, T&&... args)
-> format_to_result<char*> {
return vformat_to(out, fmt, fmt::make_format_args(args...));
auto result = fmt::format_to_n(out, N, fmt, static_cast<T&&>(args)...);
return {result.out, result.size > N};
}

/** Returns the number of chars in the output of ``format(fmt, args...)``. */
Expand All @@ -2978,6 +3004,7 @@ FMT_NODISCARD FMT_INLINE auto formatted_size(format_string<T...> fmt,

FMT_API void vprint(string_view fmt, format_args args);
FMT_API void vprint(FILE* f, string_view fmt, format_args args);
FMT_API void vprint_locked(FILE* f, string_view fmt, format_args args);
FMT_API void vprintln(FILE* f, string_view fmt, format_args args);

/**
Expand All @@ -2993,8 +3020,9 @@ FMT_API void vprintln(FILE* f, string_view fmt, format_args args);
template <typename... T>
FMT_INLINE void print(format_string<T...> fmt, T&&... args) {
const auto& vargs = fmt::make_format_args(args...);
return detail::is_utf8() ? vprint(fmt, vargs)
: detail::vprint_mojibake(stdout, fmt, vargs);
if (!detail::is_utf8()) return detail::vprint_mojibake(stdout, fmt, vargs);
return detail::is_locking<T...>() ? vprint(fmt, vargs)
: vprint_locked(stdout, fmt, vargs);
}

/**
Expand All @@ -3010,8 +3038,9 @@ FMT_INLINE void print(format_string<T...> fmt, T&&... args) {
template <typename... T>
FMT_INLINE void print(FILE* f, format_string<T...> fmt, T&&... args) {
const auto& vargs = fmt::make_format_args(args...);
return detail::is_utf8() ? vprint(f, fmt, vargs)
: detail::vprint_mojibake(f, fmt, vargs);
if (!detail::is_utf8()) return detail::vprint_mojibake(f, fmt, vargs);
return detail::is_locking<T...>() ? vprint(f, fmt, vargs)
: vprint_locked(f, fmt, vargs);
}

/**
Expand Down
Loading

0 comments on commit e1c9dd1

Please sign in to comment.