// Copyright (c) 2014, Thomas Goyne // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ #include #include #include #include class wxString; extern template class boost::interprocess::basic_vectorstream; extern template class boost::interprocess::basic_vectorstream; extern template class boost::interprocess::basic_vectorbuf; extern template class boost::interprocess::basic_vectorbuf; namespace agi { namespace format_detail { // A static cast which throws at runtime if the cast is invalid rather than // failing to compile, as with format strings we don't know what type to cast // to at compile time. template::value> struct runtime_cast_helper { static Out cast(In const&) { throw std::bad_cast(); } }; template struct runtime_cast_helper { static Out cast(In const& value) { return static_cast(value); } }; template Out runtime_cast(In const& value) { return runtime_cast_helper::cast(value); } } template struct writer { static void write(std::basic_ostream& out, int, T const& value) { out << value; } }; template struct writer { static void write(std::basic_ostream& out, int max_len, const Char *value); }; template struct writer> { static void write(std::basic_ostream& out, int max_len, std::basic_string const& value); }; // Ensure things with specializations don't get implicitly initialized template<> struct writer; template<> struct writer; template<> struct writer; template<> struct writer; namespace format_detail { template struct formatter_state { std::basic_ostream& out; const Char *fmt; const Char *fmt_cur = nullptr; bool read_width = false; bool read_precision = false; bool pending = false; int width = 0; int precision = 0; formatter_state(std::basic_ostream&out , const Char *fmt) : out(out), fmt(fmt) { } }; template class formatter : formatter_state { formatter(const formatter&) = delete; formatter& operator=(const formatter&) = delete; boost::io::basic_ios_all_saver saver; bool parse_next(); Char next_format(); public: formatter(std::basic_ostream& out, const Char *fmt) : formatter_state(out, fmt), saver(out) { } ~formatter(); template void operator()(T&& value) { if (!this->pending && !parse_next()) return; if (this->read_width) { this->width = runtime_cast(value); this->read_width = false; return; } if (this->read_precision) { this->precision = runtime_cast(value); this->read_precision = false; return; } Char c = next_format(); switch (c) { case 'c': this->out << runtime_cast(value); break; case 'd': case 'i': this->out << runtime_cast(value); break; case 'o': this->out << runtime_cast(value); break; case 'x': this->out << runtime_cast(value); break; case 'u': this->out << runtime_cast(value); break; case 'e': this->out << runtime_cast(value); break; case 'f': this->out << runtime_cast(value); break; case 'g': this->out << runtime_cast(value); break; case 'p': this->out << runtime_cast(value); break; default: // s and other writer::type>::write(this->out, this->precision, value); break; } } }; // Base case for variadic template recursion template inline void format(formatter&&) { } template void format(formatter&& fmt, T&& first, Args&&... rest) { fmt(first); format(std::move(fmt), std::forward(rest)...); } } // namespace format_detail template void format(std::basic_ostream& out, const Char *fmt, Args&&... args) { format(format_detail::formatter(out, fmt), std::forward(args)...); } template std::basic_string format(const Char *fmt, Args&&... args) { boost::interprocess::basic_vectorstream> out; format(out, fmt, std::forward(args)...); return out.vector(); } }