-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Custom formatter: force HASH_FLAG behavior #439
Comments
Writing "0x" won't play well with sign and alignment. For example, prefix[prefix_size++] = spec.type(); in prefix[prefix_size++] = spec.type_prefix(); with the default implementation of Then you could provide your own version of |
Ah yes! I forgot to mention I was OK with the sign issue since it would never occur in my case... |
Sure. |
Err... Are you sure?! Since So unless you see a broader use of having the Half-thought alternatives that do not feel right:
Did I miss something? |
I don't think you need to pass template <class CharT>
class CustomArgFormatter {
...
template <typename T>
void visit_any_int(T value) {
CustomFormatSpec spec(spec_);
writer_.write_int(value, spec);
}
}; where Does it make sense? |
The What I mean is that, for example, I noticed it doesn't look like it's actually possible to call Well all of this means I need more time than I thought to make this PR (just for the sake of doing a tiny lower case conversion; fun)! I'll report here when I got stroke by the thunder with some brilliant idea instead of making noise here. Enjoy your last Christmas before Trump-era. |
Sorry, I forgot that template <typename T, typename Spec, typename FillChar>
BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec) {
internal::CharTraits<Char>::convert(FillChar());
write_int(spec.value(), spec);
return *this;
} to something like template <typename Spec>
typename internal::EnableIf<Spec::INTEGER, BasicWriter&>::type
operator<<(Spec spec) {
internal::CharTraits<Char>::convert(spec.fill());
write_int(spec.value(), spec);
return *this;
} and add enum {INTEGER = 1}; to Then you'll be able to use a custom format spec: template <typename T>
class CustomSpec : public fmt::FormatSpec {
private:
T value_;
public:
enum {INTEGER = 1};
...
T value() const { return value_; }
char fill() const { return fill_; }
};
fmt::MemoryWriter w;
w << CustomSpec<int>(42); The good thing about this solution is that it will allow customizing formatting when using the write API too. |
Nice! It works! Still it felt a bit ugly (don't mind me) so, in the meantime and in case you care, I've modified fmt so the user can pass its own type of Usage example: struct CustomFormatSpec : public fmt::FormatSpec
{
char type_prefix() const { return type() | 0x20; } // blindly force lower case
};
template <class CharT, class SpecT = CustomFormatSpec>
class CustomArgFormatter : public fmt::BasicArgFormatter<
CustomArgFormatter<CharT>, CharT, SpecT>
{
public:
typedef
fmt::BasicArgFormatter<CustomArgFormatter<CharT>, CharT, SpecT>
SuperT;
CustomArgFormatter<CharT, SpecT>(
fmt::BasicFormatter<CharT, CustomArgFormatter>& f,
typename SpecT& s, const CharT* fmt)
: SuperT(f, s, fmt) { }
template <typename T>
void visit_any_int(T value)
{
const char type_lc = this->spec().type() | 0x20; // lower case
if (!std::is_unsigned<T>::value && (type_lc == 'x' || type_lc == 'b'))
{
typedef std::make_unsigned<T>::type UnsignedT;
SuperT::visit_any_int<UnsignedT>(static_cast<UnsignedT>(value));
}
else
{
SuperT::visit_any_int<T>(value);
}
}
}; |
Please do submit a PR and I'll have a look. |
…ArgFormatter chain (fmtlib#439)
PR #444 |
* A custom FormatSpec type can be passed as a template argument to the ArgFormatter chain (#439) * Corrected nested-name-specifier error * Spec template argument defaulted to FormatSpec * Forward declaration of FormatSpec * Style * Style (part 2) * Style (part 3)
* A custom FormatSpec type can be passed as a template argument to the ArgFormatter chain (#439) * Corrected nested-name-specifier error * Spec template argument defaulted to FormatSpec * Forward declaration of FormatSpec * Style * Style (part 2) * Style (part 3)
Hi, I was toying around with my shiny custom arg formatter and wondered what's the lightest way (speed) to modify the default behavior when
HASH_FLAG
is specified for integers (any input type, any output base). I would like to force the output prefix, only the prefix, to be in lower case (call me picky). So for example, the hex prefix would always be0x
even if the theX
modifier is used, same goes for0b
...Here are the options I've explored so far:
void BasicWriter<Char>::write_int(T value, Spec spec)
, but I do not wish to maintain my own fork offmt
spec().type_ = 'x'
in thevisit_any_int
implementation belowwriter_ << "0x"
(or whatever the right syntax/name is) then remove theHASH_FLAG
bit fromspec().flags_
before eventually proceeding to the defaultvisit_any_int
implementation. It seems to be the most acceptable solution but I thought I would ask you first as there might be an even cleaner solution that fits better tofmt
's design?Here is the current implementation of the formatter as a starting base:
The text was updated successfully, but these errors were encountered: