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 #define BOOST_LOCALE_SOURCE
9 #include <locale>
10 #include <string>
11 #include <ios>
12 #include <limits>
13 #include "formatter.hpp"
14 #include <boost/locale/formatting.hpp>
15 #include "all_generator.hpp"
16 #include "cdata.hpp"
17 #include <algorithm>
18 #include "predefined_formatters.hpp"
19
20 namespace boost {
21 namespace locale {
22 namespace impl_icu {
23
24 namespace details {
25 template<typename V,int n=std::numeric_limits<V>::digits,bool integer=std::numeric_limits<V>::is_integer>
26 struct cast_traits;
27
28 template<typename v>
29 struct cast_traits<v,7,true> {
30 typedef int32_t cast_type;
31 };
32 template<typename v>
33 struct cast_traits<v,8,true> {
34 typedef int32_t cast_type;
35 };
36
37 template<typename v>
38 struct cast_traits<v,15,true> {
39 typedef int32_t cast_type;
40 };
41 template<typename v>
42 struct cast_traits<v,16,true> {
43 typedef int32_t cast_type;
44 };
45 template<typename v>
46 struct cast_traits<v,31,true> {
47 typedef int32_t cast_type;
48 };
49 template<typename v>
50 struct cast_traits<v,32,true> {
51 typedef int64_t cast_type;
52 };
53 template<typename v>
54 struct cast_traits<v,63,true> {
55 typedef int64_t cast_type;
56 };
57 template<typename v>
58 struct cast_traits<v,64,true> {
59 typedef int64_t cast_type;
60 };
61 template<typename V,int u>
62 struct cast_traits<V,u,false> {
63 typedef double cast_type;
64 };
65
66 // ICU does not support uint64_t values so fallback
67 // to POSIX formatting
68 template< typename V,
69 bool Sig=std::numeric_limits<V>::is_signed,
70 bool Int=std::numeric_limits<V>::is_integer,
71 bool Big=(sizeof(V) >= 8)
72 >
73 struct use_parent_traits
74 {
useboost::locale::impl_icu::details::use_parent_traits75 static bool use(V /*v*/) { return false; }
76 };
77 template<typename V>
78 struct use_parent_traits<V,false,true,true>
79 {
useboost::locale::impl_icu::details::use_parent_traits80 static bool use(V v) { return static_cast<int64_t>(v) < 0; }
81 };
82
83 }
84
85
86
87 class num_base {
88 protected:
89
90 template<typename ValueType>
use_parent(std::ios_base & ios,ValueType v)91 static bool use_parent(std::ios_base &ios,ValueType v)
92 {
93 uint64_t flg = ios_info::get(ios).display_flags();
94 if(flg == flags::posix)
95 return true;
96 if(details::use_parent_traits<ValueType>::use(v))
97 return true;
98
99 if(!std::numeric_limits<ValueType>::is_integer)
100 return false;
101
102 if(flg == flags::number && (ios.flags() & std::ios_base::basefield) != std::ios_base::dec) {
103 return true;
104 }
105 return false;
106 }
107 };
108
109
110 template<typename CharType>
111 class num_format : public std::num_put<CharType>, protected num_base
112 {
113 public:
114 typedef typename std::num_put<CharType>::iter_type iter_type;
115 typedef std::basic_string<CharType> string_type;
116 typedef CharType char_type;
117 typedef formatter<CharType> formatter_type;
118 typedef std::auto_ptr<formatter_type> formatter_ptr;
119
num_format(cdata const & d,size_t refs=0)120 num_format(cdata const &d,size_t refs = 0) :
121 std::num_put<CharType>(refs),
122 loc_(d.locale),
123 enc_(d.encoding)
124 {
125 }
126 protected:
127
128
do_put(iter_type out,std::ios_base & ios,char_type fill,long val) const129 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long val) const
130 {
131 return do_real_put(out,ios,fill,val);
132 }
do_put(iter_type out,std::ios_base & ios,char_type fill,unsigned long val) const133 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long val) const
134 {
135 return do_real_put(out,ios,fill,val);
136 }
do_put(iter_type out,std::ios_base & ios,char_type fill,double val) const137 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, double val) const
138 {
139 return do_real_put(out,ios,fill,val);
140 }
do_put(iter_type out,std::ios_base & ios,char_type fill,long double val) const141 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long double val) const
142 {
143 return do_real_put(out,ios,fill,val);
144 }
145
146 #ifndef BOOST_NO_LONG_LONG
do_put(iter_type out,std::ios_base & ios,char_type fill,long long val) const147 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long long val) const
148 {
149 return do_real_put(out,ios,fill,val);
150 }
do_put(iter_type out,std::ios_base & ios,char_type fill,unsigned long long val) const151 virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long long val) const
152 {
153 return do_real_put(out,ios,fill,val);
154 }
155 #endif
156
157
158 private:
159
160
161
162 template<typename ValueType>
do_real_put(iter_type out,std::ios_base & ios,char_type fill,ValueType val) const163 iter_type do_real_put (iter_type out, std::ios_base &ios, char_type fill, ValueType val) const
164 {
165 formatter_ptr formatter;
166
167 if(use_parent<ValueType>(ios,val) || (formatter = formatter_type::create(ios,loc_,enc_)).get() == 0) {
168 return std::num_put<char_type>::do_put(out,ios,fill,val);
169 }
170
171 size_t code_points;
172 typedef typename details::cast_traits<ValueType>::cast_type cast_type;
173 string_type const &str = formatter->format(static_cast<cast_type>(val),code_points);
174 std::streamsize on_left=0,on_right = 0,points = code_points;
175 if(points < ios.width()) {
176 std::streamsize n = ios.width() - points;
177
178 std::ios_base::fmtflags flags = ios.flags() & std::ios_base::adjustfield;
179
180 //
181 // We do not really know internal point, so we assume that it does not
182 // exist. So according to the standard field should be right aligned
183 //
184 if(flags != std::ios_base::left)
185 on_left = n;
186 on_right = n - on_left;
187 }
188 while(on_left > 0) {
189 *out++ = fill;
190 on_left--;
191 }
192 std::copy(str.begin(),str.end(),out);
193 while(on_right > 0) {
194 *out++ = fill;
195 on_right--;
196 }
197 ios.width(0);
198 return out;
199
200 }
201
202 icu::Locale loc_;
203 std::string enc_;
204
205 }; /// num_format
206
207
208 template<typename CharType>
209 class num_parse : public std::num_get<CharType>, protected num_base
210 {
211 public:
num_parse(cdata const & d,size_t refs=0)212 num_parse(cdata const &d,size_t refs = 0) :
213 std::num_get<CharType>(refs),
214 loc_(d.locale),
215 enc_(d.encoding)
216 {
217 }
218 protected:
219 typedef typename std::num_get<CharType>::iter_type iter_type;
220 typedef std::basic_string<CharType> string_type;
221 typedef CharType char_type;
222 typedef formatter<CharType> formatter_type;
223 typedef std::auto_ptr<formatter_type> formatter_ptr;
224 typedef std::basic_istream<CharType> stream_type;
225
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,long & val) const226 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long &val) const
227 {
228 return do_real_get(in,end,ios,err,val);
229 }
230
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned short & val) const231 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned short &val) const
232 {
233 return do_real_get(in,end,ios,err,val);
234 }
235
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned int & val) const236 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned int &val) const
237 {
238 return do_real_get(in,end,ios,err,val);
239 }
240
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned long & val) const241 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned long &val) const
242 {
243 return do_real_get(in,end,ios,err,val);
244 }
245
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,float & val) const246 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,float &val) const
247 {
248 return do_real_get(in,end,ios,err,val);
249 }
250
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,double & val) const251 virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,double &val) const
252 {
253 return do_real_get(in,end,ios,err,val);
254 }
255
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,long double & val) const256 virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long double &val) const
257 {
258 return do_real_get(in,end,ios,err,val);
259 }
260
261 #ifndef BOOST_NO_LONG_LONG
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,long long & val) const262 virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long long &val) const
263 {
264 return do_real_get(in,end,ios,err,val);
265 }
266
do_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,unsigned long long & val) const267 virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned long long &val) const
268 {
269 return do_real_get(in,end,ios,err,val);
270 }
271
272 #endif
273
274 private:
275
276
277 //
278 // This is not really an efficient solution, but it works
279 //
280 template<typename ValueType>
do_real_get(iter_type in,iter_type end,std::ios_base & ios,std::ios_base::iostate & err,ValueType & val) const281 iter_type do_real_get(iter_type in,iter_type end,std::ios_base &ios,std::ios_base::iostate &err,ValueType &val) const
282 {
283 formatter_ptr formatter;
284 stream_type *stream_ptr = dynamic_cast<stream_type *>(&ios);
285
286 if(!stream_ptr || use_parent<ValueType>(ios,0) || (formatter = formatter_type::create(ios,loc_,enc_)).get()==0) {
287 return std::num_get<CharType>::do_get(in,end,ios,err,val);
288 }
289
290 typedef typename details::cast_traits<ValueType>::cast_type cast_type;
291 string_type tmp;
292 tmp.reserve(64);
293
294 CharType c;
295 while(in!=end && (((c=*in)<=32 && (c>0)) || c==127)) // Assuming that ASCII is a subset
296 ++in;
297
298 while(tmp.size() < 4096 && in!=end && *in!='\n') {
299 tmp += *in++;
300 }
301
302 cast_type value;
303 size_t parsed_chars;
304
305 if((parsed_chars = formatter->parse(tmp,value))==0 || !valid<ValueType>(value)) {
306 err |= std::ios_base::failbit;
307 }
308 else {
309 val=static_cast<ValueType>(value);
310 }
311
312 for(size_t n=tmp.size();n>parsed_chars;n--) {
313 stream_ptr->putback(tmp[n-1]);
314 }
315
316 in = iter_type(*stream_ptr);
317
318 if(in==end)
319 err |=std::ios_base::eofbit;
320 return in;
321 }
322
323 template<typename ValueType,typename CastedType>
valid(CastedType v) const324 bool valid(CastedType v) const
325 {
326 typedef std::numeric_limits<ValueType> value_limits;
327 typedef std::numeric_limits<CastedType> casted_limits;
328 if(v < 0 && value_limits::is_signed == false)
329 return false;
330
331 static const CastedType max_val = value_limits::max();
332
333 if(sizeof(CastedType) > sizeof(ValueType) && v > max_val)
334 return false;
335
336 if(value_limits::is_integer == casted_limits::is_integer) {
337 return true;
338 }
339 if(value_limits::is_integer) { // and casted is not
340 if(static_cast<CastedType>(static_cast<ValueType>(v))!=v)
341 return false;
342 }
343 return true;
344 }
345
346 icu::Locale loc_;
347 std::string enc_;
348
349 };
350
351
352 template<typename CharType>
install_formatting_facets(std::locale const & in,cdata const & cd)353 std::locale install_formatting_facets(std::locale const &in,cdata const &cd)
354 {
355 std::locale tmp=std::locale(in,new num_format<CharType>(cd));
356 if(!std::has_facet<icu_formatters_cache>(in)) {
357 tmp=std::locale(tmp,new icu_formatters_cache(cd.locale));
358 }
359 return tmp;
360 }
361
362 template<typename CharType>
install_parsing_facets(std::locale const & in,cdata const & cd)363 std::locale install_parsing_facets(std::locale const &in,cdata const &cd)
364 {
365 std::locale tmp=std::locale(in,new num_parse<CharType>(cd));
366 if(!std::has_facet<icu_formatters_cache>(in)) {
367 tmp=std::locale(tmp,new icu_formatters_cache(cd.locale));
368 }
369 return tmp;
370 }
371
create_formatting(std::locale const & in,cdata const & cd,character_facet_type type)372 std::locale create_formatting(std::locale const &in,cdata const &cd,character_facet_type type)
373 {
374 switch(type) {
375 case char_facet:
376 return install_formatting_facets<char>(in,cd);
377 case wchar_t_facet:
378 return install_formatting_facets<wchar_t>(in,cd);
379 #ifdef BOOST_HAS_CHAR16_T
380 case char16_t_facet:
381 return install_formatting_facets<char16_t>(in,cd);
382 #endif
383 #ifdef BOOST_HAS_CHAR32_T
384 case char32_t_facet:
385 return install_formatting_facets<char32_t>(in,cd);
386 #endif
387 default:
388 return in;
389 }
390 }
391
create_parsing(std::locale const & in,cdata const & cd,character_facet_type type)392 std::locale create_parsing(std::locale const &in,cdata const &cd,character_facet_type type)
393 {
394 switch(type) {
395 case char_facet:
396 return install_parsing_facets<char>(in,cd);
397 case wchar_t_facet:
398 return install_parsing_facets<wchar_t>(in,cd);
399 #ifdef BOOST_HAS_CHAR16_T
400 case char16_t_facet:
401 return install_parsing_facets<char16_t>(in,cd);
402 #endif
403 #ifdef BOOST_HAS_CHAR32_T
404 case char32_t_facet:
405 return install_parsing_facets<char32_t>(in,cd);
406 #endif
407 default:
408 return in;
409 }
410 }
411
412
413 } // impl_icu
414
415 } // locale
416 } //boost
417
418
419
420 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
421