Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
medithe authored Aug 12, 2020
2 parents 4d6038b + 4b69c78 commit d44ba72
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 47 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
-Wctor-dtor-privacy -Wdisabled-optimization
-Winvalid-pch -Woverloaded-virtual
-Wconversion -Wswitch-enum
-Wno-ctor-dtor-privacy -Wno-format-nonliteral -Wno-shadow)
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept
-Wno-dangling-else -Wno-unused-local-typedefs)
Expand Down
17 changes: 17 additions & 0 deletions ChangeLog.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
7.0.3 - 2020-08-06
------------------

* Worked around broken ``numeric_limits`` for 128-bit integers
(`#1787 <https://github.com/fmtlib/fmt/issues/1787>`_).

* Added error reporting on missing named arguments
(`#1796 <https://github.com/fmtlib/fmt/issues/1796>`_).

* Stopped using 128-bit integers with clang-cl
(`#1800 <https://github.com/fmtlib/fmt/pull/1800>`_).
Thanks `@Kingcom <https://github.com/Kingcom>`_.

* Fixed issues in locale-specific integer formatting
(`#1782 <https://github.com/fmtlib/fmt/issues/1782>`_,
`#1801 <https://github.com/fmtlib/fmt/issues/1801>`_).

7.0.2 - 2020-07-29
------------------

Expand Down
17 changes: 11 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ Features
* Small code size both in terms of source code with the minimum configuration
consisting of just three files, ``core.h``, ``format.h`` and ``format-inl.h``,
and compiled code; see `Compile time and code bloat`_
* Reliability: the library has an extensive set of `unit tests
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is continuously fuzzed
* Reliability: the library has an extensive set of `tests
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is `continuously fuzzed
<https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20
Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dlibfmt&can=1>`_
* Safety: the library is fully type safe, errors in format strings can be
reported at compile time, automatic memory management prevents buffer overflow
errors
Expand Down Expand Up @@ -109,7 +111,7 @@ Output::
Default format: 42s 100ms
strftime-like format: 03:15:30

**Print a container**
**Print a container** (`run <https://godbolt.org/z/MjsY7c>`_)

.. code:: c++

Expand Down Expand Up @@ -145,9 +147,10 @@ a string.
out.print("Don't {}", "Panic");
}

This is up to 6x faster than glibc's ``fprintf``.
This can be `5 to 9 times faster than fprintf
<http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html>`_.

**Color support**
**Print with colors and text styles**

.. code:: c++

Expand All @@ -162,7 +165,7 @@ This is up to 6x faster than glibc's ``fprintf``.
"Hello, {}!\n", "世界");
}

prints the following on a modern terminal:
Output on a modern terminal:

.. image:: https://user-images.githubusercontent.com/
576385/88485597-d312f600-cf2b-11ea-9cbe-61f535a86e28.png
Expand Down Expand Up @@ -342,6 +345,8 @@ Projects using this library

* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance,
associative database

* `Quill <https://github.com/odygrd/quill>`_: Asynchronous low-latency logging library

* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable

Expand Down
2 changes: 1 addition & 1 deletion doc/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
from distutils.version import LooseVersion

versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2']
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3']

def pip_install(package, commit=None, **kwargs):
"Install package using pip."
Expand Down
17 changes: 10 additions & 7 deletions include/fmt/compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,8 @@ template <typename... Args> struct type_list {};

// Returns a reference to the argument at index N from [first, rest...].
template <int N, typename T, typename... Args>
constexpr const auto& get(const T& first, const Args&... rest) {
constexpr const auto& get([[maybe_unused]] const T& first,
[[maybe_unused]] const Args&... rest) {
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
if constexpr (N == 0)
return first;
Expand Down Expand Up @@ -443,7 +444,8 @@ template <typename Char, typename T, int N> struct spec_field {
OutputIt format(OutputIt out, const Args&... args) const {
// This ensures that the argument type is convertile to `const T&`.
const T& arg = get<N>(args...);
basic_format_context<OutputIt, Char> ctx(out, {});
const auto& vargs = make_format_args(args...);
basic_format_context<OutputIt, Char> ctx(out, vargs);
return fmt.format(arg, ctx);
}
};
Expand Down Expand Up @@ -502,16 +504,17 @@ constexpr auto parse_tail(T head, S format_str) {
template <typename T, typename Char> struct parse_specs_result {
formatter<T, Char> fmt;
size_t end;
int next_arg_id;
};

template <typename T, typename Char>
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
size_t pos) {
size_t pos, int arg_id) {
str.remove_prefix(pos);
auto ctx = basic_format_parse_context<Char>(str);
auto ctx = basic_format_parse_context<Char>(str, {}, arg_id + 1);
auto f = formatter<T, Char>();
auto end = f.parse(ctx);
return {f, pos + (end - str.data()) + 1};
return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()};
}

// Compiles a non-empty format string and returns the compiled representation
Expand All @@ -531,8 +534,8 @@ constexpr auto compile_format_string(S format_str) {
format_str);
} else if constexpr (str[POS + 1] == ':') {
using type = get_type<ID, Args>;
constexpr auto result = parse_specs<type>(str, POS + 2);
return parse_tail<Args, result.end, ID + 1>(
constexpr auto result = parse_specs<type>(str, POS + 2, ID);
return parse_tail<Args, result.end, result.next_arg_id>(
spec_field<char_type, type, ID>{result.fmt}, format_str);
} else {
return unknown_format();
Expand Down
20 changes: 11 additions & 9 deletions include/fmt/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <vector>

// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 70002
#define FMT_VERSION 70003

#ifdef __clang__
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
Expand Down Expand Up @@ -298,7 +298,8 @@ template <typename T> struct std_string_view {};

#ifdef FMT_USE_INT128
// Do nothing.
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && !(FMT_CLANG_VERSION && FMT_MSC_VER)
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
!(FMT_CLANG_VERSION && FMT_MSC_VER)
# define FMT_USE_INT128 1
using int128_t = __int128_t;
using uint128_t = __uint128_t;
Expand Down Expand Up @@ -556,8 +557,9 @@ class basic_format_parse_context : private ErrorHandler {
using iterator = typename basic_string_view<Char>::iterator;

explicit constexpr basic_format_parse_context(
basic_string_view<Char> format_str, ErrorHandler eh = {})
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
basic_string_view<Char> format_str, ErrorHandler eh = {},
int next_arg_id = 0)
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {}

/**
Returns an iterator to the beginning of the format string range being
Expand Down Expand Up @@ -765,13 +767,13 @@ class iterator_buffer : public Traits, public buffer<T> {
T data_[buffer_size];

protected:
void grow(size_t) final {
void grow(size_t) final FMT_OVERRIDE {
if (this->size() == buffer_size) flush();
}
void flush();

public:
explicit iterator_buffer(OutputIt out, size_t n = 0)
explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
: Traits(n),
buffer<T>(data_, 0, n < size_t(buffer_size) ? n : size_t(buffer_size)),
out_(out) {}
Expand All @@ -786,7 +788,7 @@ class iterator_buffer : public Traits, public buffer<T> {

template <typename T> class iterator_buffer<T*, T> : public buffer<T> {
protected:
void grow(size_t) final {}
void grow(size_t) final FMT_OVERRIDE {}

public:
explicit iterator_buffer(T* out, size_t = 0) : buffer<T>(out, 0, ~size_t()) {}
Expand All @@ -804,7 +806,7 @@ class iterator_buffer<std::back_insert_iterator<Container>,
Container& container_;

protected:
void grow(size_t capacity) final {
void grow(size_t capacity) final FMT_OVERRIDE {
container_.resize(capacity);
this->set(&container_[0], capacity);
}
Expand All @@ -827,7 +829,7 @@ template <typename T = char> class counting_buffer : public buffer<T> {
size_t count_ = 0;

protected:
void grow(size_t) final {
void grow(size_t) final FMT_OVERRIDE {
if (this->size() != buffer_size) return;
count_ += this->size();
this->clear();
Expand Down
19 changes: 6 additions & 13 deletions include/fmt/format-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
FMT_FUNC int safe_strerror(int error_code, char*& buffer,
size_t buffer_size) FMT_NOEXCEPT {
inline int safe_strerror(int error_code, char*& buffer,
size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != nullptr && buffer_size != 0, "invalid buffer");

class dispatcher {
Expand Down Expand Up @@ -173,8 +173,8 @@ FMT_FUNC void report_error(format_func func, int error_code,
}

// A wrapper around fwrite that throws on error.
FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count,
FILE* stream) {
inline void fwrite_fully(const void* ptr, size_t size, size_t count,
FILE* stream) {
size_t written = std::fwrite(ptr, size, count, stream);
if (written < count) FMT_THROW(system_error(errno, "cannot write to file"));
}
Expand Down Expand Up @@ -263,13 +263,6 @@ const typename basic_data<T>::digit_pair basic_data<T>::digits[] = {
template <typename T>
const char basic_data<T>::hex_digits[] = "0123456789abcdef";

template <typename T>
const uint16_t basic_data<T>::bsr2log10[] = {
1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};

#define FMT_POWERS_OF_10(factor) \
factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \
(factor)*1000000, (factor)*10000000, (factor)*100000000, \
Expand Down Expand Up @@ -1131,7 +1124,7 @@ int format_float(T value, int precision, float_specs specs, buffer<char>& buf) {
if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error)
return snprintf_float(value, precision, specs, buf);
int num_digits = handler.size;
if (!fixed) {
if (!fixed && !specs.showpoint) {
// Remove trailing zeros.
while (num_digits > 0 && buf[num_digits - 1] == '0') {
--num_digits;
Expand Down Expand Up @@ -1264,7 +1257,7 @@ int snprintf_float(T value, int precision, float_specs specs,
* occurs, this pointer will be a guess that depends on the particular
* error, but it will always advance at least one byte.
*/
FMT_FUNC const char* utf8_decode(const char* buf, uint32_t* c, int* e) {
inline const char* utf8_decode(const char* buf, uint32_t* c, int* e) {
static const char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 2, 2, 2, 2, 3, 3, 4, 0};
Expand Down
33 changes: 25 additions & 8 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,13 @@ FMT_END_NAMESPACE
#endif

#ifndef FMT_USE_UDL_TEMPLATE
// EDG frontend based compilers (icc, nvcc, etc) and GCC < 6.4 do not properly
// support UDL templates and GCC >= 9 warns about them.
// EDG frontend based compilers (icc, nvcc, PGI, etc) and GCC < 6.4 do not
// properly support UDL templates and GCC >= 9 warns about them.
# if FMT_USE_USER_DEFINED_LITERALS && \
(!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 501) && \
((FMT_GCC_VERSION >= 604 && __cplusplus >= 201402L) || \
FMT_CLANG_VERSION >= 304)
FMT_CLANG_VERSION >= 304) && \
!defined(__PGI)
# define FMT_USE_UDL_TEMPLATE 1
# else
# define FMT_USE_UDL_TEMPLATE 0
Expand Down Expand Up @@ -622,7 +623,7 @@ class basic_memory_buffer : public detail::buffer<T> {
}

protected:
void grow(size_t size) final;
void grow(size_t size) final FMT_OVERRIDE;

public:
using value_type = T;
Expand Down Expand Up @@ -685,6 +686,13 @@ class basic_memory_buffer : public detail::buffer<T> {

/** Increases the buffer capacity to *new_capacity*. */
void reserve(size_t new_capacity) { this->try_reserve(new_capacity); }

// Directly append data into the buffer
using detail::buffer<T>::append;
template <typename ContiguousRange>
void append(const ContiguousRange& range) {
append(range.data(), range.data() + range.size());
}
};

template <typename T, size_t SIZE, typename Allocator>
Expand Down Expand Up @@ -770,8 +778,6 @@ using uint32_or_64_or_128_t =

// Static data is placed in this class template for the header-only config.
template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {
// Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)).
static const uint16_t bsr2log10[];
static const uint64_t powers_of_10_64[];
static const uint32_t zero_or_powers_of_10_32[];
static const uint64_t zero_or_powers_of_10_64[];
Expand All @@ -790,6 +796,17 @@ template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {
static const char right_padding_shifts[5];
};

// Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)).
// This is a function instead of an array to workaround a bug in GCC10 (#1810).
FMT_INLINE uint16_t bsr2log10(int bsr) {
constexpr uint16_t data[] = {
1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
return data[bsr];
}

#ifndef FMT_EXPORTED
FMT_EXTERN template struct basic_data<void>;
#endif
Expand All @@ -802,7 +819,7 @@ struct data : basic_data<> {};
// except for n == 0 in which case count_digits returns 1.
inline int count_digits(uint64_t n) {
// https://github.com/fmtlib/format-benchmark/blob/master/digits10
auto t = data::bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63];
auto t = bsr2log10(FMT_BUILTIN_CLZLL(n | 1) ^ 63);
return t - (n < data::zero_or_powers_of_10_64[t]);
}
#else
Expand Down Expand Up @@ -860,7 +877,7 @@ template <> int count_digits<4>(detail::fallback_uintptr n);
#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
inline int count_digits(uint32_t n) {
auto t = data::bsr2log10[FMT_BUILTIN_CLZ(n | 1) ^ 31];
auto t = bsr2log10(FMT_BUILTIN_CLZ(n | 1) ^ 31);
return t - (n < data::zero_or_powers_of_10_32[t]);
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion include/fmt/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ struct buffer_size {

struct ostream_params {
int oflag = file::WRONLY | file::CREATE;
size_t buffer_size = BUFSIZ > 65536 ? BUFSIZ : 65536;
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;

ostream_params() {}

Expand Down
5 changes: 5 additions & 0 deletions test/compile-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ TEST(CompileTest, FormatSpecs) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
}

TEST(CompileTest, DynamicWidth) {
EXPECT_EQ(" 42foo ",
fmt::format(FMT_COMPILE("{:{}}{:{}}"), 42, 4, "foo", 5));
}

TEST(CompileTest, FormatTo) {
char buf[8];
auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
Expand Down
Loading

0 comments on commit d44ba72

Please sign in to comment.