| // |
| // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See |
| // accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // |
| #define BOOST_LOCALE_SOURCE |
| #include <locale> |
| #include <string> |
| #include <ios> |
| #include <limits> |
| #include "formatter.hpp" |
| #include <boost/locale/formatting.hpp> |
| #include "all_generator.hpp" |
| #include "cdata.hpp" |
| #include <algorithm> |
| #include "predefined_formatters.hpp" |
| |
| namespace boost { |
| namespace locale { |
| namespace impl_icu { |
| |
| namespace details { |
| template<typename V,int n=std::numeric_limits<V>::digits,bool integer=std::numeric_limits<V>::is_integer> |
| struct cast_traits; |
| |
| template<typename v> |
| struct cast_traits<v,7,true> { |
| typedef int32_t cast_type; |
| }; |
| template<typename v> |
| struct cast_traits<v,8,true> { |
| typedef int32_t cast_type; |
| }; |
| |
| template<typename v> |
| struct cast_traits<v,15,true> { |
| typedef int32_t cast_type; |
| }; |
| template<typename v> |
| struct cast_traits<v,16,true> { |
| typedef int32_t cast_type; |
| }; |
| template<typename v> |
| struct cast_traits<v,31,true> { |
| typedef int32_t cast_type; |
| }; |
| template<typename v> |
| struct cast_traits<v,32,true> { |
| typedef int64_t cast_type; |
| }; |
| template<typename v> |
| struct cast_traits<v,63,true> { |
| typedef int64_t cast_type; |
| }; |
| template<typename v> |
| struct cast_traits<v,64,true> { |
| typedef int64_t cast_type; |
| }; |
| template<typename V,int u> |
| struct cast_traits<V,u,false> { |
| typedef double cast_type; |
| }; |
| |
| // ICU does not support uint64_t values so fallback |
| // to POSIX formatting |
| template< typename V, |
| bool Sig=std::numeric_limits<V>::is_signed, |
| bool Int=std::numeric_limits<V>::is_integer, |
| bool Big=(sizeof(V) >= 8) |
| > |
| struct use_parent_traits |
| { |
| static bool use(V /*v*/) { return false; } |
| }; |
| template<typename V> |
| struct use_parent_traits<V,false,true,true> |
| { |
| static bool use(V v) { return static_cast<int64_t>(v) < 0; } |
| }; |
| |
| } |
| |
| |
| |
| class num_base { |
| protected: |
| |
| template<typename ValueType> |
| static bool use_parent(std::ios_base &ios,ValueType v) |
| { |
| uint64_t flg = ios_info::get(ios).display_flags(); |
| if(flg == flags::posix) |
| return true; |
| if(details::use_parent_traits<ValueType>::use(v)) |
| return true; |
| |
| if(!std::numeric_limits<ValueType>::is_integer) |
| return false; |
| |
| if(flg == flags::number && (ios.flags() & std::ios_base::basefield) != std::ios_base::dec) { |
| return true; |
| } |
| return false; |
| } |
| }; |
| |
| |
| template<typename CharType> |
| class num_format : public std::num_put<CharType>, protected num_base |
| { |
| public: |
| typedef typename std::num_put<CharType>::iter_type iter_type; |
| typedef std::basic_string<CharType> string_type; |
| typedef CharType char_type; |
| typedef formatter<CharType> formatter_type; |
| typedef std::auto_ptr<formatter_type> formatter_ptr; |
| |
| num_format(cdata const &d,size_t refs = 0) : |
| std::num_put<CharType>(refs), |
| loc_(d.locale), |
| enc_(d.encoding) |
| { |
| } |
| protected: |
| |
| |
| virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long val) const |
| { |
| return do_real_put(out,ios,fill,val); |
| } |
| virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long val) const |
| { |
| return do_real_put(out,ios,fill,val); |
| } |
| virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, double val) const |
| { |
| return do_real_put(out,ios,fill,val); |
| } |
| virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long double val) const |
| { |
| return do_real_put(out,ios,fill,val); |
| } |
| |
| #ifndef BOOST_NO_LONG_LONG |
| virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, long long val) const |
| { |
| return do_real_put(out,ios,fill,val); |
| } |
| virtual iter_type do_put (iter_type out, std::ios_base &ios, char_type fill, unsigned long long val) const |
| { |
| return do_real_put(out,ios,fill,val); |
| } |
| #endif |
| |
| |
| private: |
| |
| |
| |
| template<typename ValueType> |
| iter_type do_real_put (iter_type out, std::ios_base &ios, char_type fill, ValueType val) const |
| { |
| formatter_ptr formatter; |
| |
| if(use_parent<ValueType>(ios,val) || (formatter = formatter_type::create(ios,loc_,enc_)).get() == 0) { |
| return std::num_put<char_type>::do_put(out,ios,fill,val); |
| } |
| |
| size_t code_points; |
| typedef typename details::cast_traits<ValueType>::cast_type cast_type; |
| string_type const &str = formatter->format(static_cast<cast_type>(val),code_points); |
| std::streamsize on_left=0,on_right = 0,points = code_points; |
| if(points < ios.width()) { |
| std::streamsize n = ios.width() - points; |
| |
| std::ios_base::fmtflags flags = ios.flags() & std::ios_base::adjustfield; |
| |
| // |
| // We do not really know internal point, so we assume that it does not |
| // exist. So according to the standard field should be right aligned |
| // |
| if(flags != std::ios_base::left) |
| on_left = n; |
| on_right = n - on_left; |
| } |
| while(on_left > 0) { |
| *out++ = fill; |
| on_left--; |
| } |
| std::copy(str.begin(),str.end(),out); |
| while(on_right > 0) { |
| *out++ = fill; |
| on_right--; |
| } |
| ios.width(0); |
| return out; |
| |
| } |
| |
| icu::Locale loc_; |
| std::string enc_; |
| |
| }; /// num_format |
| |
| |
| template<typename CharType> |
| class num_parse : public std::num_get<CharType>, protected num_base |
| { |
| public: |
| num_parse(cdata const &d,size_t refs = 0) : |
| std::num_get<CharType>(refs), |
| loc_(d.locale), |
| enc_(d.encoding) |
| { |
| } |
| protected: |
| typedef typename std::num_get<CharType>::iter_type iter_type; |
| typedef std::basic_string<CharType> string_type; |
| typedef CharType char_type; |
| typedef formatter<CharType> formatter_type; |
| typedef std::auto_ptr<formatter_type> formatter_ptr; |
| typedef std::basic_istream<CharType> stream_type; |
| |
| virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long &val) const |
| { |
| return do_real_get(in,end,ios,err,val); |
| } |
| |
| virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned short &val) const |
| { |
| return do_real_get(in,end,ios,err,val); |
| } |
| |
| virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned int &val) const |
| { |
| return do_real_get(in,end,ios,err,val); |
| } |
| |
| virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,unsigned long &val) const |
| { |
| return do_real_get(in,end,ios,err,val); |
| } |
| |
| virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,float &val) const |
| { |
| return do_real_get(in,end,ios,err,val); |
| } |
| |
| virtual iter_type do_get(iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,double &val) const |
| { |
| return do_real_get(in,end,ios,err,val); |
| } |
| |
| virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long double &val) const |
| { |
| return do_real_get(in,end,ios,err,val); |
| } |
| |
| #ifndef BOOST_NO_LONG_LONG |
| virtual iter_type do_get (iter_type in, iter_type end, std::ios_base &ios,std::ios_base::iostate &err,long long &val) const |
| { |
| return do_real_get(in,end,ios,err,val); |
| } |
| |
| 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 |
| { |
| return do_real_get(in,end,ios,err,val); |
| } |
| |
| #endif |
| |
| private: |
| |
| |
| // |
| // This is not really an efficient solution, but it works |
| // |
| template<typename ValueType> |
| iter_type do_real_get(iter_type in,iter_type end,std::ios_base &ios,std::ios_base::iostate &err,ValueType &val) const |
| { |
| formatter_ptr formatter; |
| stream_type *stream_ptr = dynamic_cast<stream_type *>(&ios); |
| |
| if(!stream_ptr || use_parent<ValueType>(ios,0) || (formatter = formatter_type::create(ios,loc_,enc_)).get()==0) { |
| return std::num_get<CharType>::do_get(in,end,ios,err,val); |
| } |
| |
| typedef typename details::cast_traits<ValueType>::cast_type cast_type; |
| string_type tmp; |
| tmp.reserve(64); |
| |
| CharType c; |
| while(in!=end && (((c=*in)<=32 && (c>0)) || c==127)) // Assuming that ASCII is a subset |
| ++in; |
| |
| while(tmp.size() < 4096 && in!=end && *in!='\n') { |
| tmp += *in++; |
| } |
| |
| cast_type value; |
| size_t parsed_chars; |
| |
| if((parsed_chars = formatter->parse(tmp,value))==0 || !valid<ValueType>(value)) { |
| err |= std::ios_base::failbit; |
| } |
| else { |
| val=static_cast<ValueType>(value); |
| } |
| |
| for(size_t n=tmp.size();n>parsed_chars;n--) { |
| stream_ptr->putback(tmp[n-1]); |
| } |
| |
| in = iter_type(*stream_ptr); |
| |
| if(in==end) |
| err |=std::ios_base::eofbit; |
| return in; |
| } |
| |
| template<typename ValueType,typename CastedType> |
| bool valid(CastedType v) const |
| { |
| typedef std::numeric_limits<ValueType> value_limits; |
| typedef std::numeric_limits<CastedType> casted_limits; |
| if(v < 0 && value_limits::is_signed == false) |
| return false; |
| |
| static const CastedType max_val = value_limits::max(); |
| |
| if(sizeof(CastedType) > sizeof(ValueType) && v > max_val) |
| return false; |
| |
| if(value_limits::is_integer == casted_limits::is_integer) { |
| return true; |
| } |
| if(value_limits::is_integer) { // and casted is not |
| if(static_cast<CastedType>(static_cast<ValueType>(v))!=v) |
| return false; |
| } |
| return true; |
| } |
| |
| icu::Locale loc_; |
| std::string enc_; |
| |
| }; |
| |
| |
| template<typename CharType> |
| std::locale install_formatting_facets(std::locale const &in,cdata const &cd) |
| { |
| std::locale tmp=std::locale(in,new num_format<CharType>(cd)); |
| if(!std::has_facet<icu_formatters_cache>(in)) { |
| tmp=std::locale(tmp,new icu_formatters_cache(cd.locale)); |
| } |
| return tmp; |
| } |
| |
| template<typename CharType> |
| std::locale install_parsing_facets(std::locale const &in,cdata const &cd) |
| { |
| std::locale tmp=std::locale(in,new num_parse<CharType>(cd)); |
| if(!std::has_facet<icu_formatters_cache>(in)) { |
| tmp=std::locale(tmp,new icu_formatters_cache(cd.locale)); |
| } |
| return tmp; |
| } |
| |
| std::locale create_formatting(std::locale const &in,cdata const &cd,character_facet_type type) |
| { |
| switch(type) { |
| case char_facet: |
| return install_formatting_facets<char>(in,cd); |
| case wchar_t_facet: |
| return install_formatting_facets<wchar_t>(in,cd); |
| #ifdef BOOST_HAS_CHAR16_T |
| case char16_t_facet: |
| return install_formatting_facets<char16_t>(in,cd); |
| #endif |
| #ifdef BOOST_HAS_CHAR32_T |
| case char32_t_facet: |
| return install_formatting_facets<char32_t>(in,cd); |
| #endif |
| default: |
| return in; |
| } |
| } |
| |
| std::locale create_parsing(std::locale const &in,cdata const &cd,character_facet_type type) |
| { |
| switch(type) { |
| case char_facet: |
| return install_parsing_facets<char>(in,cd); |
| case wchar_t_facet: |
| return install_parsing_facets<wchar_t>(in,cd); |
| #ifdef BOOST_HAS_CHAR16_T |
| case char16_t_facet: |
| return install_parsing_facets<char16_t>(in,cd); |
| #endif |
| #ifdef BOOST_HAS_CHAR32_T |
| case char32_t_facet: |
| return install_parsing_facets<char32_t>(in,cd); |
| #endif |
| default: |
| return in; |
| } |
| } |
| |
| |
| } // impl_icu |
| |
| } // locale |
| } //boost |
| |
| |
| |
| // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 |