File indexing completed on 2025-01-18 09:39:16
0001
0002
0003
0004
0005
0006
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
0027
0028
0029
0030
0031
0032
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* )
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 };
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 }
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180 template<typename CharType>
0181 class basic_format {
0182 int throw_if_params_bound() const;
0183
0184 public:
0185 typedef CharType char_type;
0186 typedef basic_message<char_type> message_type;
0187
0188 typedef detail::formattible<CharType> formattible_type;
0189
0190
0191 typedef std::basic_string<CharType> string_type;
0192 typedef std::basic_ostream<CharType> stream_type;
0193
0194
0195 basic_format(const string_type& format_string) : format_(format_string), translate_(false), parameters_count_(0)
0196 {}
0197
0198
0199 basic_format(const message_type& trans) : message_(trans), translate_(true), parameters_count_(0) {}
0200
0201
0202 basic_format(const basic_format& other) = delete;
0203 void operator=(const basic_format& other) = delete;
0204
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
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234 template<typename Formattible>
0235 basic_format& operator%(const Formattible& object)
0236 {
0237 add(formattible_type(object));
0238 return *this;
0239 }
0240
0241
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
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
0276 try { restore(); } catch(...) {}
0277
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
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
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
0408
0409
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
0418 typedef basic_format<char> format;
0419
0420 typedef basic_format<wchar_t> wformat;
0421 #ifndef BOOST_LOCALE_NO_CXX20_STRING8
0422
0423 typedef basic_format<char8_t> u8format;
0424 #endif
0425
0426 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
0427
0428 typedef basic_format<char16_t> u16format;
0429 #endif
0430
0431 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
0432
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 }}
0445
0446 #ifdef BOOST_MSVC
0447 # pragma warning(pop)
0448 #endif
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458 #endif