6
6
//
7
7
// ===----------------------------------------------------------------------===//
8
8
9
+ #include < __utility/no_destroy.h>
9
10
#include < algorithm>
10
11
#include < clocale>
11
12
#include < codecvt>
@@ -81,9 +82,8 @@ locale_t __cloc() {
81
82
82
83
namespace {
83
84
84
- struct release
85
- {
86
- void operator ()(locale::facet* p) {p->__release_shared ();}
85
+ struct releaser {
86
+ void operator ()(locale::facet* p) { p->__release_shared (); }
87
87
};
88
88
89
89
template <class T , class ...Args>
@@ -155,7 +155,11 @@ class _LIBCPP_HIDDEN locale::__imp
155
155
{return static_cast <size_t >(id) < facets_.size () && facets_[static_cast <size_t >(id)];}
156
156
const locale::facet* use_facet (long id) const ;
157
157
158
- private:
158
+ void acquire ();
159
+ void release ();
160
+ static __no_destroy<__imp> classic_locale_imp_;
161
+
162
+ private:
159
163
void install (facet* f, long id);
160
164
template <class F > void install (F* f) {install (f, f->id .__get ());}
161
165
template <class F > void install_from (const __imp& other);
@@ -500,7 +504,7 @@ locale::__imp::__imp(const __imp& other, facet* f, long id)
500
504
name_ (" *" )
501
505
{
502
506
f->__add_shared ();
503
- unique_ptr<facet, release > hold (f);
507
+ unique_ptr<facet, releaser > hold (f);
504
508
facets_ = other.facets_ ;
505
509
for (unsigned i = 0 ; i < other.facets_ .size (); ++i)
506
510
if (facets_[i])
519
523
locale::__imp::install (facet* f, long id)
520
524
{
521
525
f->__add_shared ();
522
- unique_ptr<facet, release > hold (f);
526
+ unique_ptr<facet, releaser > hold (f);
523
527
if (static_cast <size_t >(id) >= facets_.size ())
524
528
facets_.resize (static_cast <size_t >(id+1 ));
525
529
if (facets_[static_cast <size_t >(id)])
@@ -537,89 +541,79 @@ locale::__imp::use_facet(long id) const
537
541
538
542
// locale
539
543
540
- // This class basically implements __attribute__((no_destroy)), which isn't supported
541
- // by GCC as of writing this.
542
- template <class T >
543
- struct __no_destroy {
544
- template <class ... Args>
545
- explicit __no_destroy (Args&&... args) {
546
- T* obj = reinterpret_cast <T*>(&buf);
547
- new (obj) T (std::forward<Args>(args)...);
548
- }
549
-
550
- T& get () { return *reinterpret_cast <T*>(&buf); }
551
- T const & get () const { return *reinterpret_cast <T const *>(&buf); }
552
-
553
- private:
554
- alignas (T) byte buf[sizeof (T)];
555
- };
544
+ // We don't do reference counting on the classic locale.
545
+ // It's never destroyed anyway, but atomic reference counting may be very
546
+ // expensive in parallel applications. The classic locale is used by default
547
+ // in all streams. Note: if a new global locale is installed, then we lose
548
+ // the benefit of no reference counting.
549
+ constinit __no_destroy<locale::__imp>
550
+ locale::__imp::classic_locale_imp_ (__uninitialized_tag{}); // initialized below in classic()
556
551
557
552
const locale& locale::classic () {
558
- static const __no_destroy<locale> c (__private_tag{}, &make<__imp>(1u ));
559
- return c.get ();
553
+ static const __no_destroy<locale> classic_locale (__private_tag{}, [] {
554
+ // executed exactly once on first initialization of `classic_locale`
555
+ locale::__imp::classic_locale_imp_.__emplace (1u );
556
+ return &locale::__imp::classic_locale_imp_.__get ();
557
+ }());
558
+ return classic_locale.__get ();
560
559
}
561
560
562
561
locale& locale::__global () {
563
- static __no_destroy<locale> g (locale::classic ());
564
- return g.get ();
562
+ static __no_destroy<locale> g (locale::classic ());
563
+ return g.__get ();
565
564
}
566
565
567
- locale::locale () noexcept
568
- : __locale_ (__global ().__locale_ )
569
- {
570
- __locale_->__add_shared ();
566
+ void locale::__imp::acquire () {
567
+ if (this != &locale::__imp::classic_locale_imp_.__get ())
568
+ __add_shared ();
571
569
}
572
570
573
- locale::locale (const locale& l) noexcept
574
- : __locale_ (l.__locale_ )
575
- {
576
- __locale_->__add_shared ();
571
+ void locale::__imp::release () {
572
+ if (this != &locale::__imp::classic_locale_imp_.__get ())
573
+ __release_shared ();
577
574
}
578
575
579
- locale::~locale ()
580
- {
581
- __locale_->__release_shared ();
582
- }
576
+ locale::locale () noexcept : __locale_ (__global ().__locale_ ) { __locale_->acquire (); }
577
+
578
+ locale::locale (const locale& l) noexcept : __locale_ (l.__locale_ ) { __locale_->acquire (); }
579
+
580
+ locale::~locale () { __locale_->release (); }
583
581
584
582
const locale&
585
583
locale::operator =(const locale& other) noexcept
586
584
{
587
- other.__locale_ ->__add_shared ();
588
- __locale_->__release_shared ();
589
- __locale_ = other.__locale_ ;
590
- return *this ;
585
+ other.__locale_ ->acquire ();
586
+ __locale_->release ();
587
+ __locale_ = other.__locale_ ;
588
+ return *this ;
591
589
}
592
590
593
591
locale::locale (const char * name)
594
592
: __locale_ (name ? new __imp (name)
595
593
: (__throw_runtime_error (" locale constructed with null" ), nullptr ))
596
594
{
597
- __locale_->__add_shared ();
595
+ __locale_->acquire ();
598
596
}
599
597
600
- locale::locale (const string& name)
601
- : __locale_ (new __imp (name))
602
- {
603
- __locale_->__add_shared ();
604
- }
598
+ locale::locale (const string& name) : __locale_ (new __imp (name)) { __locale_->acquire (); }
605
599
606
600
locale::locale (const locale& other, const char * name, category c)
607
601
: __locale_ (name ? new __imp (*other.__locale_ , name, c)
608
602
: (__throw_runtime_error (" locale constructed with null" ), nullptr ))
609
603
{
610
- __locale_->__add_shared ();
604
+ __locale_->acquire ();
611
605
}
612
606
613
607
locale::locale (const locale& other, const string& name, category c)
614
608
: __locale_ (new __imp (*other.__locale_ , name, c))
615
609
{
616
- __locale_->__add_shared ();
610
+ __locale_->acquire ();
617
611
}
618
612
619
613
locale::locale (const locale& other, const locale& one, category c)
620
614
: __locale_ (new __imp (*other.__locale_ , *one.__locale_ , c))
621
615
{
622
- __locale_->__add_shared ();
616
+ __locale_->acquire ();
623
617
}
624
618
625
619
string
@@ -635,7 +629,7 @@ locale::__install_ctor(const locale& other, facet* f, long id)
635
629
__locale_ = new __imp (*other.__locale_ , f, id);
636
630
else
637
631
__locale_ = other.__locale_ ;
638
- __locale_->__add_shared ();
632
+ __locale_->acquire ();
639
633
}
640
634
641
635
locale
0 commit comments