@@ -267,6 +267,58 @@ version( CoreDdoc )
267
267
* loads and stores after the call.
268
268
*/
269
269
void atomicFence () nothrow @nogc ;
270
+
271
+ /**
272
+ * Converts a shared lvalue to a non-shared lvalue.
273
+ *
274
+ * This functions allows to treat a shared lvalue as if it was thread-local.
275
+ * It is useful to avoid overhead of atomic operations when access to shared data
276
+ * is known to be within one thread (i.e. always under a lock).
277
+ * ---
278
+ * shared static int i;
279
+ *
280
+ * // i is never used outside of synchronized {} blocks...
281
+ *
282
+ * synchronized
283
+ * {
284
+ * ++i; // ERROR: cannot directly modify shared lvalue
285
+ *
286
+ * atomicOp!"+="(i, 1); // possible overhead
287
+ *
288
+ * // Directly modify i
289
+ * assumeUnshared(i) += 1;
290
+ * // or:
291
+ * ++assumeUnshared(i);
292
+ * // or:
293
+ * i.assumeUnshared += 1;
294
+ * }
295
+ * ---
296
+ * Usage of this function is restricted to allowing limited lvalue access to shared instances of
297
+ * primitive and POD types (e.g. direct use of operators), thus it is not defined for classes.
298
+ *
299
+ * Note: this function does not perform any ordering.
300
+ *
301
+ * Note: assumeUnshared is a special-purpose primitive and should be used with care. When accessing
302
+ * shared variables both inside and outside of synchronized blocks, atomic operations should be
303
+ * used instead.
304
+ *
305
+ * Params:
306
+ * val = the shared lvalue.
307
+ *
308
+ * Returns:
309
+ * The non-shared lvalue.
310
+ */
311
+ ref T assumeUnshared (T)(ref shared T val) @system @nogc pure nothrow
312
+ if (! is (T == class ) && ! is (T == interface ))
313
+ {
314
+ return * cast (T* ) &val;
315
+ }
316
+
317
+ // / ditto
318
+ ref immutable (T) assumeUnshared (T)(ref immutable (T) val) @safe @nogc pure nothrow
319
+ {
320
+ return val;
321
+ }
270
322
}
271
323
else version ( AsmX86_32 )
272
324
{
@@ -1409,6 +1461,26 @@ if(__traits(isFloating, T))
1409
1461
}
1410
1462
}
1411
1463
1464
+ // assumeLocal is architecture-independent: it is just a cast
1465
+ ref auto assumeLocal (T)( ref shared T val ) @trusted pure nothrow
1466
+ if ( ! is ( T == class ) )
1467
+ {
1468
+ return * cast (T* ) &val;
1469
+ }
1470
+
1471
+ // assumeUnshared is architecture-independent: it is just a cast
1472
+ ref auto assumeUnshared (T)(ref shared T val) @system @nogc pure nothrow
1473
+ if (! is (T == class ) && ! is (T == interface ))
1474
+ {
1475
+ return * cast (T* ) &val;
1476
+ }
1477
+
1478
+ // immutable is implicitly unshared
1479
+ ref auto assumeUnshared(T)(ref immutable (T) val) @safe @nogc pure nothrow
1480
+ {
1481
+ return val;
1482
+ }
1483
+
1412
1484
// //////////////////////////////////////////////////////////////////////////////
1413
1485
// Unit Tests
1414
1486
// //////////////////////////////////////////////////////////////////////////////
@@ -1711,4 +1783,81 @@ version( unittest )
1711
1783
shared NoIndirections n;
1712
1784
static assert (is (typeof (atomicLoad(n)) == NoIndirections));
1713
1785
}
1786
+
1787
+ pure nothrow @nogc @system unittest
1788
+ {
1789
+ int base = 0 ;
1790
+ shared int atom = 0 ;
1791
+
1792
+ // only accept shared lvalues
1793
+ static assert (! is (typeof (assumeUnshared(base))));
1794
+ static assert (! is (typeof (assumeUnshared(cast (shared )base))));
1795
+
1796
+ ++ assumeUnshared(atom);
1797
+ assert (atomicLoad! (MemoryOrder.raw)(atom) == 1 );
1798
+ }
1799
+
1800
+ pure nothrow @nogc @system unittest
1801
+ {
1802
+ shared const int catom = 0 ;
1803
+ shared immutable int iatom = 0 ;
1804
+ // allow const
1805
+ static assert (is (typeof (assumeUnshared(catom))));
1806
+ static assert (is (typeof (assumeUnshared(iatom))));
1807
+ // preserve const
1808
+ static assert (! is (typeof (++ assumeUnshared(catom))));
1809
+ static assert (! is (typeof (++ assumeUnshared(iatom))));
1810
+ }
1811
+
1812
+ pure nothrow @nogc @system unittest
1813
+ {
1814
+ class Klass {}
1815
+
1816
+ Klass c1;
1817
+ shared Klass c2;
1818
+
1819
+ // don't accept class instances
1820
+ static assert (! is (typeof (assumeUnshared(c1))));
1821
+ static assert (! is (typeof (assumeUnshared(c2))));
1822
+ }
1823
+
1824
+ pure nothrow @nogc @system unittest
1825
+ {
1826
+ interface Interface {}
1827
+ Interface i1;
1828
+ shared Interface i2;
1829
+
1830
+ // don't accept interfaces
1831
+ static assert (! is (typeof (assumeUnshared(i1))));
1832
+ static assert (! is (typeof (assumeUnshared(i2))));
1833
+ }
1834
+
1835
+ pure nothrow @nogc @system unittest
1836
+ {
1837
+ // test assumeShared with inout
1838
+ shared struct S
1839
+ {
1840
+ int atom = 0 ;
1841
+
1842
+ @property ref get () inout
1843
+ {
1844
+ return atom.assumeUnshared;
1845
+ }
1846
+ }
1847
+
1848
+ shared S sm;
1849
+ shared const S sc;
1850
+ shared immutable S si;
1851
+
1852
+ static assert (is (typeof (sm.get ) == int ));
1853
+ static assert (is (typeof (sc.get ) == const (int )));
1854
+ static assert (is (typeof (si.get ) == immutable (int )));
1855
+
1856
+ static assert ( is (typeof (++ sm.get )));
1857
+ static assert (! is (typeof (++ sc.get )));
1858
+ static assert (! is (typeof (++ si.get )));
1859
+
1860
+ sm.get += 10 ;
1861
+ assert (atomicLoad! (MemoryOrder.raw)(sm.atom) == 10 );
1862
+ }
1714
1863
}
0 commit comments