@@ -263,6 +263,52 @@ in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
263
263
return cast (shared )core.internal.atomic.atomicExchange ! ms(cast (T* )here, cast (V)exchangeWith);
264
264
}
265
265
266
+ /**
267
+ * Converts a shared lvalue to a non-shared lvalue.
268
+ *
269
+ * This functions allows to treat a shared lvalue as if it was thread-local.
270
+ * It is useful to avoid overhead of atomic operations when access to shared data
271
+ * is known to be within one thread (i.e. always under a lock).
272
+ * ---
273
+ * shared static int i;
274
+ *
275
+ * // i is never used outside of synchronized {} blocks...
276
+ *
277
+ * synchronized
278
+ * {
279
+ * ++i; // ERROR: cannot directly modify shared lvalue
280
+ *
281
+ * atomicOp!"+="(i, 1); // possible overhead
282
+ *
283
+ * // Directly modify i
284
+ * assumeUnshared(i) += 1;
285
+ * // or:
286
+ * ++assumeUnshared(i);
287
+ * // or:
288
+ * i.assumeUnshared += 1;
289
+ * }
290
+ * ---
291
+ * Usage of this function is restricted to allowing limited lvalue access to shared instances of
292
+ * primitive and POD types (e.g. direct use of operators), thus it is not defined for classes.
293
+ *
294
+ * Note: this function does not perform any ordering.
295
+ *
296
+ * Note: assumeUnshared is a special-purpose primitive and should be used with care. When accessing
297
+ * shared variables both inside and outside of synchronized blocks, atomic operations should be
298
+ * used instead.
299
+ *
300
+ * Params:
301
+ * val = the shared lvalue.
302
+ *
303
+ * Returns:
304
+ * The non-shared lvalue.
305
+ */
306
+ ref T assumeUnshared (T)(ref shared T val) @system @nogc pure nothrow
307
+ if (! is (T == class ) && ! is (T == interface ))
308
+ {
309
+ return * cast (T* ) &val;
310
+ }
311
+
266
312
/**
267
313
* Performs either compare-and-set or compare-and-swap (or exchange).
268
314
*
@@ -1276,4 +1322,81 @@ version (CoreUnittest)
1276
1322
shared NoIndirections n;
1277
1323
static assert (is (typeof (atomicLoad(n)) == NoIndirections));
1278
1324
}
1325
+
1326
+ pure nothrow @nogc @system unittest
1327
+ {
1328
+ int base = 0 ;
1329
+ shared int atom = 0 ;
1330
+
1331
+ // only accept shared lvalues
1332
+ static assert (! is (typeof (assumeUnshared(base))));
1333
+ static assert (! is (typeof (assumeUnshared(cast (shared )base))));
1334
+
1335
+ ++ assumeUnshared(atom);
1336
+ assert (atomicLoad! (MemoryOrder.raw)(atom) == 1 );
1337
+ }
1338
+
1339
+ pure nothrow @nogc @system unittest
1340
+ {
1341
+ shared const int catom = 0 ;
1342
+ shared immutable int iatom = 0 ;
1343
+ // allow const
1344
+ static assert (is (typeof (assumeUnshared(catom))));
1345
+ static assert (is (typeof (assumeUnshared(iatom))));
1346
+ // preserve const
1347
+ static assert (! is (typeof (++ assumeUnshared(catom))));
1348
+ static assert (! is (typeof (++ assumeUnshared(iatom))));
1349
+ }
1350
+
1351
+ pure nothrow @nogc @system unittest
1352
+ {
1353
+ class Klass {}
1354
+
1355
+ Klass c1;
1356
+ shared Klass c2;
1357
+
1358
+ // don't accept class instances
1359
+ static assert (! is (typeof (assumeUnshared(c1))));
1360
+ static assert (! is (typeof (assumeUnshared(c2))));
1361
+ }
1362
+
1363
+ pure nothrow @nogc @system unittest
1364
+ {
1365
+ interface Interface {}
1366
+ Interface i1;
1367
+ shared Interface i2;
1368
+
1369
+ // don't accept interfaces
1370
+ static assert (! is (typeof (assumeUnshared(i1))));
1371
+ static assert (! is (typeof (assumeUnshared(i2))));
1372
+ }
1373
+
1374
+ pure nothrow @nogc @system unittest
1375
+ {
1376
+ // test assumeShared with inout
1377
+ shared struct S
1378
+ {
1379
+ int atom = 0 ;
1380
+
1381
+ @property ref get () inout
1382
+ {
1383
+ return atom.assumeUnshared;
1384
+ }
1385
+ }
1386
+
1387
+ shared S sm;
1388
+ shared const S sc;
1389
+ shared immutable S si;
1390
+
1391
+ static assert (is (typeof (sm.get ) == int ));
1392
+ static assert (is (typeof (sc.get ) == const (int )));
1393
+ static assert (is (typeof (si.get ) == immutable (int )));
1394
+
1395
+ static assert ( is (typeof (++ sm.get )));
1396
+ static assert (! is (typeof (++ sc.get )));
1397
+ static assert (! is (typeof (++ si.get )));
1398
+
1399
+ sm.get += 10 ;
1400
+ assert (atomicLoad! (MemoryOrder.raw)(sm.atom) == 10 );
1401
+ }
1279
1402
}
0 commit comments