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