@@ -124,15 +124,14 @@ class extrinsic_storage {
124
124
// find_or_insert( pobj ) - returns the data entry for pobj
125
125
//
126
126
// If pobj does not yet have an entry, creates it
127
+ // Returns null only if not present and allocation is needed but fails
127
128
//
128
- auto find_or_insert (void * pobj) noexcept -> Value& {
129
+ auto find_or_insert (void * pobj) noexcept -> Value* {
129
130
if constexpr (debug_instrumentation) {
130
131
// m_o_relaxed is enough, inc order doesn't matter for totals
131
132
instrument_access_count.fetch_add (1 , std::memory_order_relaxed);
132
133
}
133
- auto v = lookup (pobj, lookup_mode::find_or_insert);
134
- assert (v);
135
- return *v;
134
+ return lookup (pobj, lookup_mode::find_or_insert);
136
135
}
137
136
138
137
// --------------------------------------------------------------------------
@@ -143,7 +142,7 @@ class extrinsic_storage {
143
142
// m_o_relaxed is enough, inc order doesn't matter for totals
144
143
instrument_access_count.fetch_add (1 , std::memory_order_relaxed);
145
144
}
146
- return lookup (pobj, lookup_mode::find_or_insert );
145
+ return lookup (pobj, lookup_mode::find );
147
146
}
148
147
149
148
// --------------------------------------------------------------------------
@@ -171,8 +170,10 @@ class extrinsic_storage {
171
170
//
172
171
// Parameters
173
172
// pobj the key to look up
174
- // erase if true, reset key to null and return nullptr
175
- // if false, return a pointer to the value (insert key if not present)
173
+ // mode if erase, reset key to null and return nullptr
174
+ // if find, return a pointer to the value if it exists, or null
175
+ // if find_or_insert, return a pointer to the value (inserted if
176
+ // not present) or null if allocation was needed and failed
176
177
//
177
178
// (*) This function requires that the calling code has exclusive access to
178
179
// *pobj, and if *pobj is shared has done any necessary synchronization
@@ -274,10 +275,16 @@ class extrinsic_storage {
274
275
// b) Otherwise, we need to allocate a new chunk for it
275
276
// At this point, pchunk points to the last chunk in this bucket
276
277
assert (pchunk);
277
- auto pnew = std::make_unique<chunk>();
278
- auto ret = &pnew->values [0 ];
278
+
279
+ // Not using make_unique: In principle, if allocation fails we don't
280
+ // want to change well-formed program behavior. (In practice, if this
281
+ // small allocation ever fails the program is already in deep trouble;
282
+ // unless Key or Data are large, a chunk is usually well under 1KB)
283
+ auto pnew = std::unique_ptr<chunk>( new (std::nothrow) chunk{} );
284
+ if (pnew == nullptr ) { return nullptr ; }
279
285
280
286
pnew->keys [0 ] = pobj;
287
+ auto ret = &pnew->values [0 ];
281
288
while (!pchunk->next .compare_exchange_weak_null (pnew)) {
282
289
pchunk = pchunk->next .load ();
283
290
assert (pchunk);
0 commit comments