Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:16

0001 //
0002 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
0003 // Copyright (c) 2021-2023 Alexander Grund
0004 //
0005 // Distributed under the Boost Software License, Version 1.0.
0006 // https://www.boost.org/LICENSE_1_0.txt
0007 
0008 #ifndef BOOST_LOCALE_FORMAT_HPP_INCLUDED
0009 #define BOOST_LOCALE_FORMAT_HPP_INCLUDED
0010 
0011 #include <boost/locale/formatting.hpp>
0012 #include <boost/locale/hold_ptr.hpp>
0013 #include <boost/locale/message.hpp>
0014 #include <sstream>
0015 #include <stdexcept>
0016 #include <string>
0017 #include <vector>
0018 
0019 #ifdef BOOST_MSVC
0020 #    pragma warning(push)
0021 #    pragma warning(disable : 4275 4251 4231 4660)
0022 #endif
0023 
0024 namespace boost { namespace locale {
0025 
0026     /// \defgroup format Format
0027     ///
0028     /// This module provides printf like functionality integrated into iostreams and suitable for localization
0029     ///
0030     /// @{
0031 
0032     /// \cond INTERNAL
0033     namespace detail {
0034 
0035         template<typename CharType>
0036         struct formattible {
0037             typedef std::basic_ostream<CharType> stream_type;
0038             typedef void (*writer_type)(stream_type& output, const void* ptr);
0039 
0040             formattible() noexcept : pointer_(nullptr), writer_(&formattible::void_write) {}
0041 
0042             formattible(const formattible&) noexcept = default;
0043             formattible(formattible&&) noexcept = default;
0044             formattible& operator=(const formattible&) noexcept = default;
0045             formattible& operator=(formattible&&) noexcept = default;
0046 
0047             template<typename Type>
0048             explicit formattible(const Type& value) noexcept
0049             {
0050                 pointer_ = static_cast<const void*>(&value);
0051                 writer_ = &write<Type>;
0052             }
0053 
0054             friend stream_type& operator<<(stream_type& out, const formattible& fmt)
0055             {
0056                 fmt.writer_(out, fmt.pointer_);
0057                 return out;
0058             }
0059 
0060         private:
0061             static void void_write(stream_type& output, const void* /*ptr*/)
0062             {
0063                 CharType empty_string[1] = {0};
0064                 output << empty_string;
0065             }
0066 
0067             template<typename Type>
0068             static void write(stream_type& output, const void* ptr)
0069             {
0070                 output << *static_cast<const Type*>(ptr);
0071             }
0072 
0073             const void* pointer_;
0074             writer_type writer_;
0075         }; // formattible
0076 
0077         class BOOST_LOCALE_DECL format_parser {
0078         public:
0079             format_parser(std::ios_base& ios, void*, void (*imbuer)(void*, const std::locale&));
0080             ~format_parser();
0081             format_parser(const format_parser&) = delete;
0082             format_parser& operator=(const format_parser&) = delete;
0083 
0084             unsigned get_position();
0085 
0086             void set_one_flag(const std::string& key, const std::string& value);
0087 
0088             template<typename CharType>
0089             void set_flag_with_str(const std::string& key, const std::basic_string<CharType>& value)
0090             {
0091                 if(key == "ftime" || key == "strftime") {
0092                     as::strftime(ios_);
0093                     ios_info::get(ios_).date_time_pattern(value);
0094                 }
0095             }
0096             void restore();
0097 
0098         private:
0099             void imbue(const std::locale&);
0100 
0101             std::ios_base& ios_;
0102             struct data;
0103             hold_ptr<data> d;
0104         };
0105 
0106     } // namespace detail
0107 
0108     /// \endcond
0109 
0110     /// \brief a printf like class that allows type-safe and locale aware message formatting
0111     ///
0112     /// This class creates a formatted message similar to printf or boost::format and receives
0113     /// formatted entries via operator %.
0114     ///
0115     /// For example
0116     /// \code
0117     ///  std::cout << format("Hello {1}, you are {2} years old") % name % age << std::endl;
0118     /// \endcode
0119     ///
0120     /// Formatting is enclosed between curly brackets \c { \c } and defined by a comma separated list of flags in the
0121     /// format key[=value] value may also be text included between single quotes \c ' that is used for special purposes
0122     /// where inclusion of non-ASCII text is allowed
0123     ///
0124     /// Including of literal \c { and \c } is possible by specifying double brackets \c {{ and \c }} accordingly.
0125     ///
0126     ///
0127     /// For example:
0128     ///
0129     /// \code
0130     ///   std::cout << format("The height of water at {1,time} is {2,num=fixed,precision=3}") % time % height;
0131     /// \endcode
0132     ///
0133     /// The special key -- a number without a value defines the position of an input parameter.
0134     /// List of keys:
0135     /// -   \c [0-9]+ -- digits, the index of a formatted parameter -- mandatory key.
0136     /// -   \c num or \c number -- format a number. Optional values are:
0137     ///     -  \c hex -- display hexadecimal number
0138     ///     -  \c oct -- display in octal format
0139     ///     -  \c sci or \c scientific -- display in scientific format
0140     ///     -  \c fix or \c fixed -- display in fixed format
0141     ///     .
0142     ///     For example \c number=sci
0143     /// -  \c cur or \c currency -- format currency. Optional values are:
0144     ///
0145     ///     -  \c iso -- display using ISO currency symbol.
0146     ///     -  \c nat or \c national -- display using national currency symbol.
0147     ///     .
0148     /// -  \c per or \c percent -- format percent value.
0149     /// -  \c date, \c time , \c datetime or \c dt -- format date, time or date and time. Optional values are:
0150     ///     -  \c s or \c short -- display in short format
0151     ///     -  \c m or \c medium -- display in medium format.
0152     ///     -  \c l or \c long -- display in long format.
0153     ///     -  \c f or \c full -- display in full format.
0154     ///     .
0155     /// -  \c ftime with string (quoted) parameter -- display as with \c strftime see, \c as::ftime manipulator
0156     /// -  \c spell or \c spellout -- spell the number.
0157     /// -  \c ord or \c ordinal -- format ordinal number (1st, 2nd... etc)
0158     /// -  \c left or \c < -- align to left.
0159     /// -  \c right or \c > -- align to right.
0160     /// -  \c width or \c w -- set field width (requires parameter).
0161     /// -  \c precision or \c p -- set precision (requires parameter).
0162     /// -  \c locale -- with parameter -- switch locale for current operation. This command generates locale
0163     ///     with formatting facets giving more fine grained control of formatting. For example:
0164     ///    \code
0165     ///    std::cout << format("Today {1,date} ({1,date,locale=he_IL.UTF-8@calendar=hebrew,date} Hebrew Date)") % date;
0166     ///    \endcode
0167     /// -  \c timezone or \c tz -- the name of the timezone to display the time in. For example:\n
0168     ///    \code
0169     ///    std::cout << format("Time is: Local {1,time}, ({1,time,tz=EET} Eastern European Time)") % date;
0170     ///    \endcode
0171     /// -  \c local - display the time in local time
0172     /// -  \c gmt - display the time in UTC time scale
0173     ///    \code
0174     ///    std::cout << format("Local time is: {1,time,local}, universal time is {1,time,gmt}") % time;
0175     ///    \endcode
0176     ///
0177     ///
0178     /// Invalid formatting strings are silently ignored.
0179     /// This protects against a translator crashing the program in an unexpected location.
0180     template<typename CharType>
0181     class basic_format {
0182         int throw_if_params_bound() const;
0183 
0184     public:
0185         typedef CharType char_type;                    ///< Underlying character type
0186         typedef basic_message<char_type> message_type; ///< The translation message type
0187         /// \cond INTERNAL
0188         typedef detail::formattible<CharType> formattible_type;
0189         /// \endcond
0190 
0191         typedef std::basic_string<CharType> string_type;  ///< string type for this type of character
0192         typedef std::basic_ostream<CharType> stream_type; ///< output stream type for this type of character
0193 
0194         /// Create a format class for \a format_string
0195         basic_format(const string_type& format_string) : format_(format_string), translate_(false), parameters_count_(0)
0196         {}
0197         /// Create a format class using message \a trans. The message if translated first according
0198         /// to the rules of the target locale and then interpreted as a format string
0199         basic_format(const message_type& trans) : message_(trans), translate_(true), parameters_count_(0) {}
0200 
0201         /// Non-copyable
0202         basic_format(const basic_format& other) = delete;
0203         void operator=(const basic_format& other) = delete;
0204         /// Moveable
0205         basic_format(basic_format&& other) :
0206             message_((other.throw_if_params_bound(), std::move(other.message_))), format_(std::move(other.format_)),
0207             translate_(other.translate_), parameters_count_(0)
0208         {}
0209         basic_format& operator=(basic_format&& other)
0210         {
0211             other.throw_if_params_bound();
0212             message_ = std::move(other.message_);
0213             format_ = std::move(other.format_);
0214             translate_ = other.translate_;
0215             parameters_count_ = 0;
0216             ext_params_.clear();
0217             return *this;
0218         }
0219 
0220         /// Add new parameter to the format list. The object should be a type
0221         /// with defined expression out << object where \c out is \c std::basic_ostream.
0222         ///
0223         /// A reference to the object is stored, so do not store the format object longer
0224         /// than the lifetime of the parameter.
0225         /// It is advisable to directly print the result:
0226         /// \code
0227         /// basic_format<char> fmt("{0}");
0228         /// fmt % (5 + 2); // INVALID: Dangling reference
0229         /// int i = 42;
0230         /// return fmt % i; // INVALID: Dangling reference
0231         /// std::cout << fmt % (5 + 2); // OK, print immediately
0232         /// return (fmt % (5 + 2)).str(); // OK, convert immediately to string
0233         /// \endcode
0234         template<typename Formattible>
0235         basic_format& operator%(const Formattible& object)
0236         {
0237             add(formattible_type(object));
0238             return *this;
0239         }
0240 
0241         /// Format a string using a locale \a loc
0242         string_type str(const std::locale& loc = std::locale()) const
0243         {
0244             std::basic_ostringstream<CharType> buffer;
0245             buffer.imbue(loc);
0246             write(buffer);
0247             return buffer.str();
0248         }
0249 
0250         /// write a formatted string to output stream \a out using out's locale
0251         void write(stream_type& out) const
0252         {
0253             string_type format;
0254             if(translate_)
0255                 format = message_.str(out.getloc(), ios_info::get(out).domain_id());
0256             else
0257                 format = format_;
0258 
0259             format_output(out, format);
0260         }
0261 
0262     private:
0263         class format_guard {
0264         public:
0265             format_guard(detail::format_parser& fmt) : fmt_(fmt), restored_(false) {}
0266             void restore()
0267             {
0268                 if(restored_)
0269                     return;
0270                 fmt_.restore();
0271                 restored_ = true;
0272             }
0273             ~format_guard()
0274             {
0275                 // clang-format off
0276                 try { restore(); } catch(...) {}
0277                 // clang-format on
0278             }
0279 
0280         private:
0281             detail::format_parser& fmt_;
0282             bool restored_;
0283         };
0284 
0285         void format_output(stream_type& out, const string_type& sformat) const
0286         {
0287             constexpr char_type obrk = '{';
0288             constexpr char_type cbrk = '}';
0289             constexpr char_type eq = '=';
0290             constexpr char_type comma = ',';
0291             constexpr char_type quote = '\'';
0292 
0293             const size_t size = sformat.size();
0294             const CharType* format = sformat.c_str();
0295             for(size_t pos = 0; format[pos];) {
0296                 if(format[pos] != obrk) {
0297                     if(format[pos] == cbrk && format[pos + 1] == cbrk) {
0298                         // Escaped closing brace
0299                         out << cbrk;
0300                         pos += 2;
0301                     } else {
0302                         out << format[pos];
0303                         pos++;
0304                     }
0305                     continue;
0306                 }
0307                 pos++;
0308                 if(format[pos] == obrk) {
0309                     // Escaped opening brace
0310                     out << obrk;
0311                     pos++;
0312                     continue;
0313                 }
0314 
0315                 detail::format_parser fmt(out, static_cast<void*>(&out), &basic_format::imbue_locale);
0316 
0317                 format_guard guard(fmt);
0318 
0319                 while(pos < size) {
0320                     std::string key;
0321                     std::string svalue;
0322                     string_type value;
0323                     bool use_svalue = true;
0324                     for(char_type c = format[pos]; !(c == 0 || c == comma || c == eq || c == cbrk); c = format[++pos]) {
0325                         key += static_cast<char>(c);
0326                     }
0327 
0328                     if(format[pos] == eq) {
0329                         pos++;
0330                         if(format[pos] == quote) {
0331                             pos++;
0332                             use_svalue = false;
0333                             while(format[pos]) {
0334                                 if(format[pos] == quote) {
0335                                     if(format[pos + 1] == quote) {
0336                                         value += quote;
0337                                         pos += 2;
0338                                     } else {
0339                                         pos++;
0340                                         break;
0341                                     }
0342                                 } else {
0343                                     value += format[pos];
0344                                     pos++;
0345                                 }
0346                             }
0347                         } else {
0348                             char_type c;
0349                             while((c = format[pos]) != 0 && c != comma && c != cbrk) {
0350                                 svalue += static_cast<char>(c);
0351                                 pos++;
0352                             }
0353                         }
0354                     }
0355 
0356                     if(use_svalue)
0357                         fmt.set_one_flag(key, svalue);
0358                     else
0359                         fmt.set_flag_with_str(key, value);
0360 
0361                     if(format[pos] == comma)
0362                         pos++;
0363                     else {
0364                         if(format[pos] == cbrk) {
0365                             unsigned position = fmt.get_position();
0366                             out << get(position);
0367                             pos++;
0368                         }
0369                         break;
0370                     }
0371                 }
0372             }
0373         }
0374 
0375         void add(const formattible_type& param)
0376         {
0377             if(parameters_count_ >= base_params_)
0378                 ext_params_.push_back(param);
0379             else
0380                 parameters_[parameters_count_] = param;
0381             parameters_count_++;
0382         }
0383 
0384         formattible_type get(unsigned id) const
0385         {
0386             if(id >= parameters_count_)
0387                 return formattible_type();
0388             else if(id >= base_params_)
0389                 return ext_params_[id - base_params_];
0390             else
0391                 return parameters_[id];
0392         }
0393 
0394         static void imbue_locale(void* ptr, const std::locale& l) { static_cast<stream_type*>(ptr)->imbue(l); }
0395 
0396         static constexpr unsigned base_params_ = 8;
0397 
0398         message_type message_;
0399         string_type format_;
0400         bool translate_;
0401 
0402         formattible_type parameters_[base_params_];
0403         unsigned parameters_count_;
0404         std::vector<formattible_type> ext_params_;
0405     };
0406 
0407     /// Write formatted message to stream.
0408     ///
0409     /// This operator actually causes actual text formatting. It uses the locale of \a out stream
0410     template<typename CharType>
0411     std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& out, const basic_format<CharType>& fmt)
0412     {
0413         fmt.write(out);
0414         return out;
0415     }
0416 
0417     /// Definition of char based format
0418     typedef basic_format<char> format;
0419     /// Definition of wchar_t based format
0420     typedef basic_format<wchar_t> wformat;
0421 #ifndef BOOST_LOCALE_NO_CXX20_STRING8
0422     /// Definition of char8_t based format
0423     typedef basic_format<char8_t> u8format;
0424 #endif
0425 
0426 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
0427     /// Definition of char16_t based format
0428     typedef basic_format<char16_t> u16format;
0429 #endif
0430 
0431 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
0432     /// Definition of char32_t based format
0433     typedef basic_format<char32_t> u32format;
0434 #endif
0435 
0436     template<typename CharType>
0437     int basic_format<CharType>::throw_if_params_bound() const
0438     {
0439         if(parameters_count_)
0440             throw std::invalid_argument("Can't move a basic_format with bound parameters");
0441         return 0;
0442     }
0443     /// @}
0444 }} // namespace boost::locale
0445 
0446 #ifdef BOOST_MSVC
0447 #    pragma warning(pop)
0448 #endif
0449 
0450 /// \example hello.cpp
0451 ///
0452 /// Basic example of using various functions provided by this library
0453 ///
0454 /// \example whello.cpp
0455 ///
0456 /// Basic example of using various functions with wide strings provided by this library
0457 
0458 #endif