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