@@ -1865,12 +1865,10 @@ void moveEmplace(T)(ref T source, ref T target) @system
18651865 import core.stdc.string : memcpy, memset;
18661866 import core.internal.traits ;
18671867
1868- // TODO: this assert pulls in half of phobos. we need to work out an alternative assert strategy.
1869- // static if (!is(T == class) && hasAliasing!T) if (!__ctfe)
1870- // {
1871- // import std.exception : doesPointTo;
1872- // assert(!doesPointTo(source, source), "Cannot move object with internal pointer.");
1873- // }
1868+ static if (! is (T == class ) /* && hasAliasing!T*/ ) if (! __ctfe)
1869+ {
1870+ assert (! doesPointTo(source, source), " Cannot move object with internal pointer." );
1871+ }
18741872
18751873 static if (is (T == struct ))
18761874 {
@@ -1955,3 +1953,293 @@ pure nothrow @nogc @system unittest
19551953 static assert (! __traits(compiles, f(ncarray)));
19561954 f(move(ncarray));
19571955}
1956+
1957+ private template DynamicArrayTypeOf (T)
1958+ {
1959+ static if (is (AliasThisTypeOf! T AT ) && ! is (AT [] == AT ))
1960+ alias X = DynamicArrayTypeOf! AT ;
1961+ else
1962+ alias X = OriginalType! T;
1963+
1964+ static if (is (Unqual! X : E[], E) && ! is (typeof ({ enum n = X.length; })))
1965+ {
1966+ alias DynamicArrayTypeOf = X;
1967+ }
1968+ else
1969+ static assert (0 , T.stringof~ " is not a dynamic array" );
1970+ }
1971+
1972+ private enum bool isAggregateType(T) = is (T == struct ) || is (T == union ) ||
1973+ is (T == class ) || is (T == interface );
1974+ private enum bool isDynamicArray(T) = is (DynamicArrayTypeOf! T) && ! isAggregateType! T;
1975+ private enum bool isStaticArray(T) = __traits(isStaticArray, T);
1976+ private enum bool isPointer(T) = is (T == U* , U) && ! isAggregateType! T;
1977+
1978+ /*
1979+ Checks whether a given source object contains pointers or references to a given
1980+ target object.
1981+
1982+ Params:
1983+ source = The source object
1984+ target = The target object
1985+
1986+ Bugs:
1987+ The function is explicitly annotated `@nogc` because inference could fail,
1988+ see $(LINK2 https://issues.dlang.org/show_bug.cgi?id=17084, issue 17084).
1989+
1990+ Returns: `true` if `source`'s representation embeds a pointer
1991+ that points to `target`'s representation or somewhere inside
1992+ it.
1993+
1994+ If `source` is or contains a dynamic array, then, then these functions will check
1995+ if there is overlap between the dynamic array and `target`'s representation.
1996+
1997+ If `source` is a class, then it will be handled as a pointer.
1998+
1999+ If `target` is a pointer, a dynamic array or a class, then these functions will only
2000+ check if `source` points to `target`, $(I not) what `target` references.
2001+
2002+ If `source` is or contains a union, then there may be either false positives or
2003+ false negatives:
2004+
2005+ `doesPointTo` will return `true` if it is absolutely certain
2006+ `source` points to `target`. It may produce false negatives, but never
2007+ false positives. This function should be prefered when trying to validate
2008+ input data.
2009+
2010+ `mayPointTo` will return `false` if it is absolutely certain
2011+ `source` does not point to `target`. It may produce false positives, but never
2012+ false negatives. This function should be prefered for defensively choosing a
2013+ code path.
2014+
2015+ Note: Evaluating $(D doesPointTo(x, x)) checks whether `x` has
2016+ internal pointers. This should only be done as an assertive test,
2017+ as the language is free to assume objects don't have internal pointers
2018+ (TDPL 7.1.3.5).
2019+ */
2020+ private bool doesPointTo (S, T, Tdummy=void )(auto ref const S source, ref const T target) @nogc @trusted pure nothrow
2021+ if (__traits(isRef, source) || isDynamicArray! S ||
2022+ isPointer! S || is (S == class ))
2023+ {
2024+ static if (isPointer! S || is (S == class ) || is (S == interface ))
2025+ {
2026+ const m = * cast (void ** ) &source;
2027+ const b = cast (void * ) ⌖
2028+ const e = b + target.sizeof;
2029+ return b <= m && m < e;
2030+ }
2031+ else static if (is (S == struct ) || is (S == union ))
2032+ {
2033+ foreach (i, Subobj; typeof (source.tupleof))
2034+ static if (! isUnionAliased! (S, i))
2035+ if (doesPointTo(source.tupleof[i], target)) return true ;
2036+ return false ;
2037+ }
2038+ else static if (isStaticArray! S)
2039+ {
2040+ foreach (ref s; source)
2041+ if (doesPointTo(s, target)) return true ;
2042+ return false ;
2043+ }
2044+ else static if (isDynamicArray! S)
2045+ {
2046+ import std.array : overlap;
2047+ return overlap (cast (void []) source, cast (void [])(&target)[0 .. 1 ]).length != 0 ;
2048+ }
2049+ else
2050+ {
2051+ return false ;
2052+ }
2053+ }
2054+
2055+ // for shared objects
2056+ // / ditto
2057+ bool doesPointTo (S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow
2058+ {
2059+ return doesPointTo! (shared S, shared T, void )(source, target);
2060+ }
2061+
2062+ /+
2063+ Returns the overlapping portion, if any, of two arrays. Unlike `equal`,
2064+ `overlap` only compares the pointers and lengths in the
2065+ ranges, not the values referred by them. If `r1` and `r2` have an
2066+ overlapping slice, returns that slice. Otherwise, returns the null
2067+ slice.
2068+
2069+ Params:
2070+ a = The first array to compare
2071+ b = The second array to compare
2072+ Returns:
2073+ The overlapping portion of the two arrays.
2074+ +/
2075+ private CommonType! (T[], U[]) overlap(T, U)(T[] a, U[] b) @trusted
2076+ if (is (typeof (a.ptr < b.ptr) == bool ))
2077+ {
2078+ const aLen = a.ptr + a.length;
2079+ const bLen = b.ptr + b.length;
2080+ auto end = aLen < bLen ? aLen : bLen;
2081+ // CTFE requires pairing pointer comparisons, which forces a
2082+ // slightly inefficient implementation.
2083+ if (a.ptr <= b.ptr && b.ptr < a.ptr + a.length)
2084+ {
2085+ return b.ptr[0 .. end - b.ptr];
2086+ }
2087+
2088+ if (b.ptr <= a.ptr && a.ptr < b.ptr + b.length)
2089+ {
2090+ return a.ptr[0 .. end - a.ptr];
2091+ }
2092+
2093+ return null ;
2094+ }
2095+
2096+ // /
2097+ @safe pure nothrow unittest
2098+ {
2099+ int [] a = [ 10 , 11 , 12 , 13 , 14 ];
2100+ int [] b = a[1 .. 3 ];
2101+ assert (overlap(a, b) == [ 11 , 12 ]);
2102+ b = b.dup ;
2103+ // overlap disappears even though the content is the same
2104+ assert (overlap(a, b).length == 0 );
2105+
2106+ static test ()() @nogc
2107+ {
2108+ auto a = " It's three o'clock" d;
2109+ auto b = a[5 .. 10 ];
2110+ return b.overlap(a);
2111+ }
2112+
2113+ // works at compile-time
2114+ static assert (test == " three" d);
2115+ }
2116+
2117+ @safe nothrow unittest
2118+ {
2119+ static void test (L, R)(L l, R r)
2120+ {
2121+ assert (overlap(l, r) == [ 100 , 12 ]);
2122+
2123+ assert (overlap(l, l[0 .. 2 ]) is l[0 .. 2 ]);
2124+ assert (overlap(l, l[3 .. 5 ]) is l[3 .. 5 ]);
2125+ assert (overlap(l[0 .. 2 ], l) is l[0 .. 2 ]);
2126+ assert (overlap(l[3 .. 5 ], l) is l[3 .. 5 ]);
2127+ }
2128+
2129+ int [] a = [ 10 , 11 , 12 , 13 , 14 ];
2130+ int [] b = a[1 .. 3 ];
2131+ a[1 ] = 100 ;
2132+
2133+ immutable int [] c = a.idup;
2134+ immutable int [] d = c[1 .. 3 ];
2135+
2136+ test(a, b);
2137+ assert (overlap(a, b.dup ).length == 0 );
2138+ test(c, d);
2139+ assert (overlap(c, d.idup).length == 0 );
2140+ }
2141+
2142+ /+
2143+ Returns true if the field at index `i` in ($D T) shares its address with another field.
2144+
2145+ Note: This does not merelly check if the field is a member of an union, but also that
2146+ it is not a single child.
2147+ +/
2148+ private enum isUnionAliased (T, size_t i) = isUnionAliasedImpl! T(T.tupleof[i].offsetof);
2149+ private bool isUnionAliasedImpl (T)(size_t offset)
2150+ {
2151+ int count = 0 ;
2152+ foreach (i, U; typeof (T.tupleof))
2153+ if (T.tupleof[i].offsetof == offset)
2154+ ++ count;
2155+ return count >= 2 ;
2156+ }
2157+ //
2158+ @safe unittest
2159+ {
2160+ static struct S
2161+ {
2162+ int a0; // Not aliased
2163+ union
2164+ {
2165+ int a1; // Not aliased
2166+ }
2167+ union
2168+ {
2169+ int a2; // Aliased
2170+ int a3; // Aliased
2171+ }
2172+ union A4
2173+ {
2174+ int b0; // Not aliased
2175+ }
2176+ A4 a4;
2177+ union A5
2178+ {
2179+ int b0; // Aliased
2180+ int b1; // Aliased
2181+ }
2182+ A5 a5;
2183+ }
2184+
2185+ static assert (! isUnionAliased! (S, 0 )); // a0;
2186+ static assert (! isUnionAliased! (S, 1 )); // a1;
2187+ static assert ( isUnionAliased! (S, 2 )); // a2;
2188+ static assert ( isUnionAliased! (S, 3 )); // a3;
2189+ static assert (! isUnionAliased! (S, 4 )); // a4;
2190+ static assert (! isUnionAliased! (S.A4 , 0 )); // a4.b0;
2191+ static assert (! isUnionAliased! (S, 5 )); // a5;
2192+ static assert ( isUnionAliased! (S.A5 , 0 )); // a5.b0;
2193+ static assert ( isUnionAliased! (S.A5 , 1 )); // a5.b1;
2194+ }
2195+
2196+
2197+ /*
2198+ Get the type that all types can be implicitly converted to. Useful
2199+ e.g. in figuring out an array type from a bunch of initializing
2200+ values. Returns $(D_PARAM void) if passed an empty list, or if the
2201+ types have no common type.
2202+ */
2203+ private template CommonType (T... )
2204+ {
2205+ static if (! T.length)
2206+ {
2207+ alias CommonType = void ;
2208+ }
2209+ else static if (T.length == 1 )
2210+ {
2211+ static if (is (typeof (T[0 ])))
2212+ {
2213+ alias CommonType = typeof (T[0 ]);
2214+ }
2215+ else
2216+ {
2217+ alias CommonType = T[0 ];
2218+ }
2219+ }
2220+ else static if (is (typeof (true ? T[0 ].init : T[1 ].init) U))
2221+ {
2222+ alias CommonType = CommonType! (U, T[2 .. $]);
2223+ }
2224+ else
2225+ alias CommonType = void ;
2226+ }
2227+
2228+ // /
2229+ @safe unittest
2230+ {
2231+ alias X = CommonType! (int , long , short );
2232+ assert (is (X == long ));
2233+ alias Y = CommonType! (int , char [], short );
2234+ assert (is (Y == void ));
2235+ }
2236+
2237+ // /
2238+ @safe unittest
2239+ {
2240+ static assert (is (CommonType! (3 ) == int ));
2241+ static assert (is (CommonType! (double , 4 , float ) == double ));
2242+ static assert (is (CommonType! (string , char []) == const (char )[]));
2243+ static assert (is (CommonType! (3 , 3U ) == uint ));
2244+ static assert (is (CommonType! (double , int ) == double ));
2245+ }
0 commit comments