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