Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive

Commit 6a9dc60

Browse files
committed
Move std.exception.doesPointTo to druntime
1 parent 27b41a0 commit 6a9dc60

File tree

1 file changed

+294
-6
lines changed

1 file changed

+294
-6
lines changed

src/core/lifetime.d

Lines changed: 294 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)