1//
2// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3//
4// Distributed under the Boost Software License, Version 1.0.
5// https://www.boost.org/LICENSE_1_0.txt
6
7#include <boost/locale/encoding.hpp>
8#include <boost/locale/generator.hpp>
9#include <boost/locale/localization_backend.hpp>
10#include <boost/thread/locks.hpp>
11#include <boost/thread/mutex.hpp>
12#include <algorithm>
13#include <map>
14#include <vector>
15
16namespace boost { namespace locale {
17 struct generator::data {
18 data(const localization_backend_manager& mgr) :
19 cats(all_categories), chars(all_characters), caching_enabled(false), use_ansi_encoding(false),
20 backend_manager(mgr)
21 {}
22
23 mutable std::map<std::string, std::locale> cached;
24 mutable boost::mutex cached_lock;
25
26 category_t cats;
27 char_facet_t chars;
28
29 bool caching_enabled;
30 bool use_ansi_encoding;
31
32 std::vector<std::string> paths;
33 std::vector<std::string> domains;
34
35 std::map<std::string, std::vector<std::string>> options;
36
37 localization_backend_manager backend_manager;
38 };
39
40 generator::generator(const localization_backend_manager& mgr) : d(new generator::data(mgr)) {}
41 generator::generator() : d(new generator::data(localization_backend_manager::global())) {}
42 generator::~generator() = default;
43
44 category_t generator::categories() const
45 {
46 return d->cats;
47 }
48 void generator::categories(category_t t)
49 {
50 d->cats = t;
51 }
52
53 void generator::characters(char_facet_t t)
54 {
55 d->chars = t;
56 }
57
58 char_facet_t generator::characters() const
59 {
60 return d->chars;
61 }
62
63 void generator::add_messages_domain(const std::string& domain)
64 {
65 if(std::find(first: d->domains.begin(), last: d->domains.end(), val: domain) == d->domains.end())
66 d->domains.push_back(x: domain);
67 }
68
69 void generator::set_default_messages_domain(const std::string& domain)
70 {
71 const auto p = std::find(first: d->domains.begin(), last: d->domains.end(), val: domain);
72 if(p != d->domains.end())
73 d->domains.erase(position: p);
74 d->domains.insert(position: d->domains.begin(), x: domain);
75 }
76
77 void generator::clear_domains()
78 {
79 d->domains.clear();
80 }
81 void generator::add_messages_path(const std::string& path)
82 {
83 d->paths.push_back(x: path);
84 }
85 void generator::clear_paths()
86 {
87 d->paths.clear();
88 }
89 void generator::clear_cache()
90 {
91 d->cached.clear();
92 }
93
94 std::locale generator::generate(const std::string& id) const
95 {
96 std::locale base = std::locale::classic();
97
98 return generate(base, id);
99 }
100
101 std::locale generator::generate(const std::locale& base, const std::string& id) const
102 {
103 if(d->caching_enabled) {
104 boost::unique_lock<boost::mutex> guard(d->cached_lock);
105 const auto p = d->cached.find(x: id);
106 if(p != d->cached.end())
107 return p->second;
108 }
109 auto backend = d->backend_manager.create();
110 set_all_options(backend&: *backend, id);
111
112 std::locale result = base;
113 category_t facets = d->cats;
114 char_facet_t chars = d->chars;
115
116 for(category_t facet = per_character_facet_first; facet <= per_character_facet_last; ++facet) {
117 if(!(facets & facet))
118 continue;
119 for(char_facet_t ch = character_facet_first; ch <= character_facet_last; ++ch) {
120 if(ch & chars)
121 result = backend->install(base: result, category: facet, type: ch);
122 }
123 }
124 for(category_t facet = non_character_facet_first; facet <= non_character_facet_last; ++facet) {
125 if(facets & facet)
126 result = backend->install(base: result, category: facet, type: char_facet_t::nochar);
127 }
128 if(d->caching_enabled) {
129 boost::unique_lock<boost::mutex> guard(d->cached_lock);
130 const auto p = d->cached.find(x: id);
131 if(p == d->cached.end())
132 d->cached[id] = result;
133 }
134 return result;
135 }
136
137 bool generator::use_ansi_encoding() const
138 {
139 return d->use_ansi_encoding;
140 }
141
142 void generator::use_ansi_encoding(bool v)
143 {
144 d->use_ansi_encoding = v;
145 }
146
147 bool generator::locale_cache_enabled() const
148 {
149 return d->caching_enabled;
150 }
151 void generator::locale_cache_enabled(bool enabled)
152 {
153 d->caching_enabled = enabled;
154 }
155
156 void generator::set_all_options(localization_backend& backend, const std::string& id) const
157 {
158 backend.set_option(name: "locale", value: id);
159 backend.set_option(name: "use_ansi_encoding", value: d->use_ansi_encoding ? "true" : "false");
160 for(const std::string& domain : d->domains)
161 backend.set_option(name: "message_application", value: domain);
162 for(const std::string& path : d->paths)
163 backend.set_option(name: "message_path", value: path);
164 }
165
166 // Sanity check
167
168 static_assert((char_facet_t::char_f | char_facet_t::wchar_f) & char_facet_t::char_f, "!");
169 static_assert((char_facet_t::char_f | char_facet_t::wchar_f) & char_facet_t::wchar_f, "!");
170 static_assert(!((all_characters ^ char_facet_t::wchar_f) & char_facet_t::wchar_f), "!");
171
172 static_assert((category_t::calendar | category_t::convert) & category_t::calendar, "!");
173 static_assert((category_t::calendar | category_t::convert) & category_t::convert, "!");
174 static_assert(!((all_categories ^ category_t::calendar) & category_t::calendar), "!");
175
176#ifndef BOOST_NO_CXX14_CONSTEXPR
177 template<typename T>
178 constexpr T inc_enum(T v)
179 {
180 return ++v;
181 }
182 static_assert(inc_enum(v: char_facet_t::nochar) == char_facet_t::char_f, "!");
183 static_assert(inc_enum(v: char_facet_t::char_f) == char_facet_t::wchar_f, "!");
184 static_assert(inc_enum(v: category_t::convert) == category_t::collation, "!");
185#endif
186
187}} // namespace boost::locale
188

source code of boost/libs/locale/src/boost/locale/shared/generator.cpp