The OpenD Programming Language

mayPointTo

Checks whether a given source object contains pointers or references to a given target object.

  1. bool mayPointTo(S source, T target)
    @trusted pure nothrow
    bool
    mayPointTo
    (
    S
    T
    Tdummy = void
    )
    (
    auto ref const S source
    ,
    ref const T target
    )
    if (
    __traits(isRef, source) ||
    ||
    is(S == U*,
    U
    )
    ||
    is(S == class)
    )
  2. bool mayPointTo(S source, T target)

Parameters

source S

The source object

target T

The target object

Return Value

Type: bool

true if source's representation embeds a pointer that points to target's representation or somewhere inside it.

If source is or contains a dynamic array, then, then these functions will check if there is overlap between the dynamic array and target's representation.

If source is a class, then it will be handled as a pointer.

If target is a pointer, a dynamic array or a class, then these functions will only check if source points to target, not what target references.

If source is or contains a union or void[n], then there may be either false positives or false negatives:

doesPointTo will return true if it is absolutely certain source points to target. It may produce false negatives, but never false positives. This function should be prefered when trying to validate input data.

mayPointTo will return false if it is absolutely certain source does not point to target. It may produce false positives, but never false negatives. This function should be prefered for defensively choosing a code path.

Note: Evaluating doesPointTo(x, x) checks whether x has internal pointers. This should only be done as an assertive test, as the language is free to assume objects don't have internal pointers (TDPL 7.1.3.5).

Bugs

The function is explicitly annotated @nogc because inference could fail, see Bugzilla issue 17084.

Examples

Pointers

int  i = 0;
int* p = null;
assert(!p.doesPointTo(i));
p = &i;
assert( p.doesPointTo(i));

Structs and Unions

struct S
{
    int v;
    int* p;
}
int i;
auto s = S(0, &i);

// structs and unions "own" their members
// pointsTo will answer true if one of the members pointsTo.
assert(!s.doesPointTo(s.v)); //s.v is just v member of s, so not pointed.
assert( s.p.doesPointTo(i)); //i is pointed by s.p.
assert( s  .doesPointTo(i)); //which means i is pointed by s itself.

// Unions will behave exactly the same. Points to will check each "member"
// individually, even if they share the same memory

Arrays (dynamic and static)

int i;
 // trick the compiler when initializing slice
 // https://issues.dlang.org/show_bug.cgi?id=18637
int* p = &i;
int[]  slice = [0, 1, 2, 3, 4];
int[5] arr   = [0, 1, 2, 3, 4];
int*[]  slicep = [p];
int*[1] arrp   = [&i];

// A slice points to all of its members:
assert( slice.doesPointTo(slice[3]));
assert(!slice[0 .. 2].doesPointTo(slice[3])); // Object 3 is outside of the
                                              // slice [0 .. 2]

// Note that a slice will not take into account what its members point to.
assert( slicep[0].doesPointTo(i));
assert(!slicep   .doesPointTo(i));

// static arrays are objects that own their members, just like structs:
assert(!arr.doesPointTo(arr[0])); // arr[0] is just a member of arr, so not
                                  // pointed.
assert( arrp[0].doesPointTo(i));  // i is pointed by arrp[0].
assert( arrp   .doesPointTo(i));  // which means i is pointed by arrp
                                  // itself.

// Notice the difference between static and dynamic arrays:
assert(!arr  .doesPointTo(arr[0]));
assert( arr[].doesPointTo(arr[0]));
assert( arrp  .doesPointTo(i));
assert(!arrp[].doesPointTo(i));

Classes

class C
{
    this(int* p){this.p = p;}
    int* p;
}
int i;
C a = new C(&i);
C b = a;

// Classes are a bit particular, as they are treated like simple pointers
// to a class payload.
assert( a.p.doesPointTo(i)); // a.p points to i.
assert(!a  .doesPointTo(i)); // Yet a itself does not point i.

//To check the class payload itself, iterate on its members:
()
{
    import std.traits : Fields;

    foreach (index, _; Fields!C)
        if (doesPointTo(a.tupleof[index], i))
            return;
    assert(0);
}();

// To check if a class points a specific payload, a direct memmory check
// can be done:
auto aLoc = cast(ubyte[__traits(classInstanceSize, C)]*) a;
assert(b.doesPointTo(*aLoc)); // b points to where a is pointing

Meta