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

Commit aa2bcf3

Browse files
Merge pull request #2444 from TurkeyMan/cpp-allocator
std::allocator
2 parents 227a925 + 6805600 commit aa2bcf3

File tree

16 files changed

+407
-14
lines changed

16 files changed

+407
-14
lines changed

changelog/cpp_new.dd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Added `core.stdcpp.new_`
2+
3+
Added `core.stdcpp.new_`, which exposes interfaces for C++ global new/delete operators.
4+
This allows D programs to conveniently allocate from the C++ heap, which is useful when sharing memory between languages.

changelog/std_allocator.dd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Added `core.stdcpp.allocator`
2+
3+
Added `core.stdcpp.allocator`, which exposes the C++ `std::allocator<T>` class.
4+
This is a required foundation for any of the allocating STL container types.

mak/COPY

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ COPY=\
5050
$(IMPDIR)\core\stdc\wchar_.d \
5151
$(IMPDIR)\core\stdc\wctype.d \
5252
\
53+
$(IMPDIR)\core\stdcpp\allocator.d \
5354
$(IMPDIR)\core\stdcpp\array.d \
5455
$(IMPDIR)\core\stdcpp\exception.d \
56+
$(IMPDIR)\core\stdcpp\new_.d \
5557
$(IMPDIR)\core\stdcpp\string_view.d \
5658
$(IMPDIR)\core\stdcpp\typeinfo.d \
5759
$(IMPDIR)\core\stdcpp\type_traits.d \

mak/DOCS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ DOCS=\
3939
$(DOCDIR)\core_stdc_wchar_.html \
4040
$(DOCDIR)\core_stdc_wctype.html \
4141
\
42+
$(DOCDIR)\core_stdcpp_allocator.html \
4243
$(DOCDIR)\core_stdcpp_array.html \
43-
$(DOCDIR)\core_stdcpp_string_view.html \
4444
$(DOCDIR)\core_stdcpp_exception.html \
45+
$(DOCDIR)\core_stdcpp_new_.html \
46+
$(DOCDIR)\core_stdcpp_string_view.html \
4547
$(DOCDIR)\core_stdcpp_typeinfo.html \
4648
$(DOCDIR)\core_stdcpp_type_traits.html \
4749
\

mak/SRCS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ SRCS=\
5050
src\core\stdc\wchar_.d \
5151
src\core\stdc\wctype.d \
5252
\
53+
src\core\stdcpp\allocator.d \
5354
src\core\stdcpp\array.d \
55+
src\core\stdcpp\new_.d \
5456
src\core\stdcpp\string_view.d \
5557
src\core\stdcpp\type_traits.d \
5658
src\core\stdcpp\xutility.d \

mak/WINDOWS

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,18 @@ $(IMPDIR)\core\stdc\wchar_.d : src\core\stdc\wchar_.d
189189
$(IMPDIR)\core\stdc\wctype.d : src\core\stdc\wctype.d
190190
copy $** $@
191191

192-
$(IMPDIR)\core\stdcpp\exception.d : src\core\stdcpp\exception.d
192+
$(IMPDIR)\core\stdcpp\allocator.d : src\core\stdcpp\allocator.d
193193
copy $** $@
194194

195195
$(IMPDIR)\core\stdcpp\array.d : src\core\stdcpp\array.d
196196
copy $** $@
197197

198+
$(IMPDIR)\core\stdcpp\exception.d : src\core\stdcpp\exception.d
199+
copy $** $@
200+
201+
$(IMPDIR)\core\stdcpp\new_.d : src\core\stdcpp\new_.d
202+
copy $** $@
203+
198204
$(IMPDIR)\core\stdcpp\string_view.d : src\core\stdcpp\string_view.d
199205
copy $** $@
200206

src/core/stdcpp/allocator.d

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* D binding to C++ std::allocator.
3+
*
4+
* Copyright: Copyright (c) 2019 D Language Foundation
5+
* License: Distributed under the
6+
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7+
* (See accompanying file LICENSE)
8+
* Authors: Manu Evans
9+
* Source: $(DRUNTIMESRC core/stdcpp/allocator.d)
10+
*/
11+
12+
module core.stdcpp.allocator;
13+
14+
import core.stdcpp.new_;
15+
import core.stdcpp.xutility : __cpp_sized_deallocation, __cpp_aligned_new;
16+
17+
// some versions of VS require a `* const` pointer mangling hack
18+
// we need a way to supply the target VS version to the compile
19+
version (CppRuntime_Microsoft)
20+
version = NeedsMangleHack;
21+
22+
/**
23+
* Allocators are classes that define memory models to be used by some parts of
24+
* the C++ Standard Library, and most specifically, by STL containers.
25+
*/
26+
extern(C++, class)
27+
extern(C++, "std")
28+
struct allocator(T)
29+
{
30+
static assert(!is(T == const), "The C++ Standard forbids containers of const elements because allocator!(const T) is ill-formed.");
31+
static assert(!is(T == immutable), "immutable is not representable in C++");
32+
static assert(!is(T == class), "Instantiation with `class` is not supported; D can't mangle the base (non-pointer) type of a class. Use `extern (C++, class) struct T { ... }` instead.");
33+
34+
///
35+
alias value_type = T;
36+
37+
version (CppRuntime_Microsoft)
38+
{
39+
///
40+
T* allocate(size_t count) @nogc;
41+
///
42+
void deallocate(T* ptr, size_t count) @nogc;
43+
44+
///
45+
enum size_t max_size = size_t.max / T.sizeof;
46+
47+
version (NeedsMangleHack)
48+
{
49+
// HACK: workaround to make `deallocate` link as a `T * const`
50+
private extern (D) enum string constHack(string name) = (){
51+
version (Win64)
52+
enum sub = "AAXPE";
53+
else
54+
enum sub = "AEXPA";
55+
foreach (i; 0 .. name.length - sub.length)
56+
if (name[i .. i + sub.length] == sub[])
57+
return name[0 .. i + 3] ~ 'Q' ~ name[i + 4 .. $];
58+
assert(false, "substitution string not found!");
59+
}();
60+
pragma(linkerDirective, "/alternatename:" ~ deallocate.mangleof ~ "=" ~ constHack!(deallocate.mangleof));
61+
}
62+
}
63+
else version (CppRuntime_Gcc)
64+
{
65+
///
66+
T* allocate(size_t count, const(void)* = null) @nogc
67+
{
68+
// if (count > max_size)
69+
// std::__throw_bad_alloc();
70+
71+
static if (__cpp_aligned_new && T.alignof > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
72+
return cast(T*)__cpp_new_aligned(count * T.sizeof, cast(align_val_t)T.alignof);
73+
else
74+
return cast(T*)__cpp_new(count * T.sizeof);
75+
}
76+
///
77+
void deallocate(T* ptr, size_t count) @nogc
78+
{
79+
// NOTE: GCC doesn't seem to use the sized delete when it's available...
80+
81+
static if (__cpp_aligned_new && T.alignof > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
82+
__cpp_delete_aligned(cast(void*)ptr, cast(align_val_t)T.alignof);
83+
else
84+
__cpp_delete(cast(void*)ptr);
85+
}
86+
87+
///
88+
enum size_t max_size = (ptrdiff_t.max < size_t.max ? cast(size_t)ptrdiff_t.max : size_t.max) / T.sizeof;
89+
}
90+
else version (CppRuntime_Clang)
91+
{
92+
///
93+
T* allocate(size_t count, const(void)* = null) @nogc
94+
{
95+
// if (count > max_size)
96+
// __throw_length_error("allocator!T.allocate(size_t n) 'n' exceeds maximum supported size");
97+
98+
static if (__cpp_aligned_new && T.alignof > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
99+
return cast(T*)__cpp_new_aligned(count * T.sizeof, cast(align_val_t)T.alignof);
100+
else
101+
return cast(T*)__cpp_new(count * T.sizeof);
102+
}
103+
///
104+
void deallocate(T* ptr, size_t count) @nogc
105+
{
106+
static if (__cpp_aligned_new && T.alignof > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
107+
{
108+
static if (__cpp_sized_deallocation)
109+
return __cpp_delete_size_aligned(cast(void*)ptr, count * T.sizeof, cast(align_val_t)T.alignof);
110+
else
111+
return __cpp_delete_aligned(cast(void*)ptr, cast(align_val_t)T.alignof);
112+
}
113+
else static if (__cpp_sized_deallocation)
114+
return __cpp_delete_size(cast(void*)ptr, count * T.sizeof);
115+
else
116+
return __cpp_delete(cast(void*)ptr);
117+
}
118+
119+
///
120+
enum size_t max_size = size_t.max / T.sizeof;
121+
}
122+
else
123+
{
124+
static assert(false, "C++ runtime not supported");
125+
}
126+
}

src/core/stdcpp/new_.d

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* D binding to C++ <new>
3+
*
4+
* Copyright: Copyright (c) 2019 D Language Foundation
5+
* License: Distributed under the
6+
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7+
* (See accompanying file LICENSE)
8+
* Authors: Manu Evans
9+
* Source: $(DRUNTIMESRC core/stdcpp/new_.d)
10+
*/
11+
12+
module core.stdcpp.new_;
13+
14+
import core.stdcpp.xutility : __cpp_sized_deallocation, __cpp_aligned_new;
15+
16+
// TODO: this really should come from __traits(getTargetInfo, "defaultNewAlignment")
17+
enum size_t __STDCPP_DEFAULT_NEW_ALIGNMENT__ = 16;
18+
19+
20+
extern (C++):
21+
22+
///
23+
extern (C++, "std") enum align_val_t : size_t { defaultAlignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__ };
24+
25+
/// Binding for ::operator new(std::size_t count)
26+
pragma(mangle, __new_mangle)
27+
void* __cpp_new(size_t count) @nogc;
28+
29+
/// Binding for ::operator delete(void* ptr)
30+
pragma(mangle, __delete_mangle)
31+
void __cpp_delete(void* ptr) @nogc;
32+
33+
static if (__cpp_sized_deallocation)
34+
{
35+
/// Binding for ::operator delete(void* ptr, size_t size)
36+
pragma(mangle, __delete_size_mangle)
37+
void __cpp_delete_size(void* ptr, size_t size) @nogc;
38+
}
39+
static if (__cpp_aligned_new)
40+
{
41+
/// Binding for ::operator new(std::size_t count, std::align_val_t al)
42+
pragma(mangle, __new_align_mangle)
43+
void* __cpp_new_aligned(size_t count, align_val_t alignment) @nogc;
44+
45+
/// Binding for ::operator delete(void* ptr, std::align_val_t al)
46+
pragma(mangle, __delete_align_mangle)
47+
void __cpp_delete_aligned(void* ptr, align_val_t alignment) @nogc;
48+
49+
/// Binding for ::operator delete(void* ptr, size_t size, std::align_val_t al)
50+
pragma(mangle, __delete_size_align_mangle)
51+
void __cpp_delete_size_aligned(void* ptr, size_t size, align_val_t alignment) @nogc;
52+
}
53+
54+
private:
55+
56+
// we have to hard-code the mangling for the global new/delete operators
57+
version (CppRuntime_Microsoft)
58+
{
59+
version (D_LP64)
60+
{
61+
enum __new_mangle = "??2@YAPEAX_K@Z";
62+
enum __delete_mangle = "??3@YAXPEAX@Z";
63+
enum __delete_size_mangle = "??3@YAXPEAX_K@Z";
64+
enum __new_align_mangle = "??2@YAPEAX_KW4align_val_t@std@@@Z";
65+
enum __delete_align_mangle = "??3@YAXPEAXW4align_val_t@std@@@Z";
66+
enum __delete_size_align_mangle = "??3@YAXPEAX_KW4align_val_t@std@@@Z";
67+
}
68+
else
69+
{
70+
enum __new_mangle = "??2@YAPAXI@Z";
71+
enum __delete_mangle = "??3@YAXPAX@Z";
72+
enum __delete_size_mangle = "??3@YAXPAXI@Z";
73+
enum __new_align_mangle = "??2@YAPAXIW4align_val_t@std@@@Z";
74+
enum __delete_align_mangle = "??3@YAXPAXW4align_val_t@std@@@Z";
75+
enum __delete_size_align_mangle = "??3@YAXPAXIW4align_val_t@std@@@Z";
76+
}
77+
}
78+
else
79+
{
80+
version (D_LP64)
81+
{
82+
enum __new_mangle = "_Znwm";
83+
enum __delete_mangle = "_ZdlPv";
84+
enum __delete_size_mangle = "_ZdlPvm";
85+
enum __new_align_mangle = "_ZnwmSt11align_val_t";
86+
enum __delete_align_mangle = "_ZdlPvSt11align_val_t";
87+
enum __delete_size_align_mangle = "_ZdlPvmSt11align_val_t";
88+
}
89+
else
90+
{
91+
enum __new_mangle = "_Znwj";
92+
enum __delete_mangle = "_ZdlPv";
93+
enum __delete_size_mangle = "_ZdlPvj";
94+
enum __new_align_mangle = "_ZnwjSt11align_val_t";
95+
enum __delete_align_mangle = "_ZdlPvSt11align_val_t";
96+
enum __delete_size_align_mangle = "_ZdlPvjSt11align_val_t";
97+
}
98+
}

src/core/stdcpp/xutility.d

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,22 @@
1111

1212
module core.stdcpp.xutility;
1313

14+
15+
enum CppStdRevision : uint
16+
{
17+
cpp98 = 199711,
18+
cpp11 = 201103,
19+
cpp14 = 201402,
20+
cpp17 = 201703
21+
}
22+
23+
enum __cplusplus = __traits(getTargetInfo, "cppStd");
24+
25+
// wrangle C++ features
26+
enum __cpp_sized_deallocation = __cplusplus >= CppStdRevision.cpp14 ? 201309 : 0;
27+
enum __cpp_aligned_new = __cplusplus >= CppStdRevision.cpp17 ? 201606 : 0;
28+
29+
1430
extern(C++, "std"):
1531

1632
version (CppRuntime_Microsoft)

test/common.mak

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,20 @@ ROOT:=$(GENERATED)/$(OS)/$(BUILD)/$(MODEL)
1717
ifneq (default,$(MODEL))
1818
MODEL_FLAG:=-m$(MODEL)
1919
endif
20-
CFLAGS:=$(MODEL_FLAG) $(PIC) -Wall
20+
CFLAGS_BASE:= $(MODEL_FLAG) $(PIC) -Wall
2121
DFLAGS:=$(MODEL_FLAG) $(PIC) -w -I../../src -I../../import -I$(SRC) -defaultlib= -debuglib= -dip1000
2222
# LINK_SHARED may be set by importing makefile
2323
DFLAGS+=$(if $(LINK_SHARED),-L$(DRUNTIMESO),-L$(DRUNTIME))
2424
ifeq ($(BUILD),debug)
2525
DFLAGS += -g -debug
26-
CFLAGS += -g
26+
CFLAGS := $(CFLAGS_BASE) -g
2727
else
2828
DFLAGS += -O -release
29-
CFLAGS += -O3
29+
CFLAGS := $(CFLAGS_BASE) -O3
3030
endif
31+
CXXFLAGS_BASE := $(CFLAGS_BASE) -std=c++11
3132
CXXFLAGS:=$(CFLAGS) -std=c++11
3233
ifeq (osx,$(OS))
3334
CXXFLAGS+=-stdlib=libc++
35+
CXXFLAGS_BASE+=-stdlib=libc++
3436
endif

0 commit comments

Comments
 (0)