@@ -74,7 +74,37 @@ class TLStatNameSet::Impl {
7474 }
7575 };
7676
77- using Set = folly::F14FastMap<std::string, Wp>;
77+ // / typical layout of std::shared_ptr and std::weak_ptr
78+ // / need controlled access to address of object even from weak_ptr
79+ // /
80+ // / layout consistent with libstdc++, libc++, microsoft-stl
81+ template <typename T>
82+ struct WpLayout {
83+ T* const object{};
84+ void const * const control{};
85+
86+ explicit WpLayout (std::weak_ptr<T> const & wp) noexcept
87+ : WpLayout(reinterpret_cast <WpLayout const &>(wp)) {}
88+ };
89+
90+ struct Key {
91+ Wp weak;
92+ /* implicit */ operator std::string_view () const noexcept {
93+ return *WpLayout (weak).object ; // assume lockable - not-null, still-alive
94+ }
95+ };
96+
97+ struct KeyHash : std::hash<std::string_view> {
98+ using is_transparent = void ;
99+ using std::hash<std::string_view>::operator ();
100+ };
101+
102+ struct KeyEqual : std::equal_to<std::string_view> {
103+ using is_transparent = void ;
104+ using std::equal_to<std::string_view>::operator ();
105+ };
106+
107+ using Set = folly::F14FastSet<Key, KeyHash, KeyEqual>;
78108
79109 // / split to reduce potential lock contention at startup for threads looking
80110 // / up distinct names
@@ -94,7 +124,8 @@ class TLStatNameSet::Impl {
94124 void clean (std::string const & name) {
95125 auto const wlock = set (name).wlock ();
96126 if (auto const it = wlock->find (name); it != wlock->end ()) {
97- if (!it->second .lock ()) {
127+ if (WpLayout (it->weak ).object == &name) {
128+ assert (!it->weak .lock ());
98129 wlock->erase (it);
99130 }
100131 }
@@ -103,19 +134,20 @@ class TLStatNameSet::Impl {
103134 Sp getSlow (std::string_view const name) {
104135 auto const wlock = set (name).wlock ();
105136 if (auto const it = wlock->find (name); it != wlock->end ()) {
106- if (auto sp = it->second .lock ()) {
137+ if (auto sp = it->weak .lock ()) {
107138 return sp;
108139 }
140+ wlock->erase (it); // in case this call races with corresponding clean()
109141 }
110142 auto sp = Sp{new std::string (name), SpDeleter{}};
111- (* wlock)[ std::string (name)] = sp ;
143+ wlock-> insert (Key{sp}) ;
112144 return sp;
113145 }
114146
115147 Sp getFast (std::string_view const name) {
116148 auto const rlock = set (name).rlock ();
117149 if (auto const it = rlock->find (name); it != rlock->end ()) {
118- if (auto sp = it->second .lock ()) {
150+ if (auto sp = it->weak .lock ()) {
119151 return sp;
120152 }
121153 }
0 commit comments