1 // 2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See 5 // accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt) 7 // 8 #ifndef BOOST_LOCALE_PREDEFINED_FORMATTERS_HPP_INCLUDED 9 #define BOOST_LOCALE_PREDEFINED_FORMATTERS_HPP_INCLUDED 10 11 #include <string> 12 #include <memory> 13 #include <boost/cstdint.hpp> 14 #include <boost/thread.hpp> 15 #include <boost/locale/config.hpp> 16 #include <boost/locale/hold_ptr.hpp> 17 18 #include <unicode/locid.h> 19 #include <unicode/numfmt.h> 20 #include <unicode/rbnf.h> 21 #include <unicode/datefmt.h> 22 #include <unicode/smpdtfmt.h> 23 #include <unicode/decimfmt.h> 24 25 namespace boost { 26 namespace locale { 27 namespace impl_icu { 28 29 class icu_formatters_cache : public std::locale::facet { 30 public: 31 32 static std::locale::id id; 33 icu_formatters_cache(icu::Locale const & locale)34 icu_formatters_cache(icu::Locale const &locale) : 35 locale_(locale) 36 { 37 38 static const icu::DateFormat::EStyle styles[4] = { 39 icu::DateFormat::kShort, 40 icu::DateFormat::kMedium, 41 icu::DateFormat::kLong, 42 icu::DateFormat::kFull 43 }; 44 45 46 for(int i=0;i<4;i++) { 47 hold_ptr<icu::DateFormat> fmt(icu::DateFormat::createDateInstance(styles[i],locale)); 48 icu::SimpleDateFormat *sfmt = dynamic_cast<icu::SimpleDateFormat*>(fmt.get()); 49 if(sfmt) { 50 sfmt->toPattern(date_format_[i]); 51 } 52 } 53 54 for(int i=0;i<4;i++) { 55 hold_ptr<icu::DateFormat> fmt(icu::DateFormat::createTimeInstance(styles[i],locale)); 56 icu::SimpleDateFormat *sfmt = dynamic_cast<icu::SimpleDateFormat*>(fmt.get()); 57 if(sfmt) { 58 sfmt->toPattern(time_format_[i]); 59 } 60 } 61 62 for(int i=0;i<4;i++) { 63 for(int j=0;j<4;j++) { 64 hold_ptr<icu::DateFormat> fmt( 65 icu::DateFormat::createDateTimeInstance(styles[i],styles[j],locale)); 66 icu::SimpleDateFormat *sfmt = dynamic_cast<icu::SimpleDateFormat*>(fmt.get()); 67 if(sfmt) { 68 sfmt->toPattern(date_time_format_[i][j]); 69 } 70 } 71 } 72 73 74 } 75 76 typedef enum { 77 fmt_number, 78 fmt_sci, 79 fmt_curr_nat, 80 fmt_curr_iso, 81 fmt_per, 82 fmt_spell, 83 fmt_ord, 84 fmt_count 85 } fmt_type; 86 number_format(fmt_type type) const87 icu::NumberFormat *number_format(fmt_type type) const 88 { 89 icu::NumberFormat *ptr = number_format_[type].get(); 90 if(ptr) 91 return ptr; 92 UErrorCode err=U_ZERO_ERROR; 93 hold_ptr<icu::NumberFormat> ap; 94 95 switch(type) { 96 case fmt_number: 97 ap.reset(icu::NumberFormat::createInstance(locale_,err)); 98 break; 99 case fmt_sci: 100 ap.reset(icu::NumberFormat::createScientificInstance(locale_,err)); 101 break; 102 #if U_ICU_VERSION_MAJOR_NUM*100 + U_ICU_VERSION_MINOR_NUM >= 402 103 #if U_ICU_VERSION_MAJOR_NUM*100 + U_ICU_VERSION_MINOR_NUM >= 408 104 case fmt_curr_nat: 105 ap.reset(icu::NumberFormat::createInstance(locale_,UNUM_CURRENCY,err)); 106 break; 107 case fmt_curr_iso: 108 ap.reset(icu::NumberFormat::createInstance(locale_,UNUM_CURRENCY_ISO,err)); 109 break; 110 #else 111 case fmt_curr_nat: 112 ap.reset(icu::NumberFormat::createInstance(locale_,icu::NumberFormat::kCurrencyStyle,err)); 113 break; 114 case fmt_curr_iso: 115 ap.reset(icu::NumberFormat::createInstance(locale_,icu::NumberFormat::kIsoCurrencyStyle,err)); 116 break; 117 #endif 118 #else 119 case fmt_curr_nat: 120 case fmt_curr_iso: 121 ap.reset(icu::NumberFormat::createCurrencyInstance(locale_,err)); 122 break; 123 #endif 124 case fmt_per: 125 ap.reset(icu::NumberFormat::createPercentInstance(locale_,err)); 126 break; 127 case fmt_spell: 128 ap.reset(new icu::RuleBasedNumberFormat(icu::URBNF_SPELLOUT,locale_,err)); 129 break; 130 case fmt_ord: 131 ap.reset(new icu::RuleBasedNumberFormat(icu::URBNF_ORDINAL,locale_,err)); 132 break; 133 default: 134 throw std::runtime_error("locale::internal error should not get there"); 135 } 136 137 test(err); 138 ptr = ap.get(); 139 number_format_[type].reset(ap.release()); 140 return ptr; 141 } 142 test(UErrorCode err) const143 void test(UErrorCode err) const 144 { 145 if(U_FAILURE(err)) 146 throw std::runtime_error("Failed to create a formatter"); 147 } 148 149 icu::UnicodeString date_format_[4]; 150 icu::UnicodeString time_format_[4]; 151 icu::UnicodeString date_time_format_[4][4]; 152 date_formatter() const153 icu::SimpleDateFormat *date_formatter() const 154 { 155 icu::SimpleDateFormat *p=date_formatter_.get(); 156 if(p) 157 return p; 158 159 hold_ptr<icu::DateFormat> fmt(icu::DateFormat::createDateTimeInstance( 160 icu::DateFormat::kMedium, 161 icu::DateFormat::kMedium, 162 locale_)); 163 164 if(dynamic_cast<icu::SimpleDateFormat *>(fmt.get())) { 165 p = static_cast<icu::SimpleDateFormat *>(fmt.release()); 166 date_formatter_.reset(p); 167 } 168 return p; 169 } 170 171 private: 172 173 mutable boost::thread_specific_ptr<icu::NumberFormat> number_format_[fmt_count]; 174 mutable boost::thread_specific_ptr<icu::SimpleDateFormat> date_formatter_; 175 icu::Locale locale_; 176 }; 177 178 179 180 } // namespace impl_icu 181 } // namespace locale 182 } // namespace boost 183 184 185 186 #endif 187 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 188