aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/libs/locale/src/win32/collate.cpp
blob: 269d317ee3e88f60d5482492982cd819d5f29ee3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// 
//  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 <boost/locale/encoding.hpp> 
#include <boost/locale/generator.hpp> 
#include "api.hpp" 
#include "../shared/mo_hash.hpp" 
 
namespace boost { 
namespace locale { 
namespace impl_win { 
 
class utf8_collator : public collator<char> { 
public: 
    utf8_collator(winlocale lc,size_t refs = 0) :  
        collator<char>(refs), 
        lc_(lc) 
    { 
    } 
    virtual int do_compare(collator_base::level_type level,char const *lb,char const *le,char const *rb,char const *re) const 
    { 
        std::wstring l=conv::to_utf<wchar_t>(lb,le,"UTF-8"); 
        std::wstring r=conv::to_utf<wchar_t>(rb,re,"UTF-8"); 
        return wcscoll_l(level,l.c_str(),l.c_str()+l.size(),r.c_str(),r.c_str()+r.size(),lc_); 
    } 
    virtual long do_hash(collator_base::level_type level,char const *b,char const *e) const 
    { 
        std::string key = do_transform(level,b,e); 
        return gnu_gettext::pj_winberger_hash_function(key.c_str(),key.c_str() + key.size()); 
    } 
    virtual std::string do_transform(collator_base::level_type level,char const *b,char const *e) const 
    { 
        std::wstring tmp=conv::to_utf<wchar_t>(b,e,"UTF-8"); 
        std::wstring wkey = wcsxfrm_l(level,tmp.c_str(),tmp.c_str()+tmp.size(),lc_); 
        std::string key; 
        if(sizeof(wchar_t)==2) 
            key.reserve(wkey.size()*2); 
        else 
            key.reserve(wkey.size()*3); 
        for(unsigned i=0;i<wkey.size();i++) { 
            if(sizeof(wchar_t)==2) { 
                uint16_t tv = static_cast<uint16_t>(wkey[i]); 
                key += char(tv >> 8); 
                key += char(tv & 0xFF); 
            } 
            else { // 4 
                uint32_t tv = static_cast<uint32_t>(wkey[i]); 
                // 21 bit 
                key += char((tv >> 16) & 0xFF); 
                key += char((tv >> 8) & 0xFF); 
                key += char(tv & 0xFF); 
            } 
        } 
        return key; 
    } 
private: 
    winlocale lc_; 
}; 
 
 
class utf16_collator : public collator<wchar_t> { 
public: 
    typedef std::collate<wchar_t> wfacet; 
    utf16_collator(winlocale lc,size_t refs = 0) :  
        collator<wchar_t>(refs), 
        lc_(lc) 
    { 
    } 
    virtual int do_compare(collator_base::level_type level,wchar_t const *lb,wchar_t const *le,wchar_t const *rb,wchar_t const *re) const 
    { 
        return wcscoll_l(level,lb,le,rb,re,lc_); 
    } 
    virtual long do_hash(collator_base::level_type level,wchar_t const *b,wchar_t const *e) const 
    { 
        std::wstring key = do_transform(level,b,e); 
        char const *begin = reinterpret_cast<char const *>(key.c_str()); 
        char const *end = begin + key.size()*sizeof(wchar_t); 
        return gnu_gettext::pj_winberger_hash_function(begin,end); 
    } 
    virtual std::wstring do_transform(collator_base::level_type level,wchar_t const *b,wchar_t const *e) const 
    { 
        return wcsxfrm_l(level,b,e,lc_); 
    } 
private: 
    winlocale lc_; 
}; 
 
 
std::locale create_collate( std::locale const &in, 
                            winlocale const &lc, 
                            character_facet_type type) 
{ 
    if(lc.is_c()) { 
        switch(type) { 
        case char_facet: 
            return std::locale(in,new std::collate_byname<char>("C")); 
        case wchar_t_facet: 
            return std::locale(in,new std::collate_byname<wchar_t>("C")); 
        } 
    } 
    else { 
        switch(type) { 
        case char_facet: 
            return std::locale(in,new utf8_collator(lc)); 
        case wchar_t_facet: 
            return std::locale(in,new utf16_collator(lc)); 
        } 
    } 
    return in; 
} 
 
 
} // impl_std 
} // locale  
} //boost 
 
 
 
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4