-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
Copy pathlocale0.cpp
242 lines (186 loc) · 7.72 KB
/
locale0.cpp
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// class locale basic member functions
// This file is compiled into the import library (via locale0_implib.cpp => locale0.cpp).
// MAJOR LIMITATIONS apply to what can be included here!
// Before editing this file, read: /docs/import_library.md
#undef _ENFORCE_ONLY_CORE_HEADERS // TRANSITION, <xfacet> should be a core header
#include <crtdbg.h>
#include <internal_shared.h>
#include <xatomic.h>
#include <xfacet>
// This should probably go to a compiler section just after the locks - unfortunately we have per-appdomain
// and per-process variables to initialize
#pragma warning(disable : 4073)
#pragma init_seg(lib)
_STD_BEGIN
[[noreturn]] _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Xbad_alloc();
struct _Fac_node { // node for lazy facet recording
_Fac_node(_Fac_node* _Nextarg, _Facet_base* _Facptrarg)
: _Next(_Nextarg), _Facptr(_Facptrarg) {} // construct a node with value
~_Fac_node() noexcept { // destroy a facet
delete _Facptr->_Decref();
}
#ifdef _DEBUG
void* operator new(size_t _Size) { // replace operator new
void* _Ptr = _malloc_dbg(_Size > 0 ? _Size : 1, _CRT_BLOCK, __FILE__, __LINE__);
if (!_Ptr) {
_Xbad_alloc();
}
return _Ptr;
}
void operator delete(void* _Ptr) noexcept { // replace operator delete
_free_dbg(_Ptr, _CRT_BLOCK);
}
#endif // defined(_DEBUG)
_Fac_node* _Next;
_Facet_base* _Facptr;
};
__PURE_APPDOMAIN_GLOBAL static _Fac_node* _Fac_head = nullptr;
struct _Fac_tidy_reg_t {
~_Fac_tidy_reg_t() noexcept { // destroy lazy facets
while (_Fac_head != nullptr) { // destroy a lazy facet node
_Fac_node* nodeptr = _Fac_head;
_Fac_head = nodeptr->_Next;
delete nodeptr;
}
}
};
__PURE_APPDOMAIN_GLOBAL const _Fac_tidy_reg_t _Fac_tidy_reg;
#if defined(_M_CEE)
void __CLRCALL_OR_CDECL _Facet_Register_m(_Facet_base* _This)
#else // ^^^ defined(_M_CEE) / !defined(_M_CEE) vvv
void __CLRCALL_OR_CDECL _Facet_Register(_Facet_base* _This)
#endif // ^^^ !defined(_M_CEE) ^^^
{ // queue up lazy facet for destruction
_Fac_head = new _Fac_node(_Fac_head, _This);
}
_STD_END
#if !STDCPP_IMPLIB || defined(_M_CEE_PURE)
#include <cstdlib>
#include <locale>
extern "C" {
void __CLRCALL_OR_CDECL _Deletegloballocale(void* ptr) noexcept { // delete a global locale reference
std::locale::_Locimp* locptr = *static_cast<std::locale::_Locimp**>(ptr);
if (locptr != nullptr) {
delete locptr->_Decref();
}
}
__PURE_APPDOMAIN_GLOBAL static std::locale::_Locimp* global_locale = nullptr; // pointer to current locale
static void __CLRCALL_PURE_OR_CDECL tidy_global() noexcept { // delete static global locale reference
_BEGIN_LOCK(_LOCK_LOCALE) // prevent double delete
_Deletegloballocale(&global_locale);
global_locale = nullptr;
_END_LOCK()
}
} // extern "C"
_MRTIMP2 void __cdecl _Atexit(void(__cdecl*)());
_STD_BEGIN
_MRTIMP2_PURE std::locale::_Locimp* __CLRCALL_PURE_OR_CDECL
std::locale::_Getgloballocale() { // return pointer to current locale
return global_locale;
}
_MRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL std::locale::_Setgloballocale(void* ptr) { // alter pointer to current locale
__PURE_APPDOMAIN_GLOBAL static bool registered = false;
if (!registered) { // register cleanup first time
registered = true;
#if !defined(_M_CEE_PURE)
::_Atexit(&tidy_global);
#else
_atexit_m_appdomain(tidy_global);
#endif
}
global_locale = static_cast<std::locale::_Locimp*>(ptr);
}
__PURE_APPDOMAIN_GLOBAL static locale classic_locale(_Noinit); // "C" locale object, uninitialized
__PURE_APPDOMAIN_GLOBAL locale::_Locimp* locale::_Locimp::_Clocptr = nullptr; // pointer to classic_locale
__PURE_APPDOMAIN_GLOBAL int locale::id::_Id_cnt = 0; // unique id counter for facets
__PURE_APPDOMAIN_GLOBAL locale::id ctype<char>::id(0);
__PURE_APPDOMAIN_GLOBAL locale::id ctype<wchar_t>::id(0);
__PURE_APPDOMAIN_GLOBAL locale::id codecvt<wchar_t, char, mbstate_t>::id(0);
__PURE_APPDOMAIN_GLOBAL locale::id ctype<unsigned short>::id(0);
__PURE_APPDOMAIN_GLOBAL locale::id codecvt<unsigned short, char, mbstate_t>::id(0);
_MRTIMP2_PURE const locale& __CLRCALL_PURE_OR_CDECL locale::classic() { // get reference to "C" locale
#if !defined(_M_CEE_PURE)
const auto mem = reinterpret_cast<const intptr_t*>(&locale::_Locimp::_Clocptr);
intptr_t as_bytes;
#ifdef _WIN64
as_bytes = __iso_volatile_load64(mem);
#else // ^^^ 64-bit / 32-bit vvv
as_bytes = __iso_volatile_load32(mem);
#endif // ^^^ 32-bit ^^^
_Compiler_or_memory_barrier();
const auto ptr = reinterpret_cast<locale::_Locimp*>(as_bytes);
if (ptr == nullptr)
#endif // !defined(_M_CEE_PURE)
{
_Init();
}
return classic_locale;
}
_MRTIMP2_PURE locale __CLRCALL_PURE_OR_CDECL locale::empty() { // make empty transparent locale
_Init();
return locale{_Secret_locale_construct_tag{}, _Locimp::_New_Locimp(true)};
}
_MRTIMP2_PURE locale::_Locimp* __CLRCALL_PURE_OR_CDECL locale::_Init(bool _Do_incref) { // setup global and "C" locales
locale::_Locimp* ptr = nullptr;
_BEGIN_LOCK(_LOCK_LOCALE) // prevent double initialization
ptr = _Getgloballocale();
if (ptr == nullptr) { // create new locales
_Setgloballocale(ptr = _Locimp::_New_Locimp());
ptr->_Catmask = all; // set current locale to "C"
ptr->_Name = "C";
// set classic to match
ptr->_Incref();
::new (&classic_locale) locale{_Secret_locale_construct_tag{}, ptr};
#if defined(_M_CEE_PURE)
locale::_Locimp::_Clocptr = ptr;
#else // ^^^ defined(_M_CEE_PURE) / !defined(_M_CEE_PURE) vvv
const auto mem = reinterpret_cast<volatile intptr_t*>(&locale::_Locimp::_Clocptr);
const auto as_bytes = reinterpret_cast<intptr_t>(ptr);
_Compiler_or_memory_barrier();
#ifdef _WIN64
__iso_volatile_store64(mem, as_bytes);
#else // ^^^ 64-bit / 32-bit vvv
__iso_volatile_store32(mem, as_bytes);
#endif // ^^^ 32-bit ^^^
#endif // ^^^ !defined(_M_CEE_PURE) ^^^
}
if (_Do_incref) {
ptr->_Incref();
}
_END_LOCK()
return ptr;
}
locale::_Locimp* __CLRCALL_PURE_OR_CDECL locale::_Locimp::_New_Locimp(bool _Transparent) {
return new _Locimp(_Transparent);
}
locale::_Locimp* __CLRCALL_PURE_OR_CDECL locale::_Locimp::_New_Locimp(const _Locimp& _Right) {
return new _Locimp(_Right);
}
void __CLRCALL_PURE_OR_CDECL locale::_Locimp::_Locimp_dtor(_Locimp* _This) { // destruct a _Locimp
_BEGIN_LOCK(_LOCK_LOCALE) // prevent double delete
for (size_t count = _This->_Facetcount; 0 < count;) {
if (_This->_Facetvec[--count] != nullptr) {
delete _This->_Facetvec[count]->_Decref();
}
}
free(_This->_Facetvec);
_END_LOCK()
}
void __CLRCALL_PURE_OR_CDECL _Locinfo::_Locinfo_ctor(
_Locinfo* pLocinfo, const char* locname) { // switch to a named locale
const char* oldlocname = setlocale(LC_ALL, nullptr);
pLocinfo->_Oldlocname = oldlocname == nullptr ? "" : oldlocname;
if (locname != nullptr) {
locname = setlocale(LC_ALL, locname);
}
pLocinfo->_Newlocname = locname == nullptr ? "*" : locname;
}
void __CLRCALL_PURE_OR_CDECL _Locinfo::_Locinfo_dtor(_Locinfo* pLocinfo) { // destroy a _Locinfo object, revert locale
if (!pLocinfo->_Oldlocname._Empty()) {
setlocale(LC_ALL, pLocinfo->_Oldlocname._C_str());
}
}
_STD_END
#endif // !STDCPP_IMPLIB || defined(_M_CEE_PURE)