-
-
Notifications
You must be signed in to change notification settings - Fork 423
Added std::string #2310
Added std::string #2310
Changes from 5 commits
9028c31
400827e
38d0ad0
d3642ff
4ac352f
782fdbf
ecadacc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Added `core.stdcpp.string`. | ||
|
||
Added `core.stdcpp.string`, which links against C++ `std::string` | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
@echo off | ||
echo _MSC_VER > ver.c | ||
cl /nologo /EP ver.c > ver.txt | ||
findstr /v /r /c:"^$" "ver.txt" > "ver_trim.txt" | ||
set /P _MSC_VER=< ver_trim.txt | ||
echo set _MSC_VER=%_MSC_VER% | ||
del ver.c ver.txt ver_trim.txt |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -14,11 +14,6 @@ module core.stdcpp.allocator; | |||||
import core.stdcpp.new_; | ||||||
import core.stdcpp.xutility : __cpp_sized_deallocation, __cpp_aligned_new; | ||||||
|
||||||
// some versions of VS require a `* const` pointer mangling hack | ||||||
// we need a way to supply the target VS version to the compile | ||||||
version (CppRuntime_Microsoft) | ||||||
version = NeedsMangleHack; | ||||||
|
||||||
/** | ||||||
* Allocators are classes that define memory models to be used by some parts of | ||||||
* the C++ Standard Library, and most specifically, by STL containers. | ||||||
|
@@ -30,35 +25,114 @@ struct allocator(T) | |||||
static assert(!is(T == const), "The C++ Standard forbids containers of const elements because allocator!(const T) is ill-formed."); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should also check for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. What I really care about though, is working out how to run those tests in this pr to prove it works on all those build machines... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm pretty sure it does not work on POSIX, because template mangling is broken. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to run it on every target, then I'd know that template mangling is broken and fix it... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's right, however the additional check is a small price to pay here. A casual reader might not realize that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are all great ideas, but it's all worthless unless we find a way to test it ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See TurkeyMan#1. I suspect it will conflict with master due to other added tests, though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rainers Thanks! I can't see how the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The amended changes to the makefile now contain the cpp-compilation, but as string.d doesn't compile on anything but win64, the auto-tester stops before it schedules anything to the Windows machines. I'd suggest adding When this works to some extend, adding makefiles for other targets to the test should be straight-forward. |
||||||
static assert(!is(T == immutable), "immutable is not representable in C++"); | ||||||
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."); | ||||||
extern(D): | ||||||
|
||||||
/// | ||||||
this(U)(ref allocator!U) {} | ||||||
|
||||||
/// | ||||||
alias value_type = T; | ||||||
|
||||||
/// | ||||||
alias rebind(U) = allocator!U; | ||||||
|
||||||
version (CppRuntime_Microsoft) | ||||||
{ | ||||||
/// | ||||||
T* allocate(size_t count) @nogc; | ||||||
/// | ||||||
void deallocate(T* ptr, size_t count) @nogc; | ||||||
import core.stdcpp.xutility : _MSC_VER; | ||||||
|
||||||
/// | ||||||
enum size_t max_size = size_t.max / T.sizeof; | ||||||
T* allocate(size_t count) @nogc | ||||||
{ | ||||||
static if (_MSC_VER <= 1800) | ||||||
{ | ||||||
import core.stdcpp.xutility : _Xbad_alloc; | ||||||
if (count == 0) | ||||||
return null; | ||||||
T* mem; | ||||||
if ((size_t.max / T.sizeof < count) || (mem = __cpp_new(count * T.sizeof)) == 0) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can see that ;) ... i just had to wait 2 hours to get the error message! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If you cannot test locally, maybe it would be more productive to setup your own CI on appveyor, you can select an image with VS2013 installed, too (see top of appveyor.xml). You can probably set it up before next iteration here is done... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I pushed before going to work. if it fails again, i'll do that tonight. Look at the auto-tester logs; most machines take 5-10 minutes, except the windows machines which take 30-50 miunutes... |
||||||
_Xbad_alloc(); | ||||||
return mem; | ||||||
} | ||||||
else | ||||||
{ | ||||||
enum _Align = _New_alignof!T; | ||||||
|
||||||
version (NeedsMangleHack) | ||||||
static size_t _Get_size_of_n(T)(const size_t _Count) | ||||||
{ | ||||||
static if (T.sizeof == 1) | ||||||
return _Count; | ||||||
else | ||||||
{ | ||||||
enum size_t _Max_possible = size_t.max / T.sizeof; | ||||||
return _Max_possible < _Count ? size_t.max : _Count * T.sizeof; | ||||||
} | ||||||
} | ||||||
const size_t _Bytes = _Get_size_of_n!T(count); | ||||||
|
||||||
static if (!__cpp_aligned_new || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__) | ||||||
{ | ||||||
version (INTEL_ARCH) | ||||||
{ | ||||||
if (_Bytes >= _Big_allocation_threshold) | ||||||
return cast(T*)_Allocate_manually_vector_aligned(_Bytes); | ||||||
} | ||||||
return _Bytes ? cast(T*)__cpp_new(_Bytes) : null; | ||||||
} | ||||||
else | ||||||
{ | ||||||
if (_Bytes == 0) | ||||||
return null; | ||||||
size_t _Passed_align = _Align; | ||||||
version (INTEL_ARCH) | ||||||
{ | ||||||
if (_Bytes >= _Big_allocation_threshold) | ||||||
_Passed_align = _Align < _Big_allocation_alignment ? _Big_allocation_alignment : _Align; | ||||||
} | ||||||
return cast(T*)__cpp_new_aligned(_Bytes, cast(align_val_t)_Passed_align); | ||||||
} | ||||||
} | ||||||
} | ||||||
/// | ||||||
void deallocate(T* ptr, size_t count) @nogc | ||||||
{ | ||||||
// HACK: workaround to make `deallocate` link as a `T * const` | ||||||
private extern (D) enum string constHack(string name) = (){ | ||||||
version (Win64) | ||||||
enum sub = "AAXPE"; | ||||||
static if (_MSC_VER <= 1800) | ||||||
{ | ||||||
__cpp_delete(ptr); | ||||||
} | ||||||
else | ||||||
{ | ||||||
// this is observed from VS2017 | ||||||
void* _Ptr = ptr; | ||||||
size_t _Bytes = T.sizeof * count; | ||||||
|
||||||
enum _Align = _New_alignof!T; | ||||||
static if (!__cpp_aligned_new || _Align <= __STDCPP_DEFAULT_NEW_ALIGNMENT__) | ||||||
{ | ||||||
version (INTEL_ARCH) | ||||||
{ | ||||||
if (_Bytes >= _Big_allocation_threshold) | ||||||
_Adjust_manually_vector_aligned(_Ptr, _Bytes); | ||||||
} | ||||||
static if (_MSC_VER <= 1900) | ||||||
__cpp_delete(ptr); | ||||||
else | ||||||
__cpp_delete_size(_Ptr, _Bytes); | ||||||
} | ||||||
else | ||||||
enum sub = "AEXPA"; | ||||||
foreach (i; 0 .. name.length - sub.length) | ||||||
if (name[i .. i + sub.length] == sub[]) | ||||||
return name[0 .. i + 3] ~ 'Q' ~ name[i + 4 .. $]; | ||||||
assert(false, "substitution string not found!"); | ||||||
}(); | ||||||
pragma(linkerDirective, "/alternatename:" ~ deallocate.mangleof ~ "=" ~ constHack!(deallocate.mangleof)); | ||||||
{ | ||||||
size_t _Passed_align = _Align; | ||||||
version (INTEL_ARCH) | ||||||
{ | ||||||
if (_Bytes >= _Big_allocation_threshold) | ||||||
_Passed_align = _Align < _Big_allocation_alignment ? _Big_allocation_alignment : _Align; | ||||||
} | ||||||
__cpp_delete_size_aligned(_Ptr, _Bytes, cast(align_val_t)_Passed_align); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
/// | ||||||
enum size_t max_size = size_t.max / T.sizeof; | ||||||
} | ||||||
else version (CppRuntime_Gcc) | ||||||
{ | ||||||
|
@@ -124,3 +198,87 @@ struct allocator(T) | |||||
static assert(false, "C++ runtime not supported"); | ||||||
} | ||||||
} | ||||||
|
||||||
|
||||||
private: | ||||||
|
||||||
// MSVC has some bonus complexity! | ||||||
version (CppRuntime_Microsoft) | ||||||
{ | ||||||
// some versions of VS require a `* const` pointer mangling hack | ||||||
// we need a way to supply the target VS version to the compile | ||||||
version = NeedsMangleHack; | ||||||
|
||||||
version (X86) | ||||||
version = INTEL_ARCH; | ||||||
version (X86_64) | ||||||
version = INTEL_ARCH; | ||||||
|
||||||
// HACK: should we guess _DEBUG for `debug` builds? | ||||||
version (NDEBUG) {} | ||||||
else debug version = _DEBUG; | ||||||
|
||||||
enum _New_alignof(T) = T.alignof > __STDCPP_DEFAULT_NEW_ALIGNMENT__ ? T.alignof : __STDCPP_DEFAULT_NEW_ALIGNMENT__; | ||||||
|
||||||
version (INTEL_ARCH) | ||||||
{ | ||||||
enum size_t _Big_allocation_threshold = 4096; | ||||||
enum size_t _Big_allocation_alignment = 32; | ||||||
|
||||||
static assert(2 * (void*).sizeof <= _Big_allocation_alignment, "Big allocation alignment should at least match vector register alignment"); | ||||||
static assert((v => v != 0 && (v & (v - 1)) == 0)(_Big_allocation_alignment), "Big allocation alignment must be a power of two"); | ||||||
static assert(size_t.sizeof == (void*).sizeof, "uintptr_t is not the same size as size_t"); | ||||||
|
||||||
// NOTE: this must track `_DEBUG` macro used in C++... | ||||||
version (_DEBUG) | ||||||
enum size_t _Non_user_size = 2 * (void*).sizeof + _Big_allocation_alignment - 1; | ||||||
else | ||||||
enum size_t _Non_user_size = (void*).sizeof + _Big_allocation_alignment - 1; | ||||||
|
||||||
version (Win64) | ||||||
enum size_t _Big_allocation_sentinel = 0xFAFAFAFAFAFAFAFA; | ||||||
else | ||||||
enum size_t _Big_allocation_sentinel = 0xFAFAFAFA; | ||||||
|
||||||
void* _Allocate_manually_vector_aligned(const size_t _Bytes) @nogc | ||||||
{ | ||||||
size_t _Block_size = _Non_user_size + _Bytes; | ||||||
if (_Block_size <= _Bytes) | ||||||
_Block_size = size_t.max; | ||||||
|
||||||
const size_t _Ptr_container = cast(size_t)__cpp_new(_Block_size); | ||||||
if (!(_Ptr_container != 0)) | ||||||
assert(false, "invalid argument"); | ||||||
void* _Ptr = cast(void*)((_Ptr_container + _Non_user_size) & ~(_Big_allocation_alignment - 1)); | ||||||
(cast(size_t*)_Ptr)[-1] = _Ptr_container; | ||||||
|
||||||
version (_DEBUG) | ||||||
(cast(size_t*)_Ptr)[-2] = _Big_allocation_sentinel; | ||||||
return (_Ptr); | ||||||
} | ||||||
|
||||||
void _Adjust_manually_vector_aligned(ref void* _Ptr, ref size_t _Bytes) pure nothrow @nogc | ||||||
{ | ||||||
_Bytes += _Non_user_size; | ||||||
|
||||||
const size_t* _Ptr_user = cast(size_t*)_Ptr; | ||||||
const size_t _Ptr_container = _Ptr_user[-1]; | ||||||
|
||||||
// If the following asserts, it likely means that we are performing | ||||||
// an aligned delete on memory coming from an unaligned allocation. | ||||||
assert(_Ptr_user[-2] == _Big_allocation_sentinel, "invalid argument"); | ||||||
|
||||||
// Extra paranoia on aligned allocation/deallocation; ensure _Ptr_container is | ||||||
// in range [_Min_back_shift, _Non_user_size] | ||||||
version (_DEBUG) | ||||||
enum size_t _Min_back_shift = 2 * (void*).sizeof; | ||||||
else | ||||||
enum size_t _Min_back_shift = (void*).sizeof; | ||||||
|
||||||
const size_t _Back_shift = cast(size_t)_Ptr - _Ptr_container; | ||||||
if (!(_Back_shift >= _Min_back_shift && _Back_shift <= _Non_user_size)) | ||||||
assert(false, "invalid argument"); | ||||||
_Ptr = cast(void*)_Ptr_container; | ||||||
} | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should have stated that it's only for Windows :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I'll update that, or I'll just make the other platforms CI work. (Well, Linux still has the interior point issue...)