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 May 17, 2019
2 parents 7dd1d80 + 5e7bdf1 commit 63e7b9e
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 86 deletions.
3 changes: 1 addition & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@ if (HAVE_OPEN)
set(FMT_SOURCES ${FMT_SOURCES} src/posix.cc)
endif ()

add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} include/format README.rst
ChangeLog.rst)
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
add_library(fmt::fmt ALIAS fmt)

if (FMT_WERROR)
Expand Down
27 changes: 14 additions & 13 deletions include/fmt/format-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -647,29 +647,30 @@ template <int GRISU_VERSION> struct grisu_shortest_handler {
return digits::more;
}

// This implements Grisu3's round_weed.
// Decrement the generated number approaching value from above.
void round(uint64_t d, uint64_t divisor, uint64_t& remainder,
uint64_t error) {
while (remainder < d && error - remainder >= divisor &&
(remainder + divisor < d ||
d - remainder >= remainder + divisor - d)) {
--buf[size - 1];
remainder += divisor;
}
}

// Implements Grisu's round_weed.
digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder,
uint64_t error, int exp, bool integral) {
buf[size++] = digit;
if (remainder >= error) return digits::more;
if (GRISU_VERSION != 3) {
uint64_t d = integral ? diff : diff * data::POWERS_OF_10_64[-exp];
while (remainder < d && error - remainder >= divisor &&
(remainder + divisor < d ||
d - remainder >= remainder + divisor - d)) {
--buf[size - 1];
remainder += divisor;
}
round(d, divisor, remainder, error);
return digits::done;
}
uint64_t unit = integral ? 1 : data::POWERS_OF_10_64[-exp];
uint64_t up = (diff - 1) * unit; // wp_Wup
while (remainder < up && error - remainder >= divisor &&
(remainder + divisor < up ||
up - remainder >= remainder + divisor - up)) {
--buf[size - 1];
remainder += divisor;
}
round(up, divisor, remainder, error);
uint64_t down = (diff + 1) * unit; // wp_Wdown
if (remainder < down && error - remainder >= divisor &&
(remainder + divisor < down ||
Expand Down
28 changes: 0 additions & 28 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3047,34 +3047,6 @@ class format_int {
std::string str() const { return std::string(str_, size()); }
};

// Formats a decimal integer value writing into buffer and returns
// a pointer to the end of the formatted string. This function doesn't
// write a terminating null character.
template <typename T>
FMT_DEPRECATED inline void format_decimal(char*& buffer, T value) {
typedef typename internal::int_traits<T>::main_type main_type;
main_type abs_value = static_cast<main_type>(value);
if (internal::is_negative(value)) {
*buffer++ = '-';
abs_value = 0 - abs_value;
}
if (abs_value < 100) {
if (abs_value < 10) {
*buffer++ = static_cast<char>('0' + abs_value);
return;
}
unsigned index = static_cast<unsigned>(abs_value * 2);
*buffer++ = internal::data::DIGITS[index];
*buffer++ = internal::data::DIGITS[index + 1];
return;
}
int num_digits = internal::count_digits(abs_value);
internal::format_decimal<char>(
internal::make_checked(buffer, internal::to_unsigned(num_digits)),
abs_value, num_digits);
buffer += num_digits;
}

// Formatter of objects of type T.
template <typename T, typename Char>
struct formatter<T, Char,
Expand Down
20 changes: 20 additions & 0 deletions support/Vagrantfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :

# A vagrant config for testing against gcc-4.4.
Vagrant.configure("2") do |config|
config.vm.box = "bento/ubuntu-10.04"

config.vm.provider "virtualbox" do |vb|
vb.memory = "4096"
end

config.vm.provision "shell", inline: <<-SHELL
sed -i 's/us.archive/old-releases/' /etc/apt/sources.list
apt-get update
apt-get install -y g++ make wget
wget -q https://www.dropbox.com/s/ssvomsla6bkx2wl/cmake-3.14.4-Linux-x86_64.tar.gz
tar xzf cmake-3.14.4-Linux-x86_64.tar.gz
ln -s `pwd`/cmake-3.14.4-Linux-x86_64/bin/cmake /usr/local/bin
SHELL
end
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ add_fmt_test(prepare-test)
add_fmt_test(printf-test)
add_fmt_test(custom-formatter-test)
add_fmt_test(ranges-test)
add_fmt_test(scan-test)

# MSVC fails to compile GMock when C++17 is enabled.
if (FMT_HAS_VARIANT AND NOT MSVC)
Expand Down
File renamed without changes.
43 changes: 0 additions & 43 deletions test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1745,49 +1745,6 @@ TEST(FormatIntTest, FormatInt) {
fmt::format_int(std::numeric_limits<int64_t>::max()).str());
}

#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

#if FMT_MSC_VER
# pragma warning(push)
# pragma warning(disable : 4996) // Using a deprecated function
#endif

template <typename T> std::string format_decimal(T value) {
char buffer[10];
char* ptr = buffer;
// TODO: Replace with safer, non-deprecated overload
fmt::format_decimal(ptr, value);
return std::string(buffer, ptr);
}

#if FMT_MSC_VER
# pragma warning(pop)
#endif

#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic pop
#endif

TEST(FormatIntTest, FormatDec) {
EXPECT_EQ("-42", format_decimal(static_cast<signed char>(-42)));
EXPECT_EQ("-42", format_decimal(static_cast<short>(-42)));
std::ostringstream os;
os << std::numeric_limits<unsigned short>::max();
EXPECT_EQ(os.str(),
format_decimal(std::numeric_limits<unsigned short>::max()));
EXPECT_EQ("1", format_decimal(1));
EXPECT_EQ("-1", format_decimal(-1));
EXPECT_EQ("42", format_decimal(42));
EXPECT_EQ("-42", format_decimal(-42));
EXPECT_EQ("42", format_decimal(42l));
EXPECT_EQ("42", format_decimal(42ul));
EXPECT_EQ("42", format_decimal(42ll));
EXPECT_EQ("42", format_decimal(42ull));
}

TEST(FormatTest, Print) {
#if FMT_USE_FILE_DESCRIPTORS
EXPECT_WRITE(stdout, fmt::print("Don't {}!", "panic"), "Don't panic!");
Expand Down
100 changes: 100 additions & 0 deletions test/scan-test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Formatting library for C++ - scanning API proof of concept
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.

#include <array>
#include <climits>

#include "fmt/format.h"
#include "gmock.h"
#include "gtest-extra.h"

FMT_BEGIN_NAMESPACE
namespace internal {

struct scan_arg {
int* value;
// TODO: more types
};

template <typename Handler>
void parse_scan_format(string_view format_str, Handler&& handler) {
const char* p = format_str.data();
const char* end = p + format_str.size();
while (p != end) {
char c = *p++;
if (c != '{' || p == end || *p++ != '}')
throw format_error("invalid format string");
handler.on_arg();
}
}
} // namespace internal

struct scan_args {
int size;
const internal::scan_arg* data;

template <size_t N>
scan_args(const std::array<internal::scan_arg, N>& store)
: size(N), data(store.data()) {
static_assert(N < INT_MAX, "too many arguments");
}
};

namespace internal {
struct scan_handler {
const char* begin;
const char* end;
scan_args args;
int next_arg_id;

scan_handler(string_view input, scan_args args)
: begin(input.data()),
end(begin + input.size()),
args(args),
next_arg_id(0) {}

void on_arg() {
int value = 0;
while (begin != end) {
char c = *begin++;
if (c < '0' || c > '9') throw format_error("invalid input");
value = value * 10 + (c - '0');
}
if (next_arg_id >= args.size)
throw format_error("argument index out of range");
*args.data[0].value = value;
}
};
} // namespace internal

void vscan(string_view input, string_view format_str, scan_args args) {
internal::parse_scan_format(format_str, internal::scan_handler(input, args));
}

template <typename... Args>
std::array<internal::scan_arg, sizeof...(Args)> make_scan_args(Args&... args) {
return std::array<internal::scan_arg, sizeof...(Args)>{&args...};
}

template <typename... Args>
void scan(string_view input, string_view format_str, Args&... args) {
vscan(input, format_str, make_scan_args(args...));
}
FMT_END_NAMESPACE

TEST(ScanTest, ReadInt) {
int n = 0;
fmt::scan("42", "{}", n);
EXPECT_EQ(n, 42);
}

TEST(ScanTest, InvalidFormat) {
EXPECT_THROW_MSG(fmt::scan("", "{}"), fmt::format_error,
"argument index out of range");
EXPECT_THROW_MSG(fmt::scan("", "{"), fmt::format_error,
"invalid format string");
}

0 comments on commit 63e7b9e

Please sign in to comment.