mirror of
https://github.com/fmtlib/fmt.git
synced 2024-10-02 04:52:03 +00:00
Support compilation with exceptions disabled
This commit is contained in:
parent
55c61d1abd
commit
8b76e97062
112
format.cc
112
format.cc
@ -54,9 +54,36 @@ using fmt::LongLong;
|
|||||||
using fmt::ULongLong;
|
using fmt::ULongLong;
|
||||||
using fmt::internal::Arg;
|
using fmt::internal::Arg;
|
||||||
|
|
||||||
|
// Check if exceptions are disabled.
|
||||||
|
#if __GNUC__ && !__EXCEPTIONS
|
||||||
|
# define FMT_EXCEPTIONS 0
|
||||||
|
#endif
|
||||||
|
#if _MSC_VER && !_HAS_EXCEPTIONS
|
||||||
|
# define FMT_EXCEPTIONS 0
|
||||||
|
#endif
|
||||||
|
#ifndef FMT_EXCEPTIONS
|
||||||
|
# define FMT_EXCEPTIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FMT_EXCEPTIONS
|
||||||
|
# define FMT_TRY try
|
||||||
|
# define FMT_CATCH(x) catch (x)
|
||||||
|
#else
|
||||||
|
# define FMT_TRY if (true)
|
||||||
|
# define FMT_CATCH(x) if (false)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FMT_THROW
|
||||||
|
# if FMT_EXCEPTIONS
|
||||||
|
# define FMT_THROW(x) throw x
|
||||||
|
# else
|
||||||
|
# define FMT_THROW(x) assert(false)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if _MSC_VER
|
#if _MSC_VER
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable: 4127) // conditional expression is constant
|
# pragma warning(disable: 4127) // conditional expression is constant
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -185,14 +212,15 @@ int parse_nonnegative_int(const Char *&s) {
|
|||||||
value = new_value;
|
value = new_value;
|
||||||
} while ('0' <= *s && *s <= '9');
|
} while ('0' <= *s && *s <= '9');
|
||||||
if (value > INT_MAX)
|
if (value > INT_MAX)
|
||||||
throw fmt::FormatError("number is too big");
|
FMT_THROW(fmt::FormatError("number is too big"));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void require_numeric_argument(const Arg &arg, char spec) {
|
inline void require_numeric_argument(const Arg &arg, char spec) {
|
||||||
if (arg.type > Arg::LAST_NUMERIC_TYPE) {
|
if (arg.type > Arg::LAST_NUMERIC_TYPE) {
|
||||||
throw fmt::FormatError(
|
std::string message =
|
||||||
fmt::format("format specifier '{}' requires numeric argument", spec));
|
fmt::format("format specifier '{}' requires numeric argument", spec);
|
||||||
|
FMT_THROW(fmt::FormatError(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,8 +229,8 @@ void check_sign(const Char *&s, const Arg &arg) {
|
|||||||
char sign = static_cast<char>(*s);
|
char sign = static_cast<char>(*s);
|
||||||
require_numeric_argument(arg, sign);
|
require_numeric_argument(arg, sign);
|
||||||
if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
|
if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
|
||||||
throw fmt::FormatError(fmt::format(
|
FMT_THROW(fmt::FormatError(fmt::format(
|
||||||
"format specifier '{}' requires signed argument", sign));
|
"format specifier '{}' requires signed argument", sign)));
|
||||||
}
|
}
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
@ -217,7 +245,7 @@ class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
|
|||||||
explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
|
explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
|
||||||
|
|
||||||
unsigned visit_unhandled_arg() {
|
unsigned visit_unhandled_arg() {
|
||||||
throw fmt::FormatError("width is not integer");
|
FMT_THROW(fmt::FormatError("width is not integer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -229,7 +257,7 @@ class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
|
|||||||
width = 0 - width;
|
width = 0 - width;
|
||||||
}
|
}
|
||||||
if (width > INT_MAX)
|
if (width > INT_MAX)
|
||||||
throw fmt::FormatError("number is too big");
|
FMT_THROW(fmt::FormatError("number is too big"));
|
||||||
return static_cast<unsigned>(width);
|
return static_cast<unsigned>(width);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -238,13 +266,13 @@ class PrecisionHandler :
|
|||||||
public fmt::internal::ArgVisitor<PrecisionHandler, int> {
|
public fmt::internal::ArgVisitor<PrecisionHandler, int> {
|
||||||
public:
|
public:
|
||||||
unsigned visit_unhandled_arg() {
|
unsigned visit_unhandled_arg() {
|
||||||
throw fmt::FormatError("precision is not integer");
|
FMT_THROW(fmt::FormatError("precision is not integer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int visit_any_int(T value) {
|
int visit_any_int(T value) {
|
||||||
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||||
throw fmt::FormatError("number is too big");
|
FMT_THROW(fmt::FormatError("number is too big"));
|
||||||
return static_cast<int>(value);
|
return static_cast<int>(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -385,12 +413,12 @@ const uint64_t fmt::internal::POWERS_OF_10_64[] = {
|
|||||||
|
|
||||||
void fmt::internal::report_unknown_type(char code, const char *type) {
|
void fmt::internal::report_unknown_type(char code, const char *type) {
|
||||||
if (std::isprint(static_cast<unsigned char>(code))) {
|
if (std::isprint(static_cast<unsigned char>(code))) {
|
||||||
throw fmt::FormatError(
|
FMT_THROW(fmt::FormatError(
|
||||||
fmt::format("unknown format code '{}' for {}", code, type));
|
fmt::format("unknown format code '{}' for {}", code, type)));
|
||||||
}
|
}
|
||||||
throw fmt::FormatError(
|
FMT_THROW(fmt::FormatError(
|
||||||
fmt::format("unknown format code '\\x{:02x}' for {}",
|
fmt::format("unknown format code '\\x{:02x}' for {}",
|
||||||
static_cast<unsigned>(code), type));
|
static_cast<unsigned>(code), type)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -400,18 +428,18 @@ fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
|
|||||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
|
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
|
||||||
static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
|
static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
throw WindowsError(GetLastError(), ERROR);
|
FMT_THROW(WindowsError(GetLastError(), ERROR));
|
||||||
buffer_.resize(length);
|
buffer_.resize(length);
|
||||||
length = MultiByteToWideChar(
|
length = MultiByteToWideChar(
|
||||||
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
|
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
throw WindowsError(GetLastError(), ERROR);
|
FMT_THROW(WindowsError(GetLastError(), ERROR));
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
|
fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
|
||||||
if (int error_code = convert(s)) {
|
if (int error_code = convert(s)) {
|
||||||
throw WindowsError(error_code,
|
FMT_THROW(WindowsError(error_code,
|
||||||
"cannot convert string from UTF-16 to UTF-8");
|
"cannot convert string from UTF-16 to UTF-8"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,7 +469,7 @@ void fmt::WindowsError::init(
|
|||||||
void fmt::internal::format_system_error(
|
void fmt::internal::format_system_error(
|
||||||
fmt::Writer &out, int error_code,
|
fmt::Writer &out, int error_code,
|
||||||
fmt::StringRef message) FMT_NOEXCEPT(true) {
|
fmt::StringRef message) FMT_NOEXCEPT(true) {
|
||||||
try {
|
FMT_TRY {
|
||||||
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
|
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
|
||||||
buffer.resize(INLINE_BUFFER_SIZE);
|
buffer.resize(INLINE_BUFFER_SIZE);
|
||||||
char *system_message = 0;
|
char *system_message = 0;
|
||||||
@ -456,7 +484,7 @@ void fmt::internal::format_system_error(
|
|||||||
break; // Can't get error message, report error code instead.
|
break; // Can't get error message, report error code instead.
|
||||||
buffer.resize(buffer.size() * 2);
|
buffer.resize(buffer.size() * 2);
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} FMT_CATCH(...) {}
|
||||||
format_error_code(out, error_code, message);
|
format_error_code(out, error_code, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,7 +502,7 @@ void fmt::internal::format_windows_error(
|
|||||||
LPWSTR *ptr() { return &str_; }
|
LPWSTR *ptr() { return &str_; }
|
||||||
LPCWSTR c_str() const { return str_; }
|
LPCWSTR c_str() const { return str_; }
|
||||||
};
|
};
|
||||||
try {
|
FMT_TRY {
|
||||||
String system_message;
|
String system_message;
|
||||||
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
|
||||||
@ -486,7 +514,7 @@ void fmt::internal::format_windows_error(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} FMT_CATCH(...) {}
|
||||||
format_error_code(out, error_code, message);
|
format_error_code(out, error_code, message);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -519,7 +547,7 @@ class fmt::internal::ArgFormatter :
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
|
if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
|
||||||
throw FormatError("invalid format specifier for char");
|
FMT_THROW(FormatError("invalid format specifier for char"));
|
||||||
typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
|
typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
|
||||||
CharPtr out = CharPtr();
|
CharPtr out = CharPtr();
|
||||||
if (spec_.width_ > 1) {
|
if (spec_.width_ > 1) {
|
||||||
@ -571,7 +599,7 @@ void fmt::BasicWriter<Char>::write_str(
|
|||||||
std::size_t size = str.size;
|
std::size_t size = str.size;
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
if (!s)
|
if (!s)
|
||||||
throw FormatError("string pointer is null");
|
FMT_THROW(FormatError("string pointer is null"));
|
||||||
if (*s)
|
if (*s)
|
||||||
size = std::char_traits<StrChar>::length(s);
|
size = std::char_traits<StrChar>::length(s);
|
||||||
}
|
}
|
||||||
@ -583,8 +611,10 @@ inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
|
|||||||
const char *error = 0;
|
const char *error = 0;
|
||||||
Arg arg = *s < '0' || *s > '9' ?
|
Arg arg = *s < '0' || *s > '9' ?
|
||||||
next_arg(error) : get_arg(parse_nonnegative_int(s), error);
|
next_arg(error) : get_arg(parse_nonnegative_int(s), error);
|
||||||
if (error)
|
if (error) {
|
||||||
throw FormatError(*s != '}' && *s != ':' ? "invalid format string" : error);
|
FMT_THROW(FormatError(
|
||||||
|
*s != '}' && *s != ':' ? "invalid format string" : error));
|
||||||
|
}
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,7 +677,7 @@ Arg fmt::internal::PrintfFormatter<Char>::get_arg(
|
|||||||
Arg arg = arg_index == UINT_MAX ?
|
Arg arg = arg_index == UINT_MAX ?
|
||||||
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
|
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
|
||||||
if (error)
|
if (error)
|
||||||
throw FormatError(!*s ? "invalid format string" : error);
|
FMT_THROW(FormatError(!*s ? "invalid format string" : error));
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,7 +793,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
|
|||||||
|
|
||||||
// Parse type.
|
// Parse type.
|
||||||
if (!*s)
|
if (!*s)
|
||||||
throw FormatError("invalid format string");
|
FMT_THROW(FormatError("invalid format string"));
|
||||||
spec.type_ = static_cast<char>(*s++);
|
spec.type_ = static_cast<char>(*s++);
|
||||||
if (arg.type <= Arg::LAST_INTEGER_TYPE) {
|
if (arg.type <= Arg::LAST_INTEGER_TYPE) {
|
||||||
// Normalize type.
|
// Normalize type.
|
||||||
@ -887,7 +917,7 @@ const Char *fmt::BasicFormatter<Char>::format(
|
|||||||
if (p != s) {
|
if (p != s) {
|
||||||
if (c == '}') break;
|
if (c == '}') break;
|
||||||
if (c == '{')
|
if (c == '{')
|
||||||
throw FormatError("invalid fill character '{'");
|
FMT_THROW(FormatError("invalid fill character '{'"));
|
||||||
s += 2;
|
s += 2;
|
||||||
spec.fill_ = c;
|
spec.fill_ = c;
|
||||||
} else ++s;
|
} else ++s;
|
||||||
@ -931,7 +961,7 @@ const Char *fmt::BasicFormatter<Char>::format(
|
|||||||
// and more efficient than checking if the next char is a digit.
|
// and more efficient than checking if the next char is a digit.
|
||||||
spec.width_ = parse_nonnegative_int(s);
|
spec.width_ = parse_nonnegative_int(s);
|
||||||
if (error)
|
if (error)
|
||||||
throw FormatError(error);
|
FMT_THROW(FormatError(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse precision.
|
// Parse precision.
|
||||||
@ -941,17 +971,17 @@ const Char *fmt::BasicFormatter<Char>::format(
|
|||||||
if ('0' <= *s && *s <= '9') {
|
if ('0' <= *s && *s <= '9') {
|
||||||
spec.precision_ = parse_nonnegative_int(s);
|
spec.precision_ = parse_nonnegative_int(s);
|
||||||
if (error)
|
if (error)
|
||||||
throw FormatError(error);
|
FMT_THROW(FormatError(error));
|
||||||
} else if (*s == '{') {
|
} else if (*s == '{') {
|
||||||
++s;
|
++s;
|
||||||
const Arg &precision_arg = parse_arg_index(s);
|
const Arg &precision_arg = parse_arg_index(s);
|
||||||
if (*s++ != '}')
|
if (*s++ != '}')
|
||||||
throw FormatError("invalid format string");
|
FMT_THROW(FormatError("invalid format string"));
|
||||||
ULongLong value = 0;
|
ULongLong value = 0;
|
||||||
switch (precision_arg.type) {
|
switch (precision_arg.type) {
|
||||||
case Arg::INT:
|
case Arg::INT:
|
||||||
if (precision_arg.int_value < 0)
|
if (precision_arg.int_value < 0)
|
||||||
throw FormatError("negative precision");
|
FMT_THROW(FormatError("negative precision"));
|
||||||
value = precision_arg.int_value;
|
value = precision_arg.int_value;
|
||||||
break;
|
break;
|
||||||
case Arg::UINT:
|
case Arg::UINT:
|
||||||
@ -959,24 +989,24 @@ const Char *fmt::BasicFormatter<Char>::format(
|
|||||||
break;
|
break;
|
||||||
case Arg::LONG_LONG:
|
case Arg::LONG_LONG:
|
||||||
if (precision_arg.long_long_value < 0)
|
if (precision_arg.long_long_value < 0)
|
||||||
throw FormatError("negative precision");
|
FMT_THROW(FormatError("negative precision"));
|
||||||
value = precision_arg.long_long_value;
|
value = precision_arg.long_long_value;
|
||||||
break;
|
break;
|
||||||
case Arg::ULONG_LONG:
|
case Arg::ULONG_LONG:
|
||||||
value = precision_arg.ulong_long_value;
|
value = precision_arg.ulong_long_value;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw FormatError("precision is not integer");
|
FMT_THROW(FormatError("precision is not integer"));
|
||||||
}
|
}
|
||||||
if (value > INT_MAX)
|
if (value > INT_MAX)
|
||||||
throw FormatError("number is too big");
|
FMT_THROW(FormatError("number is too big"));
|
||||||
spec.precision_ = static_cast<int>(value);
|
spec.precision_ = static_cast<int>(value);
|
||||||
} else {
|
} else {
|
||||||
throw FormatError("missing precision specifier");
|
FMT_THROW(FormatError("missing precision specifier"));
|
||||||
}
|
}
|
||||||
if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
|
if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
|
||||||
throw FormatError(
|
FMT_THROW(FormatError(
|
||||||
"precision specifier requires floating-point argument");
|
"precision specifier requires floating-point argument"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -986,7 +1016,7 @@ const Char *fmt::BasicFormatter<Char>::format(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*s++ != '}')
|
if (*s++ != '}')
|
||||||
throw FormatError("missing '}' in format string");
|
FMT_THROW(FormatError("missing '}' in format string"));
|
||||||
start_ = s;
|
start_ = s;
|
||||||
|
|
||||||
// Format argument.
|
// Format argument.
|
||||||
@ -1008,7 +1038,7 @@ void fmt::BasicFormatter<Char>::format(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == '}')
|
if (c == '}')
|
||||||
throw FormatError("unmatched '}' in format string");
|
FMT_THROW(FormatError("unmatched '}' in format string"));
|
||||||
write(writer_, start_, s - 1);
|
write(writer_, start_, s - 1);
|
||||||
Arg arg = parse_arg_index(s);
|
Arg arg = parse_arg_index(s);
|
||||||
s = format(s, arg);
|
s = format(s, arg);
|
||||||
|
@ -58,6 +58,14 @@ if (HAVE_OPEN)
|
|||||||
add_test(posix-test posix-test)
|
add_test(posix-test posix-test)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
# Test that the library can be compiled with exceptions disabled.
|
||||||
|
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
|
||||||
|
if (HAVE_FNO_EXCEPTIONS_FLAG)
|
||||||
|
add_library(noexception-test ../format.cc)
|
||||||
|
set_target_properties(noexception-test
|
||||||
|
PROPERTIES COMPILE_FLAGS -fno-exceptions)
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_test(compile-test ${CMAKE_CTEST_COMMAND}
|
add_test(compile-test ${CMAKE_CTEST_COMMAND}
|
||||||
--build-and-test
|
--build-and-test
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/compile-test"
|
"${CMAKE_CURRENT_SOURCE_DIR}/compile-test"
|
||||||
|
Loading…
Reference in New Issue
Block a user