Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Add std::unique_ptr #2723

Merged
merged 3 commits into from
Dec 31, 2019
Merged
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
3 changes: 3 additions & 0 deletions changelog/std_unique_ptr.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added `core.stdcpp.memory.unique_ptr`

Added `core.stdcpp.memory.unique_ptr`, which corresponds to C++ `std::unique_ptr`.
3 changes: 2 additions & 1 deletion src/core/stdcpp/allocator.d
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ module core.stdcpp.allocator;
import core.stdcpp.new_;
import core.stdcpp.xutility : StdNamespace, __cpp_sized_deallocation, __cpp_aligned_new;

extern(C++, (StdNamespace)):

/**
* Allocators are classes that define memory models to be used by some parts of
* the C++ Standard Library, and most specifically, by STL containers.
*/
extern(C++, class)
extern(C++, (StdNamespace))
struct allocator(T)
{
static assert(!is(T == const), "The C++ Standard forbids containers of const elements because allocator!(const T) is ill-formed.");
Expand Down
163 changes: 163 additions & 0 deletions src/core/stdcpp/memory.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/**
* D binding to C++ <memory>.
*
* Copyright: Copyright (c) 2019 D Language Foundation
* License: Distributed under the
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Manu Evans
* Source: $(DRUNTIMESRC core/stdcpp/memory.d)
*/

module core.stdcpp.memory;

public import core.stdcpp.allocator;

import core.stdcpp.xutility : StdNamespace;

extern(C++, (StdNamespace)):

///
unique_ptr!T make_unique(T, Args...)(auto ref Args args)
{
import core.lifetime : forward;
import core.stdcpp.new_ : cpp_new;

return unique_ptr!T(cpp_new!T(forward!args));
}

///
struct default_delete(T)
{
///
alias pointer = ClassOrPtr!T;

///
void opCall()(pointer ptr) const
{
import core.stdcpp.new_ : cpp_delete;

cpp_delete(ptr);
}
}

///
extern(C++, class)
struct unique_ptr(T, Deleter = default_delete!T)
{
extern(D):
///
this(this) @disable;

///
~this()
{
reset();
}

///
ref unique_ptr opAssign(typeof(null))
{
reset();
return this;
}

///
void reset(pointer p = null)
{
pointer t = __ptr();
__ptr() = p;
if (t)
get_deleter()(t);
}

nothrow pure @safe @nogc:
///
alias pointer = ClassOrPtr!T;
///
alias element_type = T;
///
alias deleter_type = Deleter;

///
this(pointer ptr)
{
__ptr() = ptr;
}

///
inout(pointer) get() inout nothrow
{
return __ptr();
}

///
bool opCast(T : bool)() const nothrow
{
return __ptr() != null;
}

///
pointer release() nothrow
{
pointer t = __ptr();
__ptr() = null;
return t;
}

// void swap(ref unique_ptr u) nothrow
// {
// __ptr_.swap(__u.__ptr_);
// }

version (CppRuntime_Microsoft)
{
///
ref inout(deleter_type) get_deleter() inout nothrow { return _Mypair._Myval1; }

private:
import core.stdcpp.xutility : _Compressed_pair;

ref pointer __ptr() nothrow { return _Mypair._Myval2; }
inout(pointer) __ptr() inout nothrow { return _Mypair._Myval2; }

_Compressed_pair!(Deleter, pointer) _Mypair;
}
else version (CppRuntime_Gcc)
{
///
ref inout(deleter_type) get_deleter() inout nothrow { return _M_t.get!1; }

private:
import core.stdcpp.tuple : tuple, get;

ref pointer __ptr() nothrow { return _M_t.get!0; }
inout(pointer) __ptr() inout nothrow { return _M_t.get!0; }

tuple!(pointer, Deleter) _M_t;
}
else version (CppRuntime_Clang)
{
///
ref inout(deleter_type) get_deleter() inout nothrow { return __ptr_.second; }

private:
import core.stdcpp.xutility : __compressed_pair;

ref pointer __ptr() nothrow { return __ptr_.first; }
inout(pointer) __ptr() inout nothrow { return __ptr_.first; }

__compressed_pair!(pointer, deleter_type) __ptr_;
}
}


private:

template ClassOrPtr(T)
{
static if (is(T == class))
alias ClassOrPtr = T;
else
alias ClassOrPtr = T*;
}
33 changes: 33 additions & 0 deletions src/core/stdcpp/new_.d
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,39 @@ extern (C++, "std")
}


///
T* cpp_new(T, Args...)(auto ref Args args) if (!is(T == class))
{
import core.lifetime : emplace, forward;

T* mem = cast(T*)__cpp_new(T.sizeof);
return mem.emplace(forward!args);
}

///
T cpp_new(T, Args...)(auto ref Args args) if (is(T == class))
{
import core.lifetime : emplace, forward;

T mem = cast(T)__cpp_new(__traits(classInstanceSize, T));
return mem.emplace(forward!args);
}

///
void cpp_delete(T)(T* ptr) if (!is(T == class))
{
destroy!false(*ptr);
__cpp_delete(ptr);
}

///
void cpp_delete(T)(T instance) if (is(T == class))
{
destroy!false(instance);
__cpp_delete(instance);
}


// raw C++ functions
extern(C++):

Expand Down
22 changes: 19 additions & 3 deletions src/core/stdcpp/type_traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,38 @@ module core.stdcpp.type_traits;

extern(C++, "std"):

///
struct integral_constant(T, T Val)
{
///
enum T value = Val;
///
alias value_type = T;
///
alias type = typeof(this);
}

///
alias bool_constant(bool b) = integral_constant!(bool, b);

// Useful for dealing with enable_if constraints.
///
alias true_type = bool_constant!true;
///
alias false_type = bool_constant!false;

///
struct is_empty(T)
{
enum value = T.tupleof.length == 0;
alias value_type = typeof(value);
alias type = integral_constant!(typeof(value), value);
static if (is(T == struct))
private enum __is_empty = T.tupleof.length == 0;
else
private enum __is_empty = false;

///
enum bool value = __is_empty;
///
alias value_type = bool;
///
alias type = integral_constant!(bool, value);
}
3 changes: 2 additions & 1 deletion test/stdcpp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ TESTS17:=string_view
OLDABITESTS:=

ifeq (osx,$(OS))
TESTS+=memory
# TESTS+=string
# TESTS+=vector
endif
Expand All @@ -17,7 +18,7 @@ ifeq (linux,$(OS))
OLDABITESTS+=string
endif
ifeq (freebsd,$(OS))
TESTS+=string
TESTS+=memory string
# TESTS+=vector
endif

Expand Down
12 changes: 12 additions & 0 deletions test/stdcpp/src/memory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <memory>

std::unique_ptr<int> passThrough(std::unique_ptr<int> x)
{
return std::move(x);
}
std::unique_ptr<int> changeIt(std::unique_ptr<int> x)
{
auto p = new int(20); // ensure new pointer is different from released pointer
x.reset();
return std::unique_ptr<int>(p);
}
39 changes: 39 additions & 0 deletions test/stdcpp/src/memory_test.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import core.stdcpp.memory;

unittest
{
import core.lifetime : move;

unique_ptr!int up;
assert(!up);
assert(up.get == null);

auto up2 = make_unique!int(10);
assert(!!up2);
assert(up2.get != null);
assert(*up2.get == 10);

static assert(!__traits(compiles, up = up2));
static assert(!__traits(compiles, unique_ptr!int(up)));

unique_ptr!int x = up2.move;
assert(!!x && !up2);

up = x.move;
assert(!!up && !x);

int* p = up.get;
up = passThrough(up.move);
assert(up.get == p);
up = changeIt(up.move);
assert(up.get != p);
Copy link
Member

Choose a reason for hiding this comment

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

It seems malloc returns the same pointer that was just freed, this the reason the ci fails on osx. mybe check the value instead assert(*up.get == 20);?

Copy link
Member

Choose a reason for hiding this comment

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

Good catch. I've added a commit to ensure the pointers in changeIt are different.

Copy link
Member

Choose a reason for hiding this comment

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

Perfect. It's working now.

assert(*up.get == 20);

up.reset();
assert(!up);
}

extern(C++):

unique_ptr!int passThrough(unique_ptr!int x);
unique_ptr!int changeIt(unique_ptr!int x);
2 changes: 1 addition & 1 deletion test/stdcpp/win64.mak
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ MODEL=64
DRUNTIMELIB=druntime64.lib
CC=cl

TESTS=array allocator new string vector
TESTS=array allocator memory new string vector

_MSC_VER=$(file < ..\..\ver.txt)
ADD_CFLAGS=$(file < ..\..\cflags.txt)
Expand Down