aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/libs/locale/src/win32/collate.cpp
blob: 40e8c3d217dc19634f72dc5b9da5985403636409 (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