Changeset View
Changeset View
Standalone View
Standalone View
llvm/include/llvm/Support/Format.h
Show All 27 Lines | |||||
#include "llvm/Support/DataTypes.h" | #include "llvm/Support/DataTypes.h" | ||||
#include <cassert> | #include <cassert> | ||||
#include <cstdio> | #include <cstdio> | ||||
#include <tuple> | #include <tuple> | ||||
#include <utility> | #include <utility> | ||||
namespace llvm { | namespace llvm { | ||||
/// Utility class that parses printf-style format strings to yield the expected | |||||
/// C type(s) of each specifier. This class is used to verify that a format | |||||
/// string unknown at compile-time is equivalent to another format string (which | |||||
/// itself is hopefully known at compile-time). | |||||
class PrintfStyleFormatReader { | |||||
public: | |||||
enum SpecifierType { | |||||
ahatanak: Can you use `char` as the underlying type for enums? | |||||
ST_EndOfFormatString, | |||||
ST_Unknown, | |||||
ST_WideChar, | |||||
ST_Int, | |||||
ST_UInt, | |||||
ST_Long, | |||||
ST_ULong, | |||||
ST_LongLong, | |||||
ST_ULongLong, | |||||
ST_IntMax, | |||||
ST_UIntMax, | |||||
ST_Size, | |||||
ST_Ptrdiff, | |||||
ST_Double, | |||||
ST_LongDouble, | |||||
ST_CString, | |||||
ST_WideCString, | |||||
ST_VoidPointer, | |||||
ST_Count_Char, | |||||
ST_Count_Short, | |||||
ST_Count_Int, | |||||
ST_Count_Long, | |||||
ST_Count_LongLong, | |||||
ST_Count_IntMax, | |||||
ST_Count_Size, | |||||
ST_Count_Ptrdiff | |||||
}; | |||||
private: | |||||
const char *Fmt; | |||||
llvm::SmallVector<SpecifierType, 3> SpecifierQueue; | |||||
bool SignSensitive; | |||||
void RefillSpecifierQueue(); | |||||
public: | |||||
/// Verify that the format specifiers in \p Fmt consume no more arguments than | |||||
/// those in \p Expected, and that all consumed arguments have a compatible | |||||
/// type. | |||||
static const char *EnsureCompatible(const char *Expected, const char *Fmt); | |||||
PrintfStyleFormatReader(const char *Fmt, bool SignSensitive = false) | |||||
: Fmt(Fmt), SignSensitive(SignSensitive) {} | |||||
SpecifierType NextSpecifier() { | |||||
if (SpecifierQueue.empty()) | |||||
RefillSpecifierQueue(); | |||||
return SpecifierQueue.pop_back_val(); | |||||
} | |||||
}; | |||||
/// This is a helper class used for handling formatted output. It is the | /// This is a helper class used for handling formatted output. It is the | ||||
/// abstract base class of a templated derived class. | /// abstract base class of a templated derived class. | ||||
class format_object_base { | class format_object_base { | ||||
protected: | protected: | ||||
const char *Fmt; | |||||
~format_object_base() = default; // Disallow polymorphic deletion. | ~format_object_base() = default; // Disallow polymorphic deletion. | ||||
format_object_base(const format_object_base &) = default; | format_object_base(const format_object_base &) = default; | ||||
virtual void home(); // Out of line virtual method. | virtual void home(); // Out of line virtual method. | ||||
/// Call snprintf() for this object, on the given buffer and size. | /// Call snprintf() for this object, on the given buffer and size. | ||||
virtual int snprint(char *Buffer, unsigned BufferSize) const = 0; | virtual int snprint(char *Buffer, unsigned BufferSize) const = 0; | ||||
public: | public: | ||||
format_object_base(const char *fmt) : Fmt(fmt) {} | format_object_base() = default; | ||||
/// Format the object into the specified buffer. On success, this returns | /// Format the object into the specified buffer. On success, this returns | ||||
/// the length of the formatted string. If the buffer is too small, this | /// the length of the formatted string. If the buffer is too small, this | ||||
/// returns a length to retry with, which will be larger than BufferSize. | /// returns a length to retry with, which will be larger than BufferSize. | ||||
unsigned print(char *Buffer, unsigned BufferSize) const { | unsigned print(char *Buffer, unsigned BufferSize) const { | ||||
assert(BufferSize && "Invalid buffer size!"); | assert(BufferSize && "Invalid buffer size!"); | ||||
// Print the string, leaving room for the terminating null. | // Print the string, leaving room for the terminating null. | ||||
Show All 23 Lines | |||||
template <typename Arg, typename... Args> | template <typename Arg, typename... Args> | ||||
struct validate_format_parameters<Arg, Args...> { | struct validate_format_parameters<Arg, Args...> { | ||||
static_assert(std::is_scalar<Arg>::value, | static_assert(std::is_scalar<Arg>::value, | ||||
"format can't be used with non fundamental / non pointer type"); | "format can't be used with non fundamental / non pointer type"); | ||||
validate_format_parameters() { validate_format_parameters<Args...>(); } | validate_format_parameters() { validate_format_parameters<Args...>(); } | ||||
}; | }; | ||||
template <> struct validate_format_parameters<> {}; | template <> struct validate_format_parameters<> {}; | ||||
template <typename... Ts> | template <typename... Ts> auto format_capture(const char *Fmt, Ts... Vals) { | ||||
class format_object final : public format_object_base { | validate_format_parameters<Ts...>(); | ||||
std::tuple<Ts...> Vals; | return [=](char *Buffer, unsigned BufferSize) { | ||||
template <std::size_t... Is> | |||||
int snprint_tuple(char *Buffer, unsigned BufferSize, | |||||
std::index_sequence<Is...>) const { | |||||
#ifdef _MSC_VER | #ifdef _MSC_VER | ||||
return _snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...); | return _snprintf(Buffer, BufferSize, Fmt, Vals...); | ||||
#else | #else | ||||
return snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...); | return snprintf(Buffer, BufferSize, Fmt, Vals...); | ||||
#endif | #endif | ||||
}; | |||||
} | } | ||||
template <typename... Ts> | |||||
class format_object final : public format_object_base { | |||||
decltype(format_capture<Ts...>("", std::declval<Ts>()...)) Format; | |||||
public: | public: | ||||
format_object(const char *fmt, const Ts &... vals) | format_object(const char *Fmt, const Ts &...vals) | ||||
: format_object_base(fmt), Vals(vals...) { | : Format(format_capture(Fmt, vals...)) {} | ||||
validate_format_parameters<Ts...>(); | |||||
} | |||||
int snprint(char *Buffer, unsigned BufferSize) const override { | int snprint(char *Buffer, unsigned BufferSize) const override { | ||||
return snprint_tuple(Buffer, BufferSize, std::index_sequence_for<Ts...>()); | return Format(Buffer, BufferSize); | ||||
} | } | ||||
}; | }; | ||||
/// These are helper functions used to produce formatted output. They use | /// These are helper functions used to produce formatted output. They use | ||||
/// template type deduction to construct the appropriate instance of the | /// template type deduction to construct the appropriate instance of the | ||||
/// format_object class to simplify their construction. | /// format_object class to simplify their construction. | ||||
/// | /// | ||||
/// This is typically used like: | /// This is typically used like: | ||||
/// \code | /// \code | ||||
/// OS << format("%0.4f", myfloat) << '\n'; | /// OS << format("%0.4f", myfloat) << '\n'; | ||||
/// \endcode | /// \endcode | ||||
template <typename... Ts> | template <typename... Ts> | ||||
inline format_object<Ts...> format(const char *Fmt, const Ts &... Vals) { | inline format_object<Ts...> format(const char *Fmt, const Ts &... Vals) { | ||||
return format_object<Ts...>(Fmt, Vals...); | return format_object<Ts...>(Fmt, Vals...); | ||||
} | } | ||||
ahatanakUnsubmitted I don't think it's clear to the users of this function what they should pass for Expected. Can you leave a comment that explains what this function expects or in which cases Expected and Fmt would be incompatible? ahatanak: I don't think it's clear to the users of this function what they should pass for `Expected`. | |||||
fcloutierAuthorUnsubmitted Since there was just one use of this function and it was preferable to check a different way, I removed it entirely. fcloutier: Since there was just one use of this function and it was preferable to check a different way, I… | |||||
template <typename... Ts> | |||||
format_object<Ts...> format_chk(const char *Expected, const char *Fmt, | |||||
const Ts &...Vals) { | |||||
const char *const Verified = | |||||
PrintfStyleFormatReader::EnsureCompatible(Expected, Fmt); | |||||
return format(Verified, Vals...); | |||||
} | |||||
/// This is a helper class for left_justify, right_justify, and center_justify. | /// This is a helper class for left_justify, right_justify, and center_justify. | ||||
class FormattedString { | class FormattedString { | ||||
public: | public: | ||||
enum Justification { JustifyNone, JustifyLeft, JustifyRight, JustifyCenter }; | enum Justification { JustifyNone, JustifyLeft, JustifyRight, JustifyCenter }; | ||||
FormattedString(StringRef S, unsigned W, Justification J) | FormattedString(StringRef S, unsigned W, Justification J) | ||||
: Str(S), Width(W), Justify(J) {} | : Str(S), Width(W), Justify(J) {} | ||||
private: | private: | ||||
▲ Show 20 Lines • Show All 122 Lines • Show Last 20 Lines |
Can you use char as the underlying type for enums?