<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">+1<div class=""><br class=""></div><div class="">I really like this proposal. Throughout LLVM sub-projects there is a lot of string formatting that we do and it would be great to have a more modern, flexible, portable, and safe string formatting API.</div><div class=""><br class=""></div><div class="">-Chris</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Oct 11, 2016, at 6:22 PM, Zachary Turner via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">A while back llvm::format() was introduced that made it possible to combine printf-style formatting with llvm streams.  However, this still comes with all the risks and pitfalls of printf.  Everyone is no-doubt familiar with these problems, but here are just a few anyway:<div class=""><br class=""></div><div class="">1. <b class="">Not type-safe.</b>  Not all compilers warn when you mess up the format specifier.  And when you're writing your own Printf-like functions, you need to tag them with __attribute__(format, printf) which again not all compilers have.  If you change a const char * to a StringRef, it can silently succeed while passing your StringRef object to printf.  It should fail to compile!</div><div class=""><br class=""></div><div class="">2. <b class="">Not security safe.  </b>Functions like sprintf() will happily smash your stack for you if you're not careful.  </div><div class=""><br class=""></div><div class="">3. <b class="">Not portable (well kinda).  </b>Quick, how do you print a size_t?  You probably said %z.  Well MSVC didn't even support %z until 2015, which we aren't even officially requiring yet.  So you've gotta write (uint64_t)x and then use PRIx64.  Ugh.</div><div class=""><br class=""></div><div class="">4. <b class="">Redundant.</b>  If you're giving it an integer, why do you need to specify %d?  It's an integer!  We should be able to use the type system to our advantage.</div><div class=""><br class=""></div><div class="">5. <b class="">Not flexible.</b>  How do you print a std::chrono::time_point with llvm::format()?  You can't.  You have to resort to providing an overloaded streaming operator or formatting it some other way.</div><div class=""><br class=""></div><div class="">So I've been working on a library that will solve all of these problems and more.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">The high level design of my library is borrowed heavily from C#.  But if you're not familiar with C#, I believe boost has something similar in spirit.  The best way to show it off is with some examples:</div><div class=""><br class=""></div><div class="">1. os << format_string("Test");   // writes "test"</div><div class="">2. os << format_string("{0}", 7);  // writes "7"</div><div class=""><br class=""></div><div class="">Immediately we can see one big difference between this and llvm::format() / printf.  You don't have to specify the type.  If you pass in an int, it formats it as an int.</div><div class=""><br class=""></div><div class="">3. os << format_string("{0} {0}", 7); // writes "7 7"</div><div class=""><br class=""></div><div class="">#3 is an example of something that cannot be done elegantly with printf.  Sure, you can pass it in twice, but if it's expensive to compute, this means you have to save it into a temporary.</div><div class=""><br class=""></div><div class="">4. os << format_string("{0:X}", 255);  // writes "0xFF"</div><div class="">5. os << format_string("{0:X7}", 255);  // writes "0x000FF"</div><div class=""><br class=""></div><div class="">6. os << format_string("{0}", foo_object); // fails to compile!</div><div class=""><br class=""></div><div class="">Here is another example of an improvement over traditional formatting mechanisms.  If you pass an object for which it cannot find a formatter, it fails to compile.</div><div class=""><br class=""></div><div class="">However, you can always define custom formatters for your own types.  If you write:</div><div class=""><br class=""></div><div class="">namespace llvm {</div><div class="">  template<></div><div class="">  struct format_provider<Foo> {</div><div class="">    static void format(raw_ostream &S, const Foo &F, int Align, StringRef Options) {</div><div class="">    }</div><div class="">  };</div><div class="">}</div><div class=""><br class=""></div><div class="">Then #6 will magically compile, and invoke the function above to do the formatting.  There are other ways to customize the formatting behavior, but I'll keep going with some more examples:</div><div class=""><br class=""></div><div class="">7. os << format_string("{0:N}", -1234567);  // Writes "-1,234,567".  Note the commas.</div><div class="">8. os << format_string("{0:P}", 0.76);  // Writes "76.00%"</div><div class=""><br class=""></div><div class="">You can also left justify and right justify.  For example:</div><div class=""><br class=""></div><div class="">9. os << format_string("{0,8:P}", 0.76);  // Writes "  76.00%"</div><div class="">10. os << format_string("{0,-8,P}", 0.76);  // Writes "76.00%  "</div><div class=""><br class=""></div><div class="">And you can also format complicated types.  For example:</div><div class=""><br class=""></div><div class="">11. os << format_string("{0:DD/MM/YYYY hh:mm:ss}", std::chrono::system_clock::now());  // writes "10/11/2016 18:19:11"</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">I already have a working proof of concept that supports most of the fundamental data types and formatting options such as percents, exponents, comma grouping, fixed point, hex, etc.</div><div class=""><br class=""></div><div class="">To summarize, the advantages of this approach are:</div><div class=""><br class=""></div><div class="">1) <b class="">Safe.</b>  If it can't format your type, it won't even compile.  </div><div class="">2) <b class="">Concise.</b>  You can re-use parameters multiple times without re-specifying them.</div><div class="">3) <b class="">Simple.  </b>You don't have to remember whether to use %llu or PRIx64 or %z, because format specifiers don't exist!</div><div class="">4) <b class="">Flexible.</b>  You can format types in a multitude of different ways while still having the nice format-string style syntax.</div><div class="">5) <b class="">Extensible.</b>  If you don't like the behavior of a built-in formatter, you can override it with your own.  If you have your own type which you'd like to be able to format, you can add formatting support for it in multiple different ways.</div><div class=""><br class=""></div><div class="">I am hoping to have something ready for submitting later this week.  If this interests you, please help me out by reviewing my patch!  And if you think this would not be helpful for LLVM and I should not worry about this, let me know as well!</div><div class=""><br class=""></div><div class="">Thanks,</div><div class="">Zach</div></div>
_______________________________________________<br class="">LLVM Developers mailing list<br class=""><a href="mailto:llvm-dev@lists.llvm.org" class="">llvm-dev@lists.llvm.org</a><br class="">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev<br class=""></div></blockquote></div><br class=""></div></body></html>