Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mak/COPY
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ COPY=\
$(IMPDIR)\core\vararg.d \
\
$(IMPDIR)\core\internal\abort.d \
$(IMPDIR)\core\internal\array.d \
$(IMPDIR)\core\internal\convert.d \
$(IMPDIR)\core\internal\hash.d \
$(IMPDIR)\core\internal\spinlock.d \
Expand Down
1 change: 1 addition & 0 deletions mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ SRCS=\
src\core\vararg.d \
\
src\core\internal\abort.d \
src\core\internal\array.d \
src\core\internal\convert.d \
src\core\internal\hash.d \
src\core\internal\spinlock.d \
Expand Down
149 changes: 149 additions & 0 deletions src/core/internal/array.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
module core.internal.array;
import core.stdc.stdint : uintptr_t;

/*
* This allows safe use of a pointer without dereferencing. Useful when you
* want to declare that all you care about is the pointer value itself. Keeps
* the pointer as a pointer to allow GC to properly track things.
*
* Note that PtrVal has all the same characteristics of a normal pointer,
* except it doesn't allow dereferencing, and doesn't allow pointer math
* without jumping into simple integer types.
*/
struct PtrVal(T)
{
private T *_ptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not

struct PtrVal(T)
    if (is(T : U*, U))
{
    private T _ptr;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why that? I find it less straightforward.


/*
* Get the pointer as a non-dereferencable unsigned integer.
*/
uintptr_t value() const @trusted
{
return cast(uintptr_t)_ptr;
}

/*
* Keep the mechanism that returns a signed pointer difference between pointers.
*/
ptrdiff_t opBinary(string op : "-")(const(PtrVal) other) const @trusted
{
return _ptr - other._ptr;
}

// ditto
ptrdiff_t opBinary(string op : "-")(const(T*) other) const @trusted
{
return _ptr - other;
}

// ditto
ptrdiff_t opBinaryRight(string op : "-")(const(T*) other) const @trusted
{
return other - _ptr;
}

// disable subtraction between undefined types -- we don't want to
// accidentally subtract between the value() and some unknown type.
ptrdiff_t opBinary(string op : "-", X)(X) const @safe
{
static assert(0, "Cannot subtract between " ~ typeof(this).stringof ~ " and " ~ X.stringof);
}

/*
* Use this if you are in system code and wish to get back to unsafe
* pointer-land.
*/
inout(T) *ptr() inout @system
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this shouldn't be inout since your returning a copy of the pointer and if the user wants a const pointer, then PtrVal!(const T*) should be used.

Copy link
Member Author

@schveiguy schveiguy Jun 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You misunderstand why this is inout. If you have a const(PtrVal!(...)), then you can't call ptr on it unless the function is marked const or inout. I'd need several copies of the same function. This is the whole point of inout.

{
return _ptr;
}

/*
* Devolves to simple unsigned integer if any other operations are used
*/
alias value this;


/*
* Cast to void pointer type. TODO: see if there is a way to make this
* implicit.
*
* Templated to avoid extra imports if not used.
*/
auto toVoid()() inout @trusted
{
static if(is(const(T)* == const(void)*))
{
// already a void pointer
return this;
}
else
{
// need to transfer mutability modifier of _ptr
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice touch :)

import core.internal.traits: ModifyTypePreservingTQ;
alias voidify(M) = void;
alias VType = ModifyTypePreservingTQ!(voidify, T);
return inout(.PtrVal!(VType))(_ptr);
}
}
}

/*
* Factory method
*/
inout(PtrVal!T) ptrval(T)(inout(T)* ptr) @safe
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not simply:

PtrVal!(T*) ptrval(T)(T* ptr)

?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cuts down on template bloat, and code complexity.

{
return inout(PtrVal!T)(ptr);
}

/*
* Allow safe access to array.ptr as a PtrVal.
*/
inout(PtrVal!T) ptrval(T)(inout(T)[] arr) @trusted
{
return arr.ptr.ptrval;
}

pure nothrow unittest
{
import core.internal.traits: TypeTuple;
void testItSafe(T)(T[] t1, T[] t2) @safe
{
auto p1 = t1.ptrval;
auto p2 = t2.ptrval;

assert(p2 - p1 == 5, T.stringof);
assert(p1 - p2 == -5, T.stringof);
assert(p2.toVoid - p1.toVoid == 5 * T.sizeof, T.stringof);
assert(p1.toVoid - p2.toVoid == -5 * T.sizeof, T.stringof);

auto p3 = &t1[0];
auto p4 = &t2[0];

assert(p1 - p3 == 0, T.stringof);
assert(p4 - p2 == 0, T.stringof);
}

void testIt(T)(inout int = 0)
{
T[] arr = new T[10];
testItSafe(arr[0 .. 5], arr[5 .. $]);

// test getting pointer back from PtrVal.
auto p1 = arr.ptrval;
auto p2 = arr[5 .. $].ptrval;

assert(p1.ptr + 5 == p2.ptr, T.stringof);
assert(p1.ptr == arr.ptr, T.stringof);
}

class C {}
struct S {ubyte x;}
foreach(T; TypeTuple!(ubyte, byte, ushort, short, uint, int, ulong, long, float, double, real, C, S))
{
testIt!(T)();
testIt!(const(T))();
testIt!(immutable(T))();
testIt!(inout(T))();
}
}
15 changes: 15 additions & 0 deletions src/core/internal/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,18 @@ template hasElaborateCopyConstructor(T...)
else
enum bool hasElaborateCopyConstructor = false;
}

// (from phobos)
package template ModifyTypePreservingTQ(alias Modifier, T)
{
static if (is(T U == immutable U)) alias ModifyTypePreservingTQ = immutable Modifier!U;
else static if (is(T U == shared inout const U)) alias ModifyTypePreservingTQ = shared inout const Modifier!U;
else static if (is(T U == shared inout U)) alias ModifyTypePreservingTQ = shared inout Modifier!U;
else static if (is(T U == shared const U)) alias ModifyTypePreservingTQ = shared const Modifier!U;
else static if (is(T U == shared U)) alias ModifyTypePreservingTQ = shared Modifier!U;
else static if (is(T U == inout const U)) alias ModifyTypePreservingTQ = inout const Modifier!U;
else static if (is(T U == inout U)) alias ModifyTypePreservingTQ = inout Modifier!U;
else static if (is(T U == const U)) alias ModifyTypePreservingTQ = const Modifier!U;
else alias ModifyTypePreservingTQ = Modifier!T;
}

17 changes: 6 additions & 11 deletions src/rt/util/array.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module rt.util.array;


import core.internal.string;
import core.internal.array;
import core.stdc.stdint;


Expand All @@ -20,15 +21,15 @@ void enforceTypedArraysConformable(T)(const char[] action,
{
_enforceSameLength(action, a1.length, a2.length);
if(!allowOverlap)
_enforceNoOverlap(action, arrayToPtr(a1), arrayToPtr(a2), T.sizeof * a1.length);
_enforceNoOverlap(action, a1.ptrval, a2.ptrval, T.sizeof * a1.length);
}

void enforceRawArraysConformable(const char[] action, in size_t elementSize,
const void[] a1, const void[] a2, in bool allowOverlap = false)
{
_enforceSameLength(action, a1.length, a2.length);
if(!allowOverlap)
_enforceNoOverlap(action, arrayToPtr(a1), arrayToPtr(a2), elementSize * a1.length);
_enforceNoOverlap(action, a1.ptrval, a2.ptrval, elementSize * a1.length);
}

private void _enforceSameLength(const char[] action,
Expand All @@ -47,10 +48,10 @@ private void _enforceSameLength(const char[] action,
throw new Error(msg);
}

private void _enforceNoOverlap(const char[] action,
uintptr_t ptr1, uintptr_t ptr2, in size_t bytes)
private void _enforceNoOverlap(T)(const char[] action,
const PtrVal!(T) ptr1, const PtrVal!(T) ptr2, in size_t bytes)
{
const d = ptr1 > ptr2 ? ptr1 - ptr2 : ptr2 - ptr1;
const d = ptr1 > ptr2 ? ptr1.toVoid - ptr2.toVoid : ptr2.toVoid - ptr1.toVoid;
if(d >= bytes)
return;
const overlappedBytes = bytes - d;
Expand All @@ -64,9 +65,3 @@ private void _enforceNoOverlap(const char[] action,
msg ~= bytes.unsignedToTempString(tmpBuff, 10);
throw new Error(msg);
}

private uintptr_t arrayToPtr(const void[] array) @trusted
{
// Ok because the user will never dereference the pointer
return cast(uintptr_t)array.ptr;
}
3 changes: 3 additions & 0 deletions win32.mak
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ $(IMPDIR)\core\vararg.d : src\core\vararg.d
$(IMPDIR)\core\internal\abort.d : src\core\internal\abort.d
copy $** $@

$(IMPDIR)\core\internal\array.d : src\core\internal\array.d
copy $** $@

$(IMPDIR)\core\internal\convert.d : src\core\internal\convert.d
copy $** $@

Expand Down
3 changes: 3 additions & 0 deletions win64.mak
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ $(IMPDIR)\core\vararg.d : src\core\vararg.d
$(IMPDIR)\core\internal\abort.d : src\core\internal\abort.d
copy $** $@

$(IMPDIR)\core\internal\array.d : src\core\internal\array.d
copy $** $@

$(IMPDIR)\core\internal\convert.d : src\core\internal\convert.d
copy $** $@

Expand Down