Handle empty format_arg state

This commit is contained in:
Victor Zverovich 2016-12-27 07:43:25 -08:00
parent 3bbc5799b6
commit ee1651ce07
2 changed files with 16 additions and 11 deletions

View File

@ -1331,6 +1331,8 @@ template <typename Char>
class ArgMap; class ArgMap;
} // namespace internal } // namespace internal
struct monostate {};
template <typename Context, typename Char> template <typename Context, typename Char>
class basic_format_args; class basic_format_args;
@ -1352,27 +1354,22 @@ class basic_format_arg {
template <typename CharType> template <typename CharType>
friend class internal::ArgMap; friend class internal::ArgMap;
void check_type() const {
FMT_ASSERT(type_ > internal::NAMED_ARG, "invalid argument type");
}
public: public:
basic_format_arg() : type_(internal::NONE) {} basic_format_arg() : type_(internal::NONE) {}
explicit operator bool() const noexcept { return type_ != internal::NONE; } explicit operator bool() const noexcept { return type_ != internal::NONE; }
bool is_integral() const { bool is_integral() const {
check_type(); FMT_ASSERT(type_ != internal::NAMED_ARG, "invalid argument type");
return type_ <= internal::LAST_INTEGER_TYPE; return type_ > internal::NONE && type_ <= internal::LAST_INTEGER_TYPE;
} }
bool is_numeric() const { bool is_numeric() const {
check_type(); FMT_ASSERT(type_ != internal::NAMED_ARG, "invalid argument type");
return type_ <= internal::LAST_NUMERIC_TYPE; return type_ > internal::NONE && type_ <= internal::LAST_NUMERIC_TYPE;
} }
bool is_pointer() const { bool is_pointer() const {
check_type();
return type_ == internal::POINTER; return type_ == internal::POINTER;
} }
}; };
@ -1392,6 +1389,7 @@ typename std::result_of<Visitor(int)>::type
visit(Visitor &&vis, basic_format_arg<Char> arg) { visit(Visitor &&vis, basic_format_arg<Char> arg) {
switch (arg.type_) { switch (arg.type_) {
case internal::NONE: case internal::NONE:
return vis(monostate());
case internal::NAMED_ARG: case internal::NAMED_ARG:
FMT_ASSERT(false, "invalid argument type"); FMT_ASSERT(false, "invalid argument type");
break; break;
@ -1986,6 +1984,10 @@ class ArgFormatterBase {
ArgFormatterBase(BasicWriter<Char> &w, FormatSpec &s) ArgFormatterBase(BasicWriter<Char> &w, FormatSpec &s)
: writer_(w), spec_(s) {} : writer_(w), spec_(s) {}
void operator()(monostate) {
FMT_ASSERT(false, "invalid argument type");
}
template <typename T> template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type typename std::enable_if<std::is_integral<T>::value>::type
operator()(T value) { writer_.write_int(value, spec_); } operator()(T value) { writer_.write_int(value, spec_); }

View File

@ -579,8 +579,11 @@ TEST(UtilTest, CustomArg) {
} }
TEST(ArgVisitorTest, VisitInvalidArg) { TEST(ArgVisitorTest, VisitInvalidArg) {
format_arg arg = format_arg(); typedef MockVisitor<fmt::monostate> Visitor;
EXPECT_ASSERT(visit(MockVisitor<int>(), arg), "invalid argument type"); testing::StrictMock<Visitor> visitor;
EXPECT_CALL(visitor, visit(_));
format_arg arg;
visit(visitor, arg);
} }
// Tests fmt::internal::count_digits for integer type Int. // Tests fmt::internal::count_digits for integer type Int.