• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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